Remove usage of GhostScript and replace it by pdftocairo and pdfseparate.
This commit is contained in:
parent
106dbb3275
commit
466c931b92
@ -34,21 +34,11 @@ swfToolsDir=/usr/bin
|
||||
# Directory where ImageMagick's convert executable is located
|
||||
imageMagickDir=/usr/bin
|
||||
|
||||
#----------------------------------------------------
|
||||
# Use fullpath to ghostscript executable since the exec names are different
|
||||
# for each platform.
|
||||
ghostScriptExec=/usr/bin/gs
|
||||
|
||||
#----------------------------------------------------
|
||||
# Fonts directory passed into PDF2SWF to support highlighting of texts
|
||||
# in the SWF slides.
|
||||
fontsDir=/usr/share/fonts
|
||||
|
||||
#----------------------------------------------------
|
||||
# This is a workaround for a problem converting PDF files, referenced at
|
||||
# http://groups.google.com/group/comp.lang.postscript/browse_thread/thread/c2e264ca76534ce0?pli=1
|
||||
noPdfMarkWorkaround=/etc/bigbluebutton/nopdfmark.ps
|
||||
|
||||
#----------------------------------------------------
|
||||
# These will be copied in cases where the conversion process
|
||||
# fails to generate a slide from the uploaded presentation
|
||||
|
@ -21,8 +21,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
">
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||
|
||||
<bean id="documentConversionService" class="org.bigbluebutton.presentation.DocumentConversionServiceImp">
|
||||
<property name="messagingService" ref="messagingService"/>
|
||||
@ -37,15 +36,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
<property name="officeDocumentValidator" ref="officeDocumentValidator"/>
|
||||
</bean>
|
||||
|
||||
<bean id="pageExtractor" class="org.bigbluebutton.presentation.imp.GhostscriptPageExtractor">
|
||||
<property name="ghostscriptExec" value="${ghostScriptExec}"/>
|
||||
<property name="noPdfMarkWorkaround" value="${noPdfMarkWorkaround}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="imageMagickPageConverter" class="org.bigbluebutton.presentation.imp.ImageMagickPageConverter">
|
||||
<property name="imageMagickDir" value="${imageMagickDir}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="pageExtractor" class="org.bigbluebutton.presentation.imp.GhostscriptPageExtractor"/>
|
||||
|
||||
<bean id="png2SwfConverter" class="org.bigbluebutton.presentation.imp.Png2SwfPageConverter">
|
||||
<property name="swfToolsDir" value="${swfToolsDir}"/>
|
||||
</bean>
|
||||
@ -64,21 +56,13 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
</bean>
|
||||
|
||||
<bean id="pdf2SwfPageConverter" class="org.bigbluebutton.presentation.imp.Pdf2SwfPageConverter">
|
||||
<property name="ghostscriptExec" value="${ghostScriptExec}"/>
|
||||
<property name="swfToolsDir" value="${swfToolsDir}"/>
|
||||
<property name="fontsDir" value="${fontsDir}"/>
|
||||
<property name="noPdfMarkWorkaround" value="${noPdfMarkWorkaround}"/>
|
||||
<property name="placementsThreshold" value="${placementsThreshold}"/>
|
||||
<property name="defineTextThreshold" value="${defineTextThreshold}"/>
|
||||
<property name="imageTagThreshold" value="${imageTagThreshold}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="imageConvSvc" class="org.bigbluebutton.presentation.imp.PdfPageToImageConversionService">
|
||||
<property name="pageExtractor" ref="pageExtractor"/>
|
||||
<property name="pdfToImageConverter" ref="imageMagickPageConverter"/>
|
||||
<property name="imageToSwfConverter" ref="png2SwfConverter"/>
|
||||
</bean>
|
||||
|
||||
<bean id="thumbCreator" class="org.bigbluebutton.presentation.imp.ThumbnailCreatorImp">
|
||||
<property name="imageMagickDir" value="${imageMagickDir}"/>
|
||||
<property name="blankThumbnail" value="${BLANK_THUMBNAIL}"/>
|
||||
@ -98,7 +82,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
<constructor-arg index="0" value="${numConversionThreads}"/>
|
||||
<property name="counterService" ref="pageCounterService"/>
|
||||
<property name="pageConverter" ref="pdf2SwfPageConverter"/>
|
||||
<property name="pdfPageToImageConversionService" ref="imageConvSvc"/>
|
||||
<property name="thumbnailCreator" ref="thumbCreator"/>
|
||||
<property name="textFileCreator" ref="textFileCreator"/>
|
||||
<property name="svgImageCreator" ref="svgImageCreator"/>
|
||||
|
@ -25,7 +25,6 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.bigbluebutton.presentation.imp.PdfPageToImageConversionService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -37,7 +36,6 @@ public class PdfToSwfSlide {
|
||||
private UploadedPresentation pres;
|
||||
private int page;
|
||||
private PageConverter pdfToSwfConverter;
|
||||
private PdfPageToImageConversionService imageConvertService;
|
||||
private String BLANK_SLIDE;
|
||||
private int MAX_SWF_FILE_SIZE;
|
||||
|
||||
@ -49,28 +47,16 @@ public class PdfToSwfSlide {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
public PdfToSwfSlide createSlide() {
|
||||
public PdfToSwfSlide createSlide() {
|
||||
File presentationFile = pres.getUploadedFile();
|
||||
slide = new File(presentationFile.getParent() + File.separatorChar + "slide-" + page + ".swf");
|
||||
if (! pdfToSwfConverter.convert(presentationFile, slide, page, pres)) {
|
||||
Map<String, Object> logData = new HashMap<String, Object>();
|
||||
logData.put("meetingId", pres.getMeetingId());
|
||||
logData.put("presId", pres.getId());
|
||||
logData.put("filename", pres.getName());
|
||||
logData.put("page", page);
|
||||
logData.put("size(KB)", slide.length()/1024);
|
||||
|
||||
Gson gson = new Gson();
|
||||
String logStr = gson.toJson(logData);
|
||||
|
||||
log.warn("Failed to convert slide: data={}", logStr);
|
||||
|
||||
imageConvertService.convertPageAsAnImage(presentationFile, slide, page, pres);
|
||||
}
|
||||
slide = new File(presentationFile.getParent() + File.separatorChar
|
||||
+ "slide-" + page + ".swf");
|
||||
pdfToSwfConverter.convert(presentationFile, slide, page, pres);
|
||||
|
||||
// If all fails, generate a blank slide.
|
||||
if (!slide.exists()) {
|
||||
log.warn("Failed to create slide. Creating blank slide for " + slide.getAbsolutePath());
|
||||
log.warn("Failed to create slide. Creating blank slide for "
|
||||
+ slide.getAbsolutePath());
|
||||
generateBlankSlide();
|
||||
}
|
||||
|
||||
@ -79,13 +65,6 @@ public class PdfToSwfSlide {
|
||||
return this;
|
||||
}
|
||||
|
||||
private boolean slideMayHaveTooManyObjects(File slide) {
|
||||
// If the resulting swf file is greater than 500K, it probably contains a lot of objects
|
||||
// that it becomes very slow to render on the client. Take an image snapshot instead and
|
||||
// use it to generate the SWF file. (ralam Sept 2, 2009)
|
||||
return slide.length() > MAX_SWF_FILE_SIZE;
|
||||
}
|
||||
|
||||
public void generateBlankSlide() {
|
||||
if (BLANK_SLIDE != null) {
|
||||
Map<String, Object> logData = new HashMap<String, Object>();
|
||||
@ -95,7 +74,7 @@ public class PdfToSwfSlide {
|
||||
logData.put("page", page);
|
||||
|
||||
Gson gson = new Gson();
|
||||
String logStr = gson.toJson(logData);
|
||||
String logStr = gson.toJson(logData);
|
||||
|
||||
log.warn("Creating blank slide: data={}", logStr);
|
||||
|
||||
@ -108,10 +87,10 @@ public class PdfToSwfSlide {
|
||||
logData.put("page", page);
|
||||
|
||||
Gson gson = new Gson();
|
||||
String logStr = gson.toJson(logData);
|
||||
String logStr = gson.toJson(logData);
|
||||
|
||||
log.warn("Failed to create blank slide: data={}", logStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void copyBlankSlide(File slide) {
|
||||
@ -126,10 +105,6 @@ public class PdfToSwfSlide {
|
||||
this.pdfToSwfConverter = converter;
|
||||
}
|
||||
|
||||
public void setPdfPageToImageConversionService(PdfPageToImageConversionService service) {
|
||||
this.imageConvertService = service;
|
||||
}
|
||||
|
||||
public void setBlankSlide(String blankSlide) {
|
||||
this.BLANK_SLIDE = blankSlide;
|
||||
}
|
||||
|
@ -26,35 +26,17 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class GhostscriptPageExtractor implements PageExtractor {
|
||||
private static Logger log = LoggerFactory
|
||||
.getLogger(GhostscriptPageExtractor.class);
|
||||
private static Logger log = LoggerFactory
|
||||
.getLogger(GhostscriptPageExtractor.class);
|
||||
|
||||
private String GHOSTSCRIPT_EXEC;
|
||||
private String noPdfMarkWorkaround;
|
||||
private String SPACE = " ";
|
||||
private String SPACE = " ";
|
||||
|
||||
public boolean extractPage(File presentationFile, File output, int page) {
|
||||
String OPTIONS = "-sDEVICE=pdfwrite -dNOPAUSE -dQUIET -dBATCH";
|
||||
String FIRST_PAGE = "-dFirstPage=" + page;
|
||||
String LAST_PAGE = "-dLastPage=" + page;
|
||||
String DESTINATION = output.getAbsolutePath();
|
||||
String OUTPUT_FILE = "-sOutputFile=" + DESTINATION;
|
||||
public boolean extractPage(File presentationFile, File output, int page) {
|
||||
String COMMAND = "pdfseparate -f " + page + " -l " + page + SPACE
|
||||
+ presentationFile.getAbsolutePath() + SPACE + output.getAbsolutePath();
|
||||
|
||||
// extract that specific page and create a temp-pdf(only one page) with
|
||||
// GhostScript
|
||||
String COMMAND = GHOSTSCRIPT_EXEC + SPACE + OPTIONS + SPACE
|
||||
+ FIRST_PAGE + SPACE + LAST_PAGE + SPACE + OUTPUT_FILE + SPACE
|
||||
+ noPdfMarkWorkaround + SPACE
|
||||
+ presentationFile.getAbsolutePath();
|
||||
|
||||
return new ExternalProcessExecutor().exec(COMMAND, 60000);
|
||||
}
|
||||
|
||||
public void setGhostscriptExec(String exec) {
|
||||
GHOSTSCRIPT_EXEC = exec;
|
||||
}
|
||||
|
||||
public void setNoPdfMarkWorkaround(String noPdfMarkWorkaround) {
|
||||
this.noPdfMarkWorkaround = noPdfMarkWorkaround;
|
||||
}
|
||||
log.info("Extracting page {} for document {}", page,
|
||||
presentationFile.getAbsolutePath());
|
||||
return new ExternalProcessExecutor().exec(COMMAND, 60000);
|
||||
}
|
||||
}
|
||||
|
@ -1,54 +0,0 @@
|
||||
/**
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2012 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.imp;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.bigbluebutton.presentation.PageConverter;
|
||||
import org.bigbluebutton.presentation.UploadedPresentation;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ImageMagickPageConverter implements PageConverter {
|
||||
private static Logger log = LoggerFactory.getLogger(ImageMagickPageConverter.class);
|
||||
|
||||
private String IMAGEMAGICK_DIR;
|
||||
|
||||
public boolean convert(File presentationFile, File output, int page, UploadedPresentation pres){
|
||||
|
||||
String COMMAND = IMAGEMAGICK_DIR + "/convert -depth 8 " + presentationFile.getAbsolutePath() + " " + output.getAbsolutePath();
|
||||
|
||||
boolean done = new ExternalProcessExecutor().exec(COMMAND, 60000);
|
||||
|
||||
if (done && output.exists()) {
|
||||
return true;
|
||||
} else {
|
||||
log.warn("Failed to convert: " + output.getAbsolutePath() + " does not exist.");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setImageMagickDir(String dir) {
|
||||
IMAGEMAGICK_DIR = dir;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ public class Jpeg2SwfPageConverter implements PageConverter {
|
||||
|
||||
public boolean convert(File presentationFile, File output, int page, UploadedPresentation pres){
|
||||
|
||||
String COMMAND = SWFTOOLS_DIR + "/jpeg2swf -o " + output.getAbsolutePath() + " " + presentationFile.getAbsolutePath();
|
||||
String COMMAND = SWFTOOLS_DIR + File.separator + "jpeg2swf -o " + output.getAbsolutePath() + " " + presentationFile.getAbsolutePath();
|
||||
|
||||
boolean done = new ExternalProcessExecutor().exec(COMMAND, 60000);
|
||||
|
||||
|
@ -44,10 +44,8 @@ public class Pdf2SwfPageConverter implements PageConverter {
|
||||
private static Logger log = LoggerFactory
|
||||
.getLogger(Pdf2SwfPageConverter.class);
|
||||
|
||||
private String GHOSTSCRIPT_EXEC;
|
||||
private String SWFTOOLS_DIR;
|
||||
private String fontsDir;
|
||||
private String noPdfMarkWorkaround;
|
||||
private long placementsThreshold;
|
||||
private long defineTextThreshold;
|
||||
private long imageTagThreshold;
|
||||
@ -86,13 +84,6 @@ public class Pdf2SwfPageConverter implements PageConverter {
|
||||
long pdf2SwfEnd = System.currentTimeMillis();
|
||||
log.debug("Pdf2Swf conversion duration: {} sec",
|
||||
(pdf2SwfEnd - pdf2SwfStart) / 1000);
|
||||
boolean timedOut = pdf2SwfEnd
|
||||
- pdf2SwfStart >= Integer.parseInt(convTimeout.replaceFirst("s", ""))
|
||||
* 1000;
|
||||
boolean twiceTotalObjects = pHandler.numberOfPlacements()
|
||||
+ pHandler.numberOfTextTags()
|
||||
+ pHandler.numberOfImageTags() >= (placementsThreshold
|
||||
+ defineTextThreshold + imageTagThreshold) * 2;
|
||||
|
||||
File destFile = new File(dest);
|
||||
if (pHandler.isConversionSuccessful() && destFile.exists()
|
||||
@ -122,7 +113,6 @@ public class Pdf2SwfPageConverter implements PageConverter {
|
||||
|
||||
log.warn("Potential problem with generated SWF: data={}", logStr);
|
||||
|
||||
File tempPdfPage = null;
|
||||
File tempPng = null;
|
||||
String basePresentationame = FilenameUtils
|
||||
.getBaseName(presentation.getName());
|
||||
@ -135,14 +125,12 @@ public class Pdf2SwfPageConverter implements PageConverter {
|
||||
|
||||
long gsStart = System.currentTimeMillis();
|
||||
|
||||
// Step 1: Convert a PDF page to PNG using a raw GhostScript command
|
||||
// Step 1: Convert a PDF page to PNG using a raw pdftocairo
|
||||
NuProcessBuilder pbPng = new NuProcessBuilder(Arrays.asList("timeout",
|
||||
convTimeout, GHOSTSCRIPT_EXEC, "-sDEVICE=png16m", "-dNOPAUSE",
|
||||
"-dQUIET", "-dBATCH",
|
||||
!timedOut && !twiceTotalObjects ? "-r150" : "-r72",
|
||||
"-dGraphicsAlphaBits=4", "-dTextAlphaBits=4", "-dFirstPage=" + page,
|
||||
"-dLastPage=" + page, "-sOutputFile=" + tempPng.getAbsolutePath(),
|
||||
noPdfMarkWorkaround, presentation.getAbsolutePath()));
|
||||
convTimeout, "pdftocairo", "-png", "-singlefile", "-r", "150", "-f",
|
||||
String.valueOf(page), "-l", String.valueOf(page),
|
||||
presentation.getAbsolutePath(), tempPng.getAbsolutePath().substring(0,
|
||||
tempPng.getAbsolutePath().lastIndexOf('.'))));
|
||||
|
||||
Pdf2PngPageConverterHandler pbPngHandler = new Pdf2PngPageConverterHandler();
|
||||
pbPng.setProcessListener(pbPngHandler);
|
||||
@ -154,12 +142,13 @@ public class Pdf2SwfPageConverter implements PageConverter {
|
||||
}
|
||||
|
||||
long gsEnd = System.currentTimeMillis();
|
||||
log.debug("Ghostscript conversion duration: {} sec",
|
||||
log.debug("pdftocairo conversion duration: {} sec",
|
||||
(gsEnd - gsStart) / 1000);
|
||||
|
||||
long png2swfStart = System.currentTimeMillis();
|
||||
|
||||
// Step 2: Convert a PNG image to SWF
|
||||
// We need to update the file path as pdftocairo adds "-page.png"
|
||||
source = tempPng.getAbsolutePath();
|
||||
NuProcessBuilder pbSwf = new NuProcessBuilder(
|
||||
Arrays.asList("timeout", convTimeout,
|
||||
@ -174,7 +163,7 @@ public class Pdf2SwfPageConverter implements PageConverter {
|
||||
}
|
||||
|
||||
long png2swfEnd = System.currentTimeMillis();
|
||||
log.debug("ImageMagick conversion duration: {} sec",
|
||||
log.debug("SwfTools conversion duration: {} sec",
|
||||
(png2swfEnd - png2swfStart) / 1000);
|
||||
|
||||
// Delete the temporary PNG and PDF files after finishing the image
|
||||
@ -225,13 +214,4 @@ public class Pdf2SwfPageConverter implements PageConverter {
|
||||
public void setImageTagThreshold(long threshold) {
|
||||
imageTagThreshold = threshold;
|
||||
}
|
||||
|
||||
public void setGhostscriptExec(String exec) {
|
||||
GHOSTSCRIPT_EXEC = exec;
|
||||
}
|
||||
|
||||
public void setNoPdfMarkWorkaround(String noPdfMarkWorkaround) {
|
||||
this.noPdfMarkWorkaround = noPdfMarkWorkaround;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ public class Pdf2SwfPageCounter implements PageCounter {
|
||||
public int countNumberOfPages(File presentationFile) {
|
||||
int numPages = 0; //total numbers of this pdf
|
||||
|
||||
String COMMAND = SWFTOOLS_DIR + "/pdf2swf -I " + presentationFile.getAbsolutePath();
|
||||
String COMMAND = SWFTOOLS_DIR + File.separator + "pdf2swf -I " + presentationFile.getAbsolutePath();
|
||||
|
||||
Timer timer = null;
|
||||
Process p = null;
|
||||
|
@ -1,67 +0,0 @@
|
||||
/**
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2012 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.imp;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.bigbluebutton.presentation.PageConverter;
|
||||
import org.bigbluebutton.presentation.PageExtractor;
|
||||
import org.bigbluebutton.presentation.UploadedPresentation;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class PdfPageToImageConversionService {
|
||||
private static Logger log = LoggerFactory.getLogger(PdfPageToImageConversionService.class);
|
||||
|
||||
private PageExtractor extractor;
|
||||
private PageConverter pdfToImageConverter;
|
||||
private PageConverter imageToSwfConverter;
|
||||
|
||||
public boolean convertPageAsAnImage(File presentationFile, File output, int page, UploadedPresentation pres) {
|
||||
File tempDir = new File(presentationFile.getParent() + File.separatorChar + "temp");
|
||||
tempDir.mkdir();
|
||||
|
||||
File tempPdfFile = new File(tempDir.getAbsolutePath() + File.separator + "temp-" + page + ".pdf");
|
||||
|
||||
if (extractor.extractPage(presentationFile, tempPdfFile, page)) {
|
||||
File tempPngFile = new File(tempDir.getAbsolutePath() + "/temp-" + page + ".svg");
|
||||
|
||||
if (pdfToImageConverter.convert(tempPdfFile, tempPngFile, 1, pres)) {
|
||||
if (imageToSwfConverter.convert(tempPngFile, output, 1, pres)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setPageExtractor(PageExtractor extractor) {
|
||||
this.extractor = extractor;
|
||||
}
|
||||
|
||||
public void setPdfToImageConverter(PageConverter imageConverter) {
|
||||
this.pdfToImageConverter = imageConverter;
|
||||
}
|
||||
|
||||
public void setImageToSwfConverter(PageConverter swfConverter) {
|
||||
this.imageToSwfConverter = swfConverter;
|
||||
}
|
||||
}
|
@ -48,22 +48,21 @@ import org.slf4j.LoggerFactory;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
public class PdfToSwfSlidesGenerationService {
|
||||
private static Logger log = LoggerFactory.getLogger(PdfToSwfSlidesGenerationService.class);
|
||||
private static Logger log = LoggerFactory
|
||||
.getLogger(PdfToSwfSlidesGenerationService.class);
|
||||
|
||||
private SwfSlidesGenerationProgressNotifier notifier;
|
||||
private PageCounterService counterService;
|
||||
private PageConverter pdfToSwfConverter;
|
||||
private PdfPageToImageConversionService imageConvertService;
|
||||
private ExecutorService executor;
|
||||
private ExecutorService executor;
|
||||
private ThumbnailCreator thumbnailCreator;
|
||||
private TextFileCreator textFileCreator;
|
||||
private SvgImageCreator svgImageCreator;
|
||||
private long MAX_CONVERSION_TIME = 5*60*1000;
|
||||
private long MAX_CONVERSION_TIME = 5 * 60 * 1000;
|
||||
private String BLANK_SLIDE;
|
||||
private int MAX_SWF_FILE_SIZE;
|
||||
private boolean svgImagesRequired;
|
||||
private final long CONVERSION_TIMEOUT = 20000000000L; // 20s
|
||||
private int NUM_CONVERSION_THREADS = 2;
|
||||
|
||||
public PdfToSwfSlidesGenerationService(int numConversionThreads) {
|
||||
executor = Executors.newFixedThreadPool(numConversionThreads);
|
||||
@ -82,7 +81,7 @@ public class PdfToSwfSlidesGenerationService {
|
||||
}
|
||||
|
||||
notifier.sendConversionCompletedMessage(pres);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean determineNumberOfPages(UploadedPresentation pres) {
|
||||
@ -95,12 +94,15 @@ public class PdfToSwfSlidesGenerationService {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void sendFailedToCountPageMessage(CountingPageException e, UploadedPresentation pres) {
|
||||
private void sendFailedToCountPageMessage(CountingPageException e,
|
||||
UploadedPresentation pres) {
|
||||
MessageBuilder builder = new ConversionUpdateMessage.MessageBuilder(pres);
|
||||
|
||||
if (e.getExceptionType() == CountingPageException.ExceptionType.PAGE_COUNT_EXCEPTION) {
|
||||
builder.messageKey(ConversionMessageConstants.PAGE_COUNT_FAILED_KEY);
|
||||
} else if (e.getExceptionType() == CountingPageException.ExceptionType.PAGE_EXCEEDED_EXCEPTION) {
|
||||
if (e
|
||||
.getExceptionType() == CountingPageException.ExceptionType.PAGE_COUNT_EXCEPTION) {
|
||||
builder.messageKey(ConversionMessageConstants.PAGE_COUNT_FAILED_KEY);
|
||||
} else if (e
|
||||
.getExceptionType() == CountingPageException.ExceptionType.PAGE_EXCEEDED_EXCEPTION) {
|
||||
builder.numberOfPages(e.getPageCount());
|
||||
builder.maxNumberPages(e.getMaxNumberOfPages());
|
||||
builder.messageKey(ConversionMessageConstants.PAGE_COUNT_EXCEEDED_KEY);
|
||||
@ -124,16 +126,19 @@ public class PdfToSwfSlidesGenerationService {
|
||||
}
|
||||
|
||||
private void convertPdfToSwf(UploadedPresentation pres) {
|
||||
int numPages = pres.getNumberOfPages();
|
||||
int numPages = pres.getNumberOfPages();
|
||||
List<PdfToSwfSlide> slides = setupSlides(pres, numPages);
|
||||
|
||||
CompletionService<PdfToSwfSlide> completionService = new ExecutorCompletionService<PdfToSwfSlide>(executor);
|
||||
CompletionService<PdfToSwfSlide> completionService = new ExecutorCompletionService<PdfToSwfSlide>(
|
||||
executor);
|
||||
|
||||
generateSlides(pres, slides, completionService);
|
||||
generateSlides(pres, slides, completionService);
|
||||
}
|
||||
|
||||
private void generateSlides(UploadedPresentation pres, List<PdfToSwfSlide> slides, CompletionService<PdfToSwfSlide> completionService) {
|
||||
long MAXWAIT = MAX_CONVERSION_TIME * 60 /*seconds*/ * 1000 /*millis*/;
|
||||
private void generateSlides(UploadedPresentation pres,
|
||||
List<PdfToSwfSlide> slides,
|
||||
CompletionService<PdfToSwfSlide> completionService) {
|
||||
long MAXWAIT = MAX_CONVERSION_TIME * 60 /* seconds */ * 1000 /* millis */;
|
||||
int slidesCompleted = 0;
|
||||
|
||||
long presConvStart = System.currentTimeMillis();
|
||||
@ -150,12 +155,12 @@ public class PdfToSwfSlidesGenerationService {
|
||||
Future<PdfToSwfSlide> f = executor.submit(c);
|
||||
long endNanos = System.nanoTime() + CONVERSION_TIMEOUT;
|
||||
try {
|
||||
// Only wait for the remaining time budget
|
||||
long timeLeft = endNanos - System.nanoTime();
|
||||
// Only wait for the remaining time budget
|
||||
long timeLeft = endNanos - System.nanoTime();
|
||||
PdfToSwfSlide s = f.get(timeLeft, TimeUnit.NANOSECONDS);
|
||||
slidesCompleted++;
|
||||
notifier.sendConversionUpdateMessage(slidesCompleted, pres);
|
||||
} catch (ExecutionException e) {
|
||||
} catch (ExecutionException e) {
|
||||
Map<String, Object> logData = new HashMap<String, Object>();
|
||||
logData.put("meetingId", pres.getMeetingId());
|
||||
logData.put("presId", pres.getId());
|
||||
@ -163,11 +168,11 @@ public class PdfToSwfSlidesGenerationService {
|
||||
logData.put("page", slide.getPageNumber());
|
||||
|
||||
Gson gson = new Gson();
|
||||
String logStr = gson.toJson(logData);
|
||||
String logStr = gson.toJson(logData);
|
||||
|
||||
log.warn("ExecutionException while converting page: data={}", logStr);
|
||||
log.error(e.getMessage());
|
||||
} catch (InterruptedException e) {
|
||||
} catch (InterruptedException e) {
|
||||
Map<String, Object> logData = new HashMap<String, Object>();
|
||||
logData.put("meetingId", pres.getMeetingId());
|
||||
logData.put("presId", pres.getId());
|
||||
@ -175,11 +180,11 @@ public class PdfToSwfSlidesGenerationService {
|
||||
logData.put("page", slide.getPageNumber());
|
||||
|
||||
Gson gson = new Gson();
|
||||
String logStr = gson.toJson(logData);
|
||||
String logStr = gson.toJson(logData);
|
||||
|
||||
log.warn("InterruptedException while converting page: data={}", logStr);
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (TimeoutException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (TimeoutException e) {
|
||||
Map<String, Object> logData = new HashMap<String, Object>();
|
||||
logData.put("meetingId", pres.getMeetingId());
|
||||
logData.put("presId", pres.getId());
|
||||
@ -187,11 +192,11 @@ public class PdfToSwfSlidesGenerationService {
|
||||
logData.put("page", slide.getPageNumber());
|
||||
|
||||
Gson gson = new Gson();
|
||||
String logStr = gson.toJson(logData);
|
||||
String logStr = gson.toJson(logData);
|
||||
|
||||
log.warn("TimeoutException while converting page: data={}", logStr);
|
||||
f.cancel(true);
|
||||
}
|
||||
f.cancel(true);
|
||||
}
|
||||
|
||||
long pageConvEnd = System.currentTimeMillis();
|
||||
Map<String, Object> logData = new HashMap<String, Object>();
|
||||
@ -199,18 +204,18 @@ public class PdfToSwfSlidesGenerationService {
|
||||
logData.put("presId", pres.getId());
|
||||
logData.put("filename", pres.getName());
|
||||
logData.put("page", slide.getPageNumber());
|
||||
logData.put("conversionTime(sec)", (pageConvEnd - pageConvStart)/1000);
|
||||
logData.put("conversionTime(sec)", (pageConvEnd - pageConvStart) / 1000);
|
||||
Gson gson = new Gson();
|
||||
String logStr = gson.toJson(logData);
|
||||
String logStr = gson.toJson(logData);
|
||||
|
||||
log.debug("Page conversion duration(sec): data={}", logStr);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for (final PdfToSwfSlide slide : slides) {
|
||||
if (! slide.isDone()){
|
||||
if (!slide.isDone()) {
|
||||
|
||||
slide.generateBlankSlide();
|
||||
slide.generateBlankSlide();
|
||||
|
||||
Map<String, Object> logData = new HashMap<String, Object>();
|
||||
logData.put("meetingId", pres.getMeetingId());
|
||||
@ -218,12 +223,12 @@ public class PdfToSwfSlidesGenerationService {
|
||||
logData.put("filename", pres.getName());
|
||||
|
||||
Gson gson = new Gson();
|
||||
String logStr = gson.toJson(logData);
|
||||
String logStr = gson.toJson(logData);
|
||||
|
||||
log.warn("Creating blank slide: data={}", logStr);
|
||||
|
||||
notifier.sendConversionUpdateMessage(slidesCompleted++, pres);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long presConvEnd = System.currentTimeMillis();
|
||||
@ -231,23 +236,22 @@ public class PdfToSwfSlidesGenerationService {
|
||||
logData.put("meetingId", pres.getMeetingId());
|
||||
logData.put("presId", pres.getId());
|
||||
logData.put("filename", pres.getName());
|
||||
logData.put("conversionTime(sec)", (presConvEnd - presConvStart)/1000);
|
||||
logData.put("conversionTime(sec)", (presConvEnd - presConvStart) / 1000);
|
||||
Gson gson = new Gson();
|
||||
String logStr = gson.toJson(logData);
|
||||
String logStr = gson.toJson(logData);
|
||||
|
||||
log.debug("Presentation conversion duration (sec): data={}", logStr);
|
||||
}
|
||||
|
||||
|
||||
private List<PdfToSwfSlide> setupSlides(UploadedPresentation pres, int numPages) {
|
||||
private List<PdfToSwfSlide> setupSlides(UploadedPresentation pres,
|
||||
int numPages) {
|
||||
List<PdfToSwfSlide> slides = new ArrayList<PdfToSwfSlide>(numPages);
|
||||
|
||||
for (int page = 1; page <= numPages; page++) {
|
||||
for (int page = 1; page <= numPages; page++) {
|
||||
PdfToSwfSlide slide = new PdfToSwfSlide(pres, page);
|
||||
slide.setBlankSlide(BLANK_SLIDE);
|
||||
slide.setMaxSwfFileSize(MAX_SWF_FILE_SIZE);
|
||||
slide.setPageConverter(pdfToSwfConverter);
|
||||
slide.setPdfPageToImageConversionService(imageConvertService);
|
||||
|
||||
slides.add(slide);
|
||||
}
|
||||
@ -255,8 +259,6 @@ public class PdfToSwfSlidesGenerationService {
|
||||
return slides;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setCounterService(PageCounterService counterService) {
|
||||
this.counterService = counterService;
|
||||
}
|
||||
@ -265,10 +267,6 @@ public class PdfToSwfSlidesGenerationService {
|
||||
this.pdfToSwfConverter = converter;
|
||||
}
|
||||
|
||||
public void setPdfPageToImageConversionService(PdfPageToImageConversionService service) {
|
||||
this.imageConvertService = service;
|
||||
}
|
||||
|
||||
public void setBlankSlide(String blankSlide) {
|
||||
this.BLANK_SLIDE = blankSlide;
|
||||
}
|
||||
@ -284,17 +282,21 @@ public class PdfToSwfSlidesGenerationService {
|
||||
public void setThumbnailCreator(ThumbnailCreator thumbnailCreator) {
|
||||
this.thumbnailCreator = thumbnailCreator;
|
||||
}
|
||||
|
||||
public void setTextFileCreator(TextFileCreator textFileCreator) {
|
||||
this.textFileCreator = textFileCreator;
|
||||
}
|
||||
|
||||
public void setSvgImageCreator(SvgImageCreator svgImageCreator) {
|
||||
this.svgImageCreator = svgImageCreator;
|
||||
}
|
||||
|
||||
public void setMaxConversionTime(int minutes) {
|
||||
MAX_CONVERSION_TIME = minutes * 60 * 1000;
|
||||
}
|
||||
|
||||
public void setSwfSlidesGenerationProgressNotifier(SwfSlidesGenerationProgressNotifier notifier) {
|
||||
public void setSwfSlidesGenerationProgressNotifier(
|
||||
SwfSlidesGenerationProgressNotifier notifier) {
|
||||
this.notifier = notifier;
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ public class Png2SwfPageConverter implements PageConverter {
|
||||
private String SWFTOOLS_DIR;
|
||||
|
||||
public boolean convert(File presentationFile, File output, int page, UploadedPresentation pres){
|
||||
String COMMAND = SWFTOOLS_DIR + "/png2swf -o " + output.getAbsolutePath() + " " + presentationFile.getAbsolutePath();
|
||||
String COMMAND = SWFTOOLS_DIR + File.separator + "png2swf -o " + output.getAbsolutePath() + " " + presentationFile.getAbsolutePath();
|
||||
|
||||
boolean done = new ExternalProcessExecutor().exec(COMMAND, 60000);
|
||||
|
||||
|
@ -9,113 +9,88 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class SvgImageCreatorImp implements SvgImageCreator {
|
||||
private static Logger log = LoggerFactory
|
||||
.getLogger(SvgImageCreatorImp.class);
|
||||
private static Logger log = LoggerFactory.getLogger(SvgImageCreatorImp.class);
|
||||
|
||||
private String IMAGEMAGICK_DIR;
|
||||
private String IMAGEMAGICK_DIR;
|
||||
|
||||
@Override
|
||||
public boolean createSvgImages(UploadedPresentation pres) {
|
||||
boolean success = false;
|
||||
File svgImagesPresentationDir = determineSvgImagesDirectory(pres
|
||||
.getUploadedFile());
|
||||
if (!svgImagesPresentationDir.exists())
|
||||
svgImagesPresentationDir.mkdir();
|
||||
@Override
|
||||
public boolean createSvgImages(UploadedPresentation pres) {
|
||||
boolean success = false;
|
||||
File svgImagesPresentationDir = determineSvgImagesDirectory(
|
||||
pres.getUploadedFile());
|
||||
if (!svgImagesPresentationDir.exists())
|
||||
svgImagesPresentationDir.mkdir();
|
||||
|
||||
cleanDirectory(svgImagesPresentationDir);
|
||||
cleanDirectory(svgImagesPresentationDir);
|
||||
|
||||
try {
|
||||
extractPdfPages(pres);
|
||||
success = generateSvgImages(svgImagesPresentationDir, pres);
|
||||
} catch (InterruptedException e) {
|
||||
log.warn("Interrupted Exception while generating images.");
|
||||
success = false;
|
||||
try {
|
||||
success = generateSvgImages(svgImagesPresentationDir, pres);
|
||||
} catch (InterruptedException e) {
|
||||
log.warn("Interrupted Exception while generating images.");
|
||||
success = false;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private boolean generateSvgImages(File imagePresentationDir,
|
||||
UploadedPresentation pres) throws InterruptedException {
|
||||
String source = pres.getUploadedFile().getAbsolutePath();
|
||||
String dest;
|
||||
String COMMAND = "";
|
||||
boolean done = true;
|
||||
if (SupportedFileTypes.isImageFile(pres.getFileType())) {
|
||||
dest = imagePresentationDir.getAbsolutePath() + File.separator
|
||||
+ "slide1.pdf";
|
||||
COMMAND = IMAGEMAGICK_DIR + File.separator + "convert " + source + " "
|
||||
+ dest;
|
||||
|
||||
done = new ExternalProcessExecutor().exec(COMMAND, 60000);
|
||||
|
||||
source = imagePresentationDir.getAbsolutePath() + File.separator
|
||||
+ "slide1.pdf";
|
||||
dest = imagePresentationDir.getAbsolutePath() + File.separator
|
||||
+ "slide1.svg";
|
||||
COMMAND = "pdftocairo -rx 300 -ry 300 -svg -q -f 1 -l 1 " + source + " "
|
||||
+ dest;
|
||||
|
||||
done = new ExternalProcessExecutor().exec(COMMAND, 60000);
|
||||
|
||||
} else {
|
||||
for (int i = 1; i <= pres.getNumberOfPages(); i++) {
|
||||
File destsvg = new File(imagePresentationDir.getAbsolutePath()
|
||||
+ File.separatorChar + "slide" + i + ".svg");
|
||||
COMMAND = "pdftocairo -rx 300 -ry 300 -svg -q -f " + i + " -l " + i
|
||||
+ " " + File.separatorChar + source + " "
|
||||
+ destsvg.getAbsolutePath();
|
||||
|
||||
done = new ExternalProcessExecutor().exec(COMMAND, 60000);
|
||||
if (!done) {
|
||||
break;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
private void extractPdfPages(UploadedPresentation pres) {
|
||||
File pdfDir = new File(pres.getUploadedFile().getParent()
|
||||
+ File.separatorChar + "pdfs");
|
||||
if (!pdfDir.exists())
|
||||
pdfDir.mkdir();
|
||||
|
||||
if (SupportedFileTypes.isPdfFile(pres.getFileType())) {
|
||||
for (int i = 1; i <= pres.getNumberOfPages(); i++) {
|
||||
File pdfFile = new File(pdfDir.getAbsolutePath()
|
||||
+ File.separatorChar + "slide" + i + ".pdf");
|
||||
String COMMAND = IMAGEMAGICK_DIR
|
||||
+ "/gs -sDEVICE=pdfwrite -dNOPAUSE -dQUIET -dBATCH -dFirstPage="
|
||||
+ i + " -dLastPage=" + i + " -sOutputFile="
|
||||
+ pdfFile.getAbsolutePath()
|
||||
+ " /etc/bigbluebutton/nopdfmark.ps "
|
||||
+ pres.getUploadedFile().getAbsolutePath();
|
||||
new ExternalProcessExecutor().exec(COMMAND, 60000);
|
||||
}
|
||||
|
||||
}
|
||||
if (done) {
|
||||
return true;
|
||||
}
|
||||
log.warn("Failed to create svg images: " + COMMAND);
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean generateSvgImages(File imagePresentationDir,
|
||||
UploadedPresentation pres) throws InterruptedException {
|
||||
String source = pres.getUploadedFile().getAbsolutePath();
|
||||
String dest;
|
||||
String COMMAND = "";
|
||||
boolean done = true;
|
||||
if (SupportedFileTypes.isImageFile(pres.getFileType())) {
|
||||
dest = imagePresentationDir.getAbsolutePath() + File.separator
|
||||
+ "slide1.pdf";
|
||||
COMMAND = IMAGEMAGICK_DIR + "/convert " + source + " " + dest;
|
||||
done = new ExternalProcessExecutor().exec(COMMAND, 60000);
|
||||
private File determineSvgImagesDirectory(File presentationFile) {
|
||||
return new File(presentationFile.getParent() + File.separatorChar + "svgs");
|
||||
}
|
||||
|
||||
source = imagePresentationDir.getAbsolutePath() + File.separator
|
||||
+ "slide1.pdf";
|
||||
dest = imagePresentationDir.getAbsolutePath() + File.separator
|
||||
+ "slide1.svg";
|
||||
COMMAND = "pdftocairo -rx 300 -ry 300 -svg -q -f 1 -l 1 " + source
|
||||
+ " " + dest;
|
||||
done = new ExternalProcessExecutor().exec(COMMAND, 60000);
|
||||
|
||||
} else {
|
||||
for (int i = 1; i <= pres.getNumberOfPages(); i++) {
|
||||
File pdfFile = new File(imagePresentationDir.getParent()
|
||||
+ File.separatorChar + "pdfs" + File.separatorChar
|
||||
+ "slide" + i + ".pdf");
|
||||
File destsvg = new File(imagePresentationDir.getAbsolutePath()
|
||||
+ File.separatorChar + "slide" + i + ".svg");
|
||||
COMMAND = "pdftocairo -rx 300 -ry 300 -svg -q -f 1 -l 1 "
|
||||
+ File.separatorChar + pdfFile.getAbsolutePath() + " "
|
||||
+ destsvg.getAbsolutePath();
|
||||
|
||||
done = new ExternalProcessExecutor().exec(COMMAND, 60000);
|
||||
if (!done) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (done) {
|
||||
return true;
|
||||
}
|
||||
log.warn("Failed to create svg images: " + COMMAND);
|
||||
return false;
|
||||
private void cleanDirectory(File directory) {
|
||||
File[] files = directory.listFiles();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
files[i].delete();
|
||||
}
|
||||
}
|
||||
|
||||
private File determineSvgImagesDirectory(File presentationFile) {
|
||||
return new File(presentationFile.getParent() + File.separatorChar
|
||||
+ "svgs");
|
||||
}
|
||||
|
||||
private void cleanDirectory(File directory) {
|
||||
File[] files = directory.listFiles();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
files[i].delete();
|
||||
}
|
||||
}
|
||||
|
||||
public void setImageMagickDir(String imageMagickDir) {
|
||||
IMAGEMAGICK_DIR = imageMagickDir;
|
||||
}
|
||||
public void setImageMagickDir(String imageMagickDir) {
|
||||
IMAGEMAGICK_DIR = imageMagickDir;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -32,90 +32,95 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class TextFileCreatorImp implements TextFileCreator {
|
||||
private static Logger log = LoggerFactory.getLogger(TextFileCreatorImp.class);
|
||||
|
||||
private String IMAGEMAGICK_DIR;
|
||||
|
||||
@Override
|
||||
public boolean createTextFiles(UploadedPresentation pres) {
|
||||
boolean success = false;
|
||||
File textfilesDir = determineTextfilesDirectory(pres.getUploadedFile());
|
||||
if (! textfilesDir.exists())
|
||||
textfilesDir.mkdir();
|
||||
|
||||
cleanDirectory(textfilesDir);
|
||||
|
||||
try {
|
||||
success = generateTextFiles(textfilesDir, pres);
|
||||
} catch (InterruptedException e) {
|
||||
log.warn("Interrupted Exception while generating thumbnails.");
|
||||
success = false;
|
||||
}
|
||||
|
||||
//TODO: in case that it doesn't generated the textfile, we should create a textfile with some message
|
||||
// createUnavailableTextFile
|
||||
|
||||
return success;
|
||||
}
|
||||
private static Logger log = LoggerFactory.getLogger(TextFileCreatorImp.class);
|
||||
|
||||
private boolean generateTextFiles(File textfilesDir, UploadedPresentation pres) throws InterruptedException {
|
||||
boolean success = true;
|
||||
String source = pres.getUploadedFile().getAbsolutePath();
|
||||
String dest;
|
||||
String COMMAND = "";
|
||||
|
||||
if(SupportedFileTypes.isImageFile(pres.getFileType())){
|
||||
dest = textfilesDir.getAbsolutePath() + File.separator + "slide-1.txt";
|
||||
String text = "No text could be retrieved for the slide";
|
||||
|
||||
File file = new File(dest);
|
||||
Writer writer = null;
|
||||
try {
|
||||
writer = new BufferedWriter(new FileWriter(file));
|
||||
writer.write(text);
|
||||
} catch (IOException e) {
|
||||
log.error("Error: " + e.getMessage());
|
||||
success = false;
|
||||
} finally {
|
||||
try {
|
||||
writer.close();
|
||||
} catch (IOException e) {
|
||||
log.error("Error: " + e.getMessage());
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
}else{
|
||||
dest = textfilesDir.getAbsolutePath() + File.separator + "slide-";
|
||||
// sudo apt-get install xpdf-utils
|
||||
for( int i = 1; i <= pres.getNumberOfPages(); i++){
|
||||
COMMAND = IMAGEMAGICK_DIR + "/pdftotext -raw -nopgbrk -f "+ i +" -l " + i + " " + source + " " + dest + i + ".txt";
|
||||
boolean done = new ExternalProcessExecutor().exec(COMMAND, 60000);
|
||||
if (!done) {
|
||||
success = false;
|
||||
log.warn("Failed to create textfiles: " + COMMAND);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
private String IMAGEMAGICK_DIR;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private File determineTextfilesDirectory(File presentationFile) {
|
||||
return new File(presentationFile.getParent() + File.separatorChar + "textfiles");
|
||||
}
|
||||
|
||||
private void cleanDirectory(File directory) {
|
||||
File[] files = directory.listFiles();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
files[i].delete();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public boolean createTextFiles(UploadedPresentation pres) {
|
||||
boolean success = false;
|
||||
File textfilesDir = determineTextfilesDirectory(pres.getUploadedFile());
|
||||
if (!textfilesDir.exists())
|
||||
textfilesDir.mkdir();
|
||||
|
||||
public void setImageMagickDir(String imageMagickDir) {
|
||||
IMAGEMAGICK_DIR = imageMagickDir;
|
||||
}
|
||||
cleanDirectory(textfilesDir);
|
||||
|
||||
try {
|
||||
success = generateTextFiles(textfilesDir, pres);
|
||||
} catch (InterruptedException e) {
|
||||
log.warn("Interrupted Exception while generating thumbnails.");
|
||||
success = false;
|
||||
}
|
||||
|
||||
// TODO: in case that it doesn't generated the textfile, we should create a
|
||||
// textfile with some message
|
||||
// createUnavailableTextFile
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private boolean generateTextFiles(File textfilesDir,
|
||||
UploadedPresentation pres) throws InterruptedException {
|
||||
boolean success = true;
|
||||
String source = pres.getUploadedFile().getAbsolutePath();
|
||||
String dest;
|
||||
String COMMAND = "";
|
||||
|
||||
if (SupportedFileTypes.isImageFile(pres.getFileType())) {
|
||||
dest = textfilesDir.getAbsolutePath() + File.separator + "slide-1.txt";
|
||||
String text = "No text could be retrieved for the slide";
|
||||
|
||||
File file = new File(dest);
|
||||
Writer writer = null;
|
||||
try {
|
||||
writer = new BufferedWriter(new FileWriter(file));
|
||||
writer.write(text);
|
||||
} catch (IOException e) {
|
||||
log.error("Error: " + e.getMessage());
|
||||
success = false;
|
||||
} finally {
|
||||
try {
|
||||
writer.close();
|
||||
} catch (IOException e) {
|
||||
log.error("Error: " + e.getMessage());
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
dest = textfilesDir.getAbsolutePath() + File.separator + "slide-";
|
||||
// sudo apt-get install xpdf-utils
|
||||
for (int i = 1; i <= pres.getNumberOfPages(); i++) {
|
||||
COMMAND = IMAGEMAGICK_DIR + File.separator
|
||||
+ "pdftotext -raw -nopgbrk -enc UTF-8 -f " + i + " -l " + i + " "
|
||||
+ source + " " + dest + i + ".txt";
|
||||
boolean done = new ExternalProcessExecutor().exec(COMMAND, 60000);
|
||||
if (!done) {
|
||||
success = false;
|
||||
log.warn("Failed to create textfiles: " + COMMAND);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private File determineTextfilesDirectory(File presentationFile) {
|
||||
return new File(
|
||||
presentationFile.getParent() + File.separatorChar + "textfiles");
|
||||
}
|
||||
|
||||
private void cleanDirectory(File directory) {
|
||||
File[] files = directory.listFiles();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
files[i].delete();
|
||||
}
|
||||
}
|
||||
|
||||
public void setImageMagickDir(String imageMagickDir) {
|
||||
IMAGEMAGICK_DIR = imageMagickDir;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -32,132 +32,142 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ThumbnailCreatorImp implements ThumbnailCreator {
|
||||
private static Logger log = LoggerFactory.getLogger(ThumbnailCreatorImp.class);
|
||||
|
||||
private static final Pattern PAGE_NUMBER_PATTERN = Pattern.compile("(.+-thumb)-([0-9]+)(.png)");
|
||||
|
||||
private String IMAGEMAGICK_DIR;
|
||||
private String BLANK_THUMBNAIL;
|
||||
|
||||
private static String TEMP_THUMB_NAME = "temp-thumb";
|
||||
|
||||
public boolean createThumbnails(UploadedPresentation pres){
|
||||
boolean success = false;
|
||||
File thumbsDir = determineThumbnailDirectory(pres.getUploadedFile());
|
||||
|
||||
if (! thumbsDir.exists())
|
||||
thumbsDir.mkdir();
|
||||
|
||||
cleanDirectory(thumbsDir);
|
||||
|
||||
try {
|
||||
success = generateThumbnails(thumbsDir, pres);
|
||||
} catch (InterruptedException e) {
|
||||
log.warn("Interrupted Exception while generating thumbnails.");
|
||||
success = false;
|
||||
}
|
||||
|
||||
// Create blank thumbnails for pages that failed to generate a thumbnail.
|
||||
createBlankThumbnails(thumbsDir, pres.getNumberOfPages());
|
||||
|
||||
renameThumbnails(thumbsDir);
|
||||
|
||||
return true;
|
||||
}
|
||||
private static Logger log = LoggerFactory
|
||||
.getLogger(ThumbnailCreatorImp.class);
|
||||
|
||||
private boolean generateThumbnails(File thumbsDir, UploadedPresentation pres) throws InterruptedException {
|
||||
String source = pres.getUploadedFile().getAbsolutePath();
|
||||
String dest;
|
||||
String COMMAND = "";
|
||||
if(SupportedFileTypes.isImageFile(pres.getFileType())){
|
||||
dest = thumbsDir.getAbsolutePath() + File.separator + TEMP_THUMB_NAME + ".png";
|
||||
COMMAND = IMAGEMAGICK_DIR + "/convert -thumbnail 150x150 " + source + " " + dest;
|
||||
}else{
|
||||
dest = thumbsDir.getAbsolutePath() + File.separator + "thumb-";
|
||||
COMMAND = IMAGEMAGICK_DIR + "/gs -q -sDEVICE=pngalpha -dBATCH -dNOPAUSE -dNOPROMPT -dDOINTERPOLATE -dPDFFitPage -r16 -sOutputFile=" + dest +"%d.png " + source;
|
||||
}
|
||||
private static final Pattern PAGE_NUMBER_PATTERN = Pattern
|
||||
.compile("(.+-thumb)-([0-9]+)(.png)");
|
||||
|
||||
boolean done = new ExternalProcessExecutor().exec(COMMAND, 60000);
|
||||
private String IMAGEMAGICK_DIR;
|
||||
private String BLANK_THUMBNAIL;
|
||||
|
||||
if (done) {
|
||||
return true;
|
||||
} else {
|
||||
log.warn("Failed to create thumbnails: " + COMMAND);
|
||||
}
|
||||
private static String TEMP_THUMB_NAME = "temp-thumb";
|
||||
|
||||
return false;
|
||||
}
|
||||
public boolean createThumbnails(UploadedPresentation pres) {
|
||||
boolean success = false;
|
||||
File thumbsDir = determineThumbnailDirectory(pres.getUploadedFile());
|
||||
|
||||
private File determineThumbnailDirectory(File presentationFile) {
|
||||
return new File(presentationFile.getParent() + File.separatorChar + "thumbnails");
|
||||
}
|
||||
if (!thumbsDir.exists())
|
||||
thumbsDir.mkdir();
|
||||
|
||||
private void renameThumbnails(File dir) {
|
||||
/*
|
||||
* If more than 1 file, filename like 'temp-thumb-X.png' else filename is 'temp-thumb.png'
|
||||
*/
|
||||
if (dir.list().length > 1) {
|
||||
File[] files = dir.listFiles();
|
||||
Matcher matcher;
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
matcher = PAGE_NUMBER_PATTERN.matcher(files[i].getAbsolutePath());
|
||||
if (matcher.matches()) {
|
||||
// Path should be something like 'c:/temp/bigluebutton/presname/thumbnails/temp-thumb-1.png'
|
||||
// Extract the page number. There should be 4 matches.
|
||||
// 0. c:/temp/bigluebutton/presname/thumbnails/temp-thumb-1.png
|
||||
// 1. c:/temp/bigluebutton/presname/thumbnails/temp-thumb
|
||||
// 2. 1 ---> what we are interested in
|
||||
// 3. .png
|
||||
// We are interested in the second match.
|
||||
int pageNum = Integer.valueOf(matcher.group(2).trim()).intValue();
|
||||
String newFilename = "thumb-" + (pageNum + 1) + ".png";
|
||||
File renamedFile = new File(dir.getAbsolutePath() + File.separator + newFilename);
|
||||
files[i].renameTo(renamedFile);
|
||||
}
|
||||
}
|
||||
} else if (dir.list().length == 1) {
|
||||
File oldFilename = new File(dir.getAbsolutePath() + File.separator + dir.list()[0]);
|
||||
String newFilename = "thumb-1.png";
|
||||
File renamedFile = new File(oldFilename.getParent() + File.separator + newFilename);
|
||||
oldFilename.renameTo(renamedFile);
|
||||
}
|
||||
}
|
||||
|
||||
private void createBlankThumbnails(File thumbsDir, int pageCount) {
|
||||
File[] thumbs = thumbsDir.listFiles();
|
||||
|
||||
if (thumbs.length != pageCount) {
|
||||
for (int i = 0; i < pageCount; i++) {
|
||||
File thumb = new File(thumbsDir.getAbsolutePath() + File.separator + TEMP_THUMB_NAME + "-" + i + ".png");
|
||||
if (! thumb.exists()) {
|
||||
log.info("Copying blank thumbnail for slide " + i);
|
||||
copyBlankThumbnail(thumb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cleanDirectory(thumbsDir);
|
||||
|
||||
private void copyBlankThumbnail(File thumb) {
|
||||
try {
|
||||
FileUtils.copyFile(new File(BLANK_THUMBNAIL), thumb);
|
||||
} catch (IOException e) {
|
||||
log.error("IOException while copying blank thumbnail.");
|
||||
}
|
||||
}
|
||||
try {
|
||||
success = generateThumbnails(thumbsDir, pres);
|
||||
} catch (InterruptedException e) {
|
||||
log.warn("Interrupted Exception while generating thumbnails.");
|
||||
success = false;
|
||||
}
|
||||
|
||||
private void cleanDirectory(File directory) {
|
||||
File[] files = directory.listFiles();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
files[i].delete();
|
||||
}
|
||||
}
|
||||
// Create blank thumbnails for pages that failed to generate a thumbnail.
|
||||
createBlankThumbnails(thumbsDir, pres.getNumberOfPages());
|
||||
|
||||
public void setImageMagickDir(String imageMagickDir) {
|
||||
IMAGEMAGICK_DIR = imageMagickDir;
|
||||
}
|
||||
renameThumbnails(thumbsDir);
|
||||
|
||||
public void setBlankThumbnail(String blankThumbnail) {
|
||||
BLANK_THUMBNAIL = blankThumbnail;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
private boolean generateThumbnails(File thumbsDir, UploadedPresentation pres)
|
||||
throws InterruptedException {
|
||||
String source = pres.getUploadedFile().getAbsolutePath();
|
||||
String dest;
|
||||
String COMMAND = "";
|
||||
dest = thumbsDir.getAbsolutePath() + File.separator + TEMP_THUMB_NAME;
|
||||
if (SupportedFileTypes.isImageFile(pres.getFileType())) {
|
||||
COMMAND = IMAGEMAGICK_DIR + File.separator + "convert -thumbnail 150x150 "
|
||||
+ source + " " + dest + ".png";
|
||||
} else {
|
||||
COMMAND = "pdftocairo -png -scale-to 150 " + source + " " + dest;
|
||||
}
|
||||
|
||||
boolean done = new ExternalProcessExecutor().exec(COMMAND, 60000);
|
||||
|
||||
if (done) {
|
||||
return true;
|
||||
} else {
|
||||
log.warn("Failed to create thumbnails: " + COMMAND);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private File determineThumbnailDirectory(File presentationFile) {
|
||||
return new File(
|
||||
presentationFile.getParent() + File.separatorChar + "thumbnails");
|
||||
}
|
||||
|
||||
private void renameThumbnails(File dir) {
|
||||
/*
|
||||
* If more than 1 file, filename like 'temp-thumb-X.png' else filename is
|
||||
* 'temp-thumb.png'
|
||||
*/
|
||||
if (dir.list().length > 1) {
|
||||
File[] files = dir.listFiles();
|
||||
Matcher matcher;
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
matcher = PAGE_NUMBER_PATTERN.matcher(files[i].getAbsolutePath());
|
||||
if (matcher.matches()) {
|
||||
// Path should be something like
|
||||
// 'c:/temp/bigluebutton/presname/thumbnails/temp-thumb-1.png'
|
||||
// Extract the page number. There should be 4 matches.
|
||||
// 0. c:/temp/bigluebutton/presname/thumbnails/temp-thumb-1.png
|
||||
// 1. c:/temp/bigluebutton/presname/thumbnails/temp-thumb
|
||||
// 2. 1 ---> what we are interested in
|
||||
// 3. .png
|
||||
// We are interested in the second match.
|
||||
int pageNum = Integer.valueOf(matcher.group(2).trim()).intValue();
|
||||
String newFilename = "thumb-" + (pageNum) + ".png";
|
||||
File renamedFile = new File(
|
||||
dir.getAbsolutePath() + File.separator + newFilename);
|
||||
files[i].renameTo(renamedFile);
|
||||
}
|
||||
}
|
||||
} else if (dir.list().length == 1) {
|
||||
File oldFilename = new File(
|
||||
dir.getAbsolutePath() + File.separator + dir.list()[0]);
|
||||
String newFilename = "thumb-1.png";
|
||||
File renamedFile = new File(
|
||||
oldFilename.getParent() + File.separator + newFilename);
|
||||
oldFilename.renameTo(renamedFile);
|
||||
}
|
||||
}
|
||||
|
||||
private void createBlankThumbnails(File thumbsDir, int pageCount) {
|
||||
File[] thumbs = thumbsDir.listFiles();
|
||||
|
||||
if (thumbs.length != pageCount) {
|
||||
for (int i = 0; i < pageCount; i++) {
|
||||
File thumb = new File(thumbsDir.getAbsolutePath() + File.separator
|
||||
+ TEMP_THUMB_NAME + "-" + i + ".png");
|
||||
if (!thumb.exists()) {
|
||||
log.info("Copying blank thumbnail for slide " + i);
|
||||
copyBlankThumbnail(thumb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void copyBlankThumbnail(File thumb) {
|
||||
try {
|
||||
FileUtils.copyFile(new File(BLANK_THUMBNAIL), thumb);
|
||||
} catch (IOException e) {
|
||||
log.error("IOException while copying blank thumbnail.");
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanDirectory(File directory) {
|
||||
File[] files = directory.listFiles();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
files[i].delete();
|
||||
}
|
||||
}
|
||||
|
||||
public void setImageMagickDir(String imageMagickDir) {
|
||||
IMAGEMAGICK_DIR = imageMagickDir;
|
||||
}
|
||||
|
||||
public void setBlankThumbnail(String blankThumbnail) {
|
||||
BLANK_THUMBNAIL = blankThumbnail;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user