1. The background

At present, a small program is under way. The customer has put forward the requirement to generate a PDF of some data for download and sharing. Because it is a small program project, the GENERATION of PDF can only be carried out through the back end, so the conventional ITEXT scheme is adopted. Generated is the kind of more partial text type of PDF. The generated PDF screenshot is shown below

Although report insertion can also be achieved by some means, after using it for a period of time, the customer put forward requirements on the aesthetics of PDF and presented the design draft, as shown in the figure below

At this point itext can’t solve this problem because a lot of the content needs to be customized and a lot of images and Echarts diagrams are inserted. Therefore, other solutions need to be sought.

2. Solutions

The core idea is to generate the page you want to achieve through H5, intercept the page, the back end by cutting the picture by IText paste into the PDF, and finally generate the deserved PDF.

1. H5 page is embedded in the small program, and pictures are generated through canvas drawing and transferred to the background, and PDF is generated.

Small program embedded H5 page through web-view, through access to the deserved page drawing pictures, and upload to the background to generate PDF, the process is not smooth, because android and ios browser kernel is different, resulting in the drawn page offset and partial details loss and other problems, finally generated PDF has a high probability of unusable. There are also some successful generation, so this scheme is abandoned.

2. Pure JAVA generation.

Access web pages and take screenshots on the server via ChormeHeadless + Selenium.

  • The Java side needs to introduce a few JARS
<! Guava </groupId> <artifactId>guava</artifactId> <version>30.1.1-jre</version> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> < version > 4.0.0 - alpha - 6 < / version > < / dependency >Copy the code
  • Server or local installation of Chrome and the due driver

Chrome download address driver download address PS: note the corresponding version

  • Java implementation
Public WebDriver getDriver(String argument) {public WebDriver getDriver(String argument) { System.setProperty("webdriver.chrome.driver", "/xxx/chromedriver"); ChromeOptions chromeOptions = new ChromeOptions(); SetBinary ("/usr/bin/google-chrome"); chromeOptions.addArguments("--no-sandbox"); chromeOptions.addArguments("start-maximized"); chromeOptions.addArguments("disable-infobars"); chromeOptions.addArguments("--disable-dev-shm-usage"); chromeOptions.addArguments("--test-type"); chromeOptions.addArguments("--disable-extensions"); chromeOptions.addArguments("--headless"); chromeOptions.setExperimentalOption("useAutomationExtension", false); chromeOptions.addArguments("--disable-dev-shm-usage"); if(! argument.equals("")) chromeOptions.addArguments(argument); WebDriver webDriver = new ChromeDriver(chromeOptions); return webDriver; } /** * public static pdfImgGenerate(String imgName, String type, String resultId) { String url = MdisConfig.getPdfUrl() + "? id=" + resultId + "&type=" + type; WebDriver driver = new PdfUtils().getDriver(""); driver.get(url); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); JavascriptExecutor driver_js = ((JavascriptExecutor) driver); Long height = (Long) driver_js.executeScript("return document.body.scrollHeight"); Long width = (Long) driver_js.executeScript("return document.body.scrollWidth"); System.out.println("height" + height); Map<String, Long> map = new HashMap<>(); map.put("height", height); map.put("width", width); driver.quit(); new PdfUtils().frontEndCut(imgName, url, map); Public frontEndCut(String imgName, String url, Map<String, Long> map) { String argument = "--window-size=" + map.get("width") + "," + map.get("height"); WebDriver driver = new PdfUtils().getDriver(argument); driver.get(url); Try {thread.sleep (3000); } catch (InterruptedException e) { e.printStackTrace(); } File screenshotFile = ((TakesScreenshot) driver).getScreenShotas (outputType.file); if((screenshotFile ! = null) && screenShotfile.exists ()) {// FileOutputStream out = null; FileInputStream in = null; try { in = new FileInputStream(screenshotFile); // Local path out = new FileOutputStream(mdisconfig.getuploadPath () + "/images/" + imgName + ".png"); byte[] b = new byte[1024]; while(true) { int temp = in.read(b, 0, b.length); If (temp == -1) {break; // If (temp == -1) {break; } out.write(b, 0, temp); }} catch (Exception e) {//TODO Exception handler}} driver.quit(); }Copy the code

Due to the rush of time, the code is relatively rough, the overall implementation idea is to call the browser of the server to visit the page to be screenshot, get the height and width of the entire page, and then by getting the width and height of the area for a screenshot to save to the local. After obtaining the image, you can cut the image according to the SIZE of A4 paper and paste it into PDF by IText. Cutting and generating PDF is relatively simple, and the code will not be pasted. As the page is written by VUE instead of static page, it is necessary to wait for a period of time when capturing the screenshot and obtaining the height, waiting for the page to be drawn completely.

3. Possible problems

1. An error occurs during the local operation

Solutions:

  • Check whether the Chrome version matches the driver version
  • Whether to grant the driver permission to run on due permissions
  • Check whether the Selenium version is the same as the Chrome version, and modify the Selenium version

2. An error occurs during the deployment to the server

Solutions:

  • Whether to grant the driver permission to run on due permissions
  • Check the native code for the Chrome-headless argument, paying special attention to the ‘–no-sandbox’ argument

3. Other errors (after selenium version was replaced, the version in jar package was not replaced)

Solutions:

  • Remove Swagger package from Maven, there may be conflicts

4. To summarize

After many attempts, I finally realized the effect I wanted. In the process of finding a solution, I encountered numerous problems. Finally, I stepped down the pit and wrote an article to record it.