Skip to content
Snippets Groups Projects
Commit b6e0a571 authored by Gustavo Trott's avatar Gustavo Trott
Browse files

Implements forceRasterizeSlides (force convert presentation to png before svg)...

Implements forceRasterizeSlides (force convert presentation to png before svg) and pngWidthRasterizedSlides (force png width (px))
parent b2174446
No related branches found
No related tags found
No related merge requests found
...@@ -31,6 +31,8 @@ public class SvgImageCreatorImp implements SvgImageCreator { ...@@ -31,6 +31,8 @@ public class SvgImageCreatorImp implements SvgImageCreator {
private long pathsThreshold; private long pathsThreshold;
private int convPdfToSvgTimeout = 60; private int convPdfToSvgTimeout = 60;
private int svgResolutionPpi = 300; private int svgResolutionPpi = 300;
private boolean forceRasterizeSlides = false;
private int pngWidthRasterizedSlides = 2048;
private String BLANK_SVG; private String BLANK_SVG;
@Override @Override
...@@ -93,30 +95,37 @@ public class SvgImageCreatorImp implements SvgImageCreator { ...@@ -93,30 +95,37 @@ public class SvgImageCreatorImp implements SvgImageCreator {
File destsvg = new File(imagePresentationDir.getAbsolutePath() + File.separatorChar + "slide" + page + ".svg"); File destsvg = new File(imagePresentationDir.getAbsolutePath() + File.separatorChar + "slide" + page + ".svg");
NuProcessBuilder convertPdfToSvg = createConversionProcess("-svg", page, source, destsvg.getAbsolutePath(), SvgConversionHandler pHandler = new SvgConversionHandler();
if(this.forceRasterizeSlides == false) {
NuProcessBuilder convertPdfToSvg = createConversionProcess("-svg", page, source, destsvg.getAbsolutePath(),
true); true);
SvgConversionHandler pHandler = new SvgConversionHandler(); convertPdfToSvg.setProcessListener(pHandler);
convertPdfToSvg.setProcessListener(pHandler);
NuProcess process = convertPdfToSvg.start(); NuProcess process = convertPdfToSvg.start();
try { try {
process.waitFor(convPdfToSvgTimeout + 1, TimeUnit.SECONDS); process.waitFor(convPdfToSvgTimeout + 1, TimeUnit.SECONDS);
done = true; done = true;
} catch (InterruptedException e) { } catch (InterruptedException e) {
log.error("Interrupted Exception while generating SVG slides {}", pres.getName(), e); log.error("Interrupted Exception while generating SVG slides {}", pres.getName(), e);
} }
if(pHandler.isCommandTimeout()) { if(pHandler.isCommandTimeout()) {
log.error("Command execution (convertPdfToSvg) exceeded the {} secs timeout for {} page {}.", convPdfToSvgTimeout, pres.getName(), page); log.error("Command execution (convertPdfToSvg) exceeded the {} secs timeout for {} page {}.", convPdfToSvgTimeout, pres.getName(), page);
} }
if (!done) { if (!done) {
return done; return done;
}
} }
if (destsvg.length() == 0 || pHandler.numberOfImageTags() > imageTagThreshold
|| pHandler.numberOfPaths() > pathsThreshold) { if (destsvg.length() == 0 ||
pHandler.numberOfImageTags() > imageTagThreshold ||
pHandler.numberOfPaths() > pathsThreshold ||
this.forceRasterizeSlides) {
// We need t delete the destination file as we are starting a // We need t delete the destination file as we are starting a
// new conversion process // new conversion process
if (destsvg.exists()) { if (destsvg.exists()) {
...@@ -125,21 +134,24 @@ public class SvgImageCreatorImp implements SvgImageCreator { ...@@ -125,21 +134,24 @@ public class SvgImageCreatorImp implements SvgImageCreator {
done = false; done = false;
Map<String, Object> logData = new HashMap<String, Object>(); if(!this.forceRasterizeSlides) {
logData.put("meetingId", pres.getMeetingId()); Map<String, Object> logData = new HashMap<String, Object>();
logData.put("presId", pres.getId()); logData.put("meetingId", pres.getMeetingId());
logData.put("filename", pres.getName()); logData.put("presId", pres.getId());
logData.put("page", page); logData.put("filename", pres.getName());
logData.put("convertSuccess", pHandler.isCommandSuccessful()); logData.put("page", page);
logData.put("fileExists", destsvg.exists()); logData.put("convertSuccess", pHandler.isCommandSuccessful());
logData.put("numberOfImages", pHandler.numberOfImageTags()); logData.put("fileExists", destsvg.exists());
logData.put("numberOfPaths", pHandler.numberOfPaths()); logData.put("numberOfImages", pHandler.numberOfImageTags());
logData.put("logCode", "potential_problem_with_svg"); logData.put("numberOfPaths", pHandler.numberOfPaths());
logData.put("message", "Potential problem with generated SVG"); logData.put("logCode", "potential_problem_with_svg");
Gson gson = new Gson(); logData.put("message", "Potential problem with generated SVG");
String logStr = gson.toJson(logData); Gson gson = new Gson();
String logStr = gson.toJson(logData);
log.warn(" --analytics-- data={}", logStr);
log.warn(" --analytics-- data={}", logStr);
}
File tempPng = null; File tempPng = null;
String basePresentationame = UUID.randomUUID().toString(); String basePresentationame = UUID.randomUUID().toString();
...@@ -148,14 +160,15 @@ public class SvgImageCreatorImp implements SvgImageCreator { ...@@ -148,14 +160,15 @@ public class SvgImageCreatorImp implements SvgImageCreator {
} catch (IOException ioException) { } catch (IOException ioException) {
// We should never fall into this if the server is correctly // We should never fall into this if the server is correctly
// configured // configured
Map<String, Object> logData = new HashMap<String, Object>();
logData = new HashMap<String, Object>(); logData = new HashMap<String, Object>();
logData.put("meetingId", pres.getMeetingId()); logData.put("meetingId", pres.getMeetingId());
logData.put("presId", pres.getId()); logData.put("presId", pres.getId());
logData.put("filename", pres.getName()); logData.put("filename", pres.getName());
logData.put("logCode", "problem_with_creating_svg"); logData.put("logCode", "problem_with_creating_svg");
logData.put("message", "Unable to create temporary files"); logData.put("message", "Unable to create temporary files");
gson = new Gson(); Gson gson = new Gson();
logStr = gson.toJson(logData); String logStr = gson.toJson(logData);
log.error(" --analytics-- data={}", logStr, ioException); log.error(" --analytics-- data={}", logStr, ioException);
} }
...@@ -178,7 +191,6 @@ public class SvgImageCreatorImp implements SvgImageCreator { ...@@ -178,7 +191,6 @@ public class SvgImageCreatorImp implements SvgImageCreator {
if(tempPng.length() > 0) { if(tempPng.length() > 0) {
// Step 2: Convert a PNG image to SVG // Step 2: Convert a PNG image to SVG
NuProcessBuilder convertPngToSvg = new NuProcessBuilder(Arrays.asList("timeout", convPdfToSvgTimeout + "s", "convert", NuProcessBuilder convertPngToSvg = new NuProcessBuilder(Arrays.asList("timeout", convPdfToSvgTimeout + "s", "convert",
tempPng.getAbsolutePath(), destsvg.getAbsolutePath())); tempPng.getAbsolutePath(), destsvg.getAbsolutePath()));
...@@ -254,12 +266,19 @@ public class SvgImageCreatorImp implements SvgImageCreator { ...@@ -254,12 +266,19 @@ public class SvgImageCreatorImp implements SvgImageCreator {
private NuProcessBuilder createConversionProcess(String format, int page, String source, String destFile, private NuProcessBuilder createConversionProcess(String format, int page, String source, String destFile,
boolean analyze) { boolean analyze) {
String rawCommand = "pdftocairo -r " + this.svgResolutionPpi + " " + format + (analyze ? "" : " -singlefile") String rawCommand = "pdftocairo -r " + this.svgResolutionPpi + " " + format + (analyze ? "" : " -singlefile");
+ " -q -f " + String.valueOf(page) + " -l " + String.valueOf(page) + " " + source + " " + destFile;
//Resize png resolution to avoid too large files
if(format.equals("-png") && this.pngWidthRasterizedSlides != 0) {
rawCommand += " -scale-to-x " + this.pngWidthRasterizedSlides + " -scale-to-y -1 ";
}
rawCommand += " -q -f " + String.valueOf(page) + " -l " + String.valueOf(page) + " " + source + " " + destFile;
if (analyze) { if (analyze) {
rawCommand += " && cat " + destFile; rawCommand += " && cat " + destFile;
rawCommand += " | egrep 'data:image/png;base64|<path' | sed 's/ / /g' | cut -d' ' -f 1 | sort | uniq -cw 2"; rawCommand += " | egrep 'data:image/png;base64|<path' | sed 's/ / /g' | cut -d' ' -f 1 | sort | uniq -cw 2";
} }
return new NuProcessBuilder(Arrays.asList("timeout", convPdfToSvgTimeout + "s", "/bin/sh", "-c", rawCommand)); return new NuProcessBuilder(Arrays.asList("timeout", convPdfToSvgTimeout + "s", "/bin/sh", "-c", rawCommand));
} }
...@@ -314,4 +333,12 @@ public class SvgImageCreatorImp implements SvgImageCreator { ...@@ -314,4 +333,12 @@ public class SvgImageCreatorImp implements SvgImageCreator {
public void setSvgResolutionPpi(int svgResolutionPpi) { public void setSvgResolutionPpi(int svgResolutionPpi) {
this.svgResolutionPpi = svgResolutionPpi; this.svgResolutionPpi = svgResolutionPpi;
} }
public void setForceRasterizeSlides(boolean forceRasterizeSlides) {
this.forceRasterizeSlides = forceRasterizeSlides;
}
public void setPngWidthRasterizedSlides(int pngWidthRasterizedSlides) {
this.pngWidthRasterizedSlides = pngWidthRasterizedSlides;
}
} }
...@@ -108,6 +108,23 @@ svgConversionTimeout=60 ...@@ -108,6 +108,23 @@ svgConversionTimeout=60
#------------------------------------ #------------------------------------
svgPresentationResolutionPpi=300 svgPresentationResolutionPpi=300
#------------------------------------
# Force conversion of slides to PNG before converting to SVG
## This will solve problems like reported in issue #8835
## Disabled by default as it can affect the quality in zoom
#------------------------------------
forceRasterizeSlides=false
#------------------------------------
# Presentation will be resized to this width (in pixels) when rasterizing (converting to PNG)
## Applied in these situations:
## a) the source can't be converted directly to SVG ;
## b) option "forceRasterizeSlides" is defined as true ;
## To disable this constraint (and keep source resolution) define this property as 0.
#------------------------------------
pngWidthRasterizedSlides=2048
#------------------------------------ #------------------------------------
# Timeout(secs) to wait for conversion script execution # Timeout(secs) to wait for conversion script execution
#------------------------------------ #------------------------------------
......
...@@ -88,6 +88,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. ...@@ -88,6 +88,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<property name="blankSvg" value="${BLANK_SVG}"/> <property name="blankSvg" value="${BLANK_SVG}"/>
<property name="convPdfToSvgTimeout" value="${svgConversionTimeout}"/> <property name="convPdfToSvgTimeout" value="${svgConversionTimeout}"/>
<property name="svgResolutionPpi" value="${svgPresentationResolutionPpi}"/> <property name="svgResolutionPpi" value="${svgPresentationResolutionPpi}"/>
<property name="forceRasterizeSlides" value="${forceRasterizeSlides}"/>
<property name="pngWidthRasterizedSlides" value="${pngWidthRasterizedSlides}"/>
</bean> </bean>
<bean id="generatedSlidesInfoHelper" class="org.bigbluebutton.presentation.GeneratedSlidesInfoHelperImp"/> <bean id="generatedSlidesInfoHelper" class="org.bigbluebutton.presentation.GeneratedSlidesInfoHelperImp"/>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment