From 7ab6a2c4c9c88c73f416946625b411e3579f4245 Mon Sep 17 00:00:00 2001 From: Gustavo Trott <gustavo@trott.com.br> Date: Wed, 28 Apr 2021 15:47:55 -0300 Subject: [PATCH] Detects if PDF contains font Type 3 and rasterize automatically --- .../handlers/AbstractCommandHandler.java | 4 ++ .../handlers/PdfFontType3DetectorHandler.java | 42 ++++++++++++++++++ .../presentation/imp/SvgImageCreatorImp.java | 43 +++++++++++++++++-- 3 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 bbb-common-web/src/main/java/org/bigbluebutton/presentation/handlers/PdfFontType3DetectorHandler.java diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/handlers/AbstractCommandHandler.java b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/handlers/AbstractCommandHandler.java index d15172569b..fe0e8c95d9 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/handlers/AbstractCommandHandler.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/handlers/AbstractCommandHandler.java @@ -82,6 +82,10 @@ public abstract class AbstractCommandHandler extends return stdoutBuilder.indexOf(value) > -1; } + protected Boolean stdoutEquals(String value) { + return stdoutBuilder.toString().trim().equals(value); + } + protected Boolean stderrContains(String value) { return stderrBuilder.indexOf(value) > -1; } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/handlers/PdfFontType3DetectorHandler.java b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/handlers/PdfFontType3DetectorHandler.java new file mode 100644 index 0000000000..5d3e04750f --- /dev/null +++ b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/handlers/PdfFontType3DetectorHandler.java @@ -0,0 +1,42 @@ +/** + * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ + * + * Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below). + * + * This program is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation; either version 3.0 of the License, or (at your option) any later + * version. + * + * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. + * + */ + +package org.bigbluebutton.presentation.handlers; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PdfFontType3DetectorHandler extends AbstractCommandHandler { + + private static Logger log = LoggerFactory + .getLogger(PdfFontType3DetectorHandler.class); + + /** + * + * @return If pdf page contains one or more texts with font Type 3. + */ + public boolean hasFontType3() { + if (stdoutEquals("1")) { + return true; + } + + return false; + } + +} diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/SvgImageCreatorImp.java b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/SvgImageCreatorImp.java index 50e654e902..5cb07b8ffb 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/SvgImageCreatorImp.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/SvgImageCreatorImp.java @@ -16,6 +16,7 @@ import org.bigbluebutton.presentation.handlers.AddNamespaceToSvgHandler; import org.bigbluebutton.presentation.handlers.Pdf2PngPageConverterHandler; import org.bigbluebutton.presentation.handlers.Png2SvgConversionHandler; import org.bigbluebutton.presentation.handlers.SvgConversionHandler; +import org.bigbluebutton.presentation.handlers.PdfFontType3DetectorHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,6 +60,7 @@ public class SvgImageCreatorImp implements SvgImageCreator { int numSlides = 1; boolean done = false; + Boolean rasterizeCurrSlide = this.forceRasterizeSlides; // Convert single image file if (SupportedFileTypes.isImageFile(pres.getFileType())) { @@ -93,11 +95,38 @@ public class SvgImageCreatorImp implements SvgImageCreator { // Continue image processing long startConv = System.currentTimeMillis(); + + //Detect if PDF contains text with font Type 3 + //Pdftocairo has problem to convert Pdf to Svg when text contains font Type 3 + //Case detects type 3, rasterize will be forced to avoid the problem + NuProcessBuilder detectFontType3Process = this.createDetectFontType3Process(source,page); + PdfFontType3DetectorHandler detectFontType3tHandler = new PdfFontType3DetectorHandler(); + detectFontType3Process.setProcessListener(detectFontType3tHandler); + + NuProcess processDetectFontType3 = detectFontType3Process.start(); + try { + processDetectFontType3.waitFor(convPdfToSvgTimeout + 1, TimeUnit.SECONDS); + done = true; + } catch (InterruptedException e) { + done = false; + log.error("InterruptedException while verifing font type 3 on {} page {}: {}", pres.getName(), page, e); + } + + if(detectFontType3tHandler.isCommandTimeout()) { + log.error("Command execution (detectFontType3) exceeded the {} secs timeout for {} page {}.", convPdfToSvgTimeout, pres.getName(), page); + } + + if(detectFontType3tHandler.hasFontType3()) { + log.info("Font Type 3 identified on {} page {}, slide will be rasterized.", pres.getName(), page); + rasterizeCurrSlide = true; + } + + File destsvg = new File(imagePresentationDir.getAbsolutePath() + File.separatorChar + "slide" + page + ".svg"); SvgConversionHandler pHandler = new SvgConversionHandler(); - if(this.forceRasterizeSlides == false) { + if(rasterizeCurrSlide == false) { NuProcessBuilder convertPdfToSvg = createConversionProcess("-svg", page, source, destsvg.getAbsolutePath(), true); @@ -124,7 +153,7 @@ public class SvgImageCreatorImp implements SvgImageCreator { if (destsvg.length() == 0 || pHandler.numberOfImageTags() > imageTagThreshold || pHandler.numberOfPaths() > pathsThreshold || - this.forceRasterizeSlides) { + rasterizeCurrSlide) { // We need t delete the destination file as we are starting a // new conversion process @@ -134,7 +163,7 @@ public class SvgImageCreatorImp implements SvgImageCreator { done = false; - if(!this.forceRasterizeSlides) { + if(!rasterizeCurrSlide) { Map<String, Object> logData = new HashMap<String, Object>(); logData.put("meetingId", pres.getMeetingId()); logData.put("presId", pres.getId()); @@ -282,6 +311,14 @@ public class SvgImageCreatorImp implements SvgImageCreator { return new NuProcessBuilder(Arrays.asList("timeout", convPdfToSvgTimeout + "s", "/bin/sh", "-c", rawCommand)); } + private NuProcessBuilder createDetectFontType3Process(String source, int page) { + String rawCommand = "pdffonts -f " + String.valueOf(page) + " -l " + String.valueOf(page) + " " + source; + rawCommand += " | grep -m 1 'Type 3'"; + rawCommand += " | wc -l"; + + return new NuProcessBuilder(Arrays.asList("timeout", convPdfToSvgTimeout + "s", "/bin/sh", "-c", rawCommand)); + } + private File determineSvgImagesDirectory(File presentationFile) { return new File(presentationFile.getParent() + File.separatorChar + "svgs"); } -- GitLab