वेब पेज को आसानी से पीडीएफ में कैसे बदला जा सकता है?


यह मेरे लिए बहुत अप्रत्याशित था कि जावा हब में पीडीएफ दस्तावेजों के साथ काम करने के बारे में व्यावहारिक रूप से कोई जानकारी नहीं है, इसलिए, व्यक्तिगत अनुभव से, मैं एक सर्वलेट के उदाहरण से दिखाना चाहता हूं कि किसी भी वेब पेज को पीडीएफ दस्तावेज़ में बदलना कितना आसान है।

प्रस्तावना:
हम एक सरल सर्वलेट लिखेंगे जो HTTP प्रोटोकॉल का उपयोग करके संकेतित वेब पेज को ले जाएगा और इसके आधार पर एक पूर्ण पीडीएफ दस्तावेज़ उत्पन्न करेगा।

प्रयुक्त पुस्तकालय:

मावेन कॉन्फ़िगरेशन के लिए लाइब्रेरी विवरण (pom.xml)
<dependency> <groupId>org.xhtmlrenderer</groupId> <artifactId>flying-saucer-pdf</artifactId> <version>9.0.4</version> </dependency> <dependency> <groupId>net.sourceforge.htmlcleaner</groupId> <artifactId>htmlcleaner</artifactId> <version>2.6.1</version> </dependency> 


पृष्ठ का गठन:
सबसे महत्वपूर्ण बिंदुओं में से एक पृष्ठ का गठन है। तथ्य यह है कि यह पृष्ठ से ही है, सीएसएस के माध्यम से, कि भविष्य के पीडीएफ दस्तावेज़ के पैरामीटर सेट हैं।

लेआउट पर विचार करें:
page.jsp
 <%@ page import="java.util.Date" %> <%@ page import="java.text.SimpleDateFormat" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%! private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); %> <html> <head> <title></title> <style> @font-face { font-family: "HabraFont"; src: url(http://localhost:8080/resources/fonts/tahoma.ttf); -fs-pdf-font-embed: embed; -fs-pdf-font-encoding: Identity-H; } @page { margin: 0px; padding: 0px; size: A4 portrait; } @media print { .new_page { page-break-after: always; } } body { background-image: url(http://localhost:8080/resources/images/background.png); } body *{ padding: 0; margin: 0; } * { font-family: HabraFont; } #block { width: 90%; margin: auto; background-color: white; border: dashed #dbdbdb 1px; } #logo { margin-top: 5px; width: 100%; text-align: center; border-bottom: dashed #dbdbdb 1px; } #content { padding-left: 10px; } </style> </head> <body> <div id="block"> <div id="logo"><img src="http://localhost:8080/resources/images/habra-logo.png"></div> <div id="content"> , !  : <%=sdf.format(new Date())%> <div class="new_page"> </div>  ! </div> </div> </body> </html> 


यहां मैं कुछ बिंदुओं पर ध्यान देना चाहता हूं। शुरुआत के लिए, सबसे महत्वपूर्ण बात: सभी रास्ते निरपेक्ष होने चाहिए ! चित्र, शैली, फ़ॉन्ट पते, आदि, हर चीज़ पर निरपेक्ष पथ लिखे जाने चाहिए। अब चलो CSS नियमों (जो @ प्रतीक से शुरू होता है) के माध्यम से चलते हैं।
@ फ़ॉन्ट-फेस एक नियम है जो हमारे पीडीएफ जनरेटर को बताता है कि कौन सा फ़ॉन्ट प्राप्त करना है और यह कहां से आता है। समस्या यह है कि पीडीएफ दस्तावेज़ उत्पन्न करने वाले पुस्तकालय में साइरिलिक शामिल फ़ॉन्ट नहीं होते हैं। इसीलिए यह आवश्यक है कि आपके पेज में उपयोग होने वाले सभी फोंट का निर्धारण किया जाए, भले ही वे मानक फोंट हों: एरियल, वर्दाना, ताहोमा, आदि, अन्यथा आप अपने दस्तावेज़ में सिरिलिक वर्णमाला नहीं देखने का जोखिम उठाते हैं।
"-Fs-pdf-font-embed: एम्बेड:" जैसी संपत्तियों पर ध्यान दें और "-fs-pdf-font-एन्कोडिंग: आइडेंटिटी-एच;", ये गुण आवश्यक हैं, बस उन्हें जोड़ना याद रखें।
@ पृष्ठ एक नियम है जो पीडीएफ दस्तावेज़ और उसके आकार के लिए पैडिंग सेट करता है। यहां मैं यह नोट करना चाहूंगा कि यदि आप A3 पृष्ठ का आकार निर्दिष्ट करते हैं (और जैसा कि अभ्यास से पता चलता है, यह अक्सर आवश्यक होता है, क्योंकि पृष्ठ चौड़ाई में दस्तावेज़ में फिट नहीं होता है), इसका मतलब यह नहीं है कि उपयोगकर्ता को दस्तावेज़ प्रिंट करने की आवश्यकता होगी (यदि वांछित है) A3 प्रारूप में, बल्कि, सभी सामग्री आनुपातिक रूप से कम हो जाएगी / वांछित (आमतौर पर A4) तक बढ़ेगी। यानी आकार की संपत्ति के मूल्य के बारे में उलझन में रहें , लेकिन ध्यान रखें कि यह आपके लिए एक महत्वपूर्ण भूमिका निभा सकता है।
@ मीडिया - एक नियम जो आपको एक निश्चित प्रकार के डिवाइस के लिए सीएसएस कक्षाएं बनाने की अनुमति देता है, हमारे मामले में यह "प्रिंट" है। इस नियम के अंदर, हमने एक क्लास बनाया, जिसके बाद हमारा पीडीएफ डॉक्यूमेंट जनरेटर एक नया पेज बनाएगा।

सर्वलेट:
अब हम एक सर्वलेट लिखते हैं जो हमें उत्पन्न पीडीएफ दस्तावेज़ लौटाएगा:
PdfServlet.java
 package ru.habrahabr.web_to_pdf.servlets; import org.htmlcleaner.CleanerProperties; import org.htmlcleaner.HtmlCleaner; import org.htmlcleaner.PrettyXmlSerializer; import org.htmlcleaner.TagNode; import org.xhtmlrenderer.pdf.ITextRenderer; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; /** * Date: 31.03.2014 * Time: 9:33 * * @author Ruslan Molchanov (ruslanys@gmail.com) */ public class PdfServlet extends HttpServlet { private static final String PAGE_TO_PARSE = "http://localhost:8080/page.jsp"; private static final String CHARSET = "UTF-8"; @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try { resp.setContentType("application/pdf"); byte[] pdfDoc = performPdfDocument(PAGE_TO_PARSE); resp.setContentLength(pdfDoc.length); resp.getOutputStream().write(pdfDoc); } catch (Exception ex) { resp.setContentType("text/html"); PrintWriter out = resp.getWriter(); out.write("<strong>Something wrong</strong><br /><br />"); ex.printStackTrace(out); ex.printStackTrace(); } } /** * ,  PDF . * @param path    * @return PDF  * @throws Exception */ private byte[] performPdfDocument(String path) throws Exception { //  HTML   String html = getHtml(path); // ,      HTML  ByteArrayOutputStream out = new ByteArrayOutputStream(); //  HTML  /*    ,        */ HtmlCleaner cleaner = new HtmlCleaner(); CleanerProperties props = cleaner.getProperties(); props.setCharset(CHARSET); TagNode node = cleaner.clean(html); new PrettyXmlSerializer(props).writeToStream(node, out); //  PDF   HTML  ITextRenderer renderer = new ITextRenderer(); renderer.setDocumentFromString(new String(out.toByteArray(), CHARSET)); renderer.layout(); /* ,       PDF , ,   *     ,    PDF , *    ,     */ ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); renderer.createPDF(outputStream); //   renderer.finishPDF(); out.flush(); out.close(); byte[] result = outputStream.toByteArray(); outputStream.close(); return result; } private String getHtml(String path) throws IOException { URLConnection urlConnection = new URL(path).openConnection(); ((HttpURLConnection) urlConnection).setInstanceFollowRedirects(true); HttpURLConnection.setFollowRedirects(true); boolean redirect = false; // normally, 3xx is redirect int status = ((HttpURLConnection) urlConnection).getResponseCode(); if (HttpURLConnection.HTTP_OK != status && (HttpURLConnection.HTTP_MOVED_TEMP == status || HttpURLConnection.HTTP_MOVED_PERM == status || HttpURLConnection.HTTP_SEE_OTHER == status)) { redirect = true; } if (redirect) { // get redirect url from "location" header field String newUrl = urlConnection.getHeaderField("Location"); // open the new connnection again urlConnection = new URL(newUrl).openConnection(); } urlConnection.setConnectTimeout(30000); urlConnection.setReadTimeout(30000); BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), CHARSET)); StringBuilder sb = new StringBuilder(); String line; while (null != (line = in.readLine())) { sb.append(line).append("\n"); } return sb.toString().trim(); } @Override public String getServletInfo() { return "The servlet that generate and returns pdf file"; } } 


वैसे, इन उद्देश्यों के लिए एक सर्वलेट लिखना आवश्यक नहीं है, आप इस सर्वलेट के तर्क को एक कंसोल एप्लिकेशन पर भी स्थानांतरित कर सकते हैं जो पीडीएफ दस्तावेजों को फाइलों में बचाएगा। जैसा कि आपने देखा होगा, सर्वलेट में आपको कॉन्फ़िगर, परिवर्तन, पूरक आदि की आवश्यकता नहीं है। (ठीक है, पृष्ठ के पथ के अपवाद के साथ और, संभवतः, एन्कोडिंग), क्रमशः, एक पीडीएफ दस्तावेज़ तैयार करने पर सभी काम बहुत सरल हैं और विशेष रूप से दृश्य में होते हैं।

अंत में, आपको कुछ इस तरह के पीडीएफ दस्तावेज़ मिलना चाहिए: github.com/ruslanys/example-web-to-pdf/blob/master/web-to-pdf-example.pdf
मैंने अपने दस्तावेज़ को जानकारी के साथ पूरक किया (हैबर के मुख्य पृष्ठ को पार्स किया) और मुझे निम्नलिखित दस्तावेज़ मिला: github.com/ruslanys/sample-html-to-pdf/blob/master/web-to-pdf-habra.pdf

सूत्रों का लिंक: github.com/ruslanys/sample-html-to-pdf

PS सिद्धांत रूप में, इस उदाहरण के आधार पर, आप एक पूरी सेवा लिख ​​सकते हैं जो किसी भी पृष्ठ पते पर एक पीडीएफ दस्तावेज़ बनाएगा। केवल एक चीज की आवश्यकता है जो पृष्ठ के HTML कोड को हमारे नियमों के अनुसार लाए, अर्थात्। सबसे पहले, सभी रिश्तेदार पथों को निरपेक्ष लोगों के लिए फिर से लिखना आवश्यक होगा (क्योंकि यह करना मुश्किल नहीं है), और कुछ तर्क के अनुसार, दस्तावेज़ आकार निर्धारित करें।

Source: https://habr.com/ru/post/In217561/


All Articles