From ebd2618b2ed3a08ef409e668475625050417bf55 Mon Sep 17 00:00:00 2001 From: Adam Rauch Date: Wed, 5 Nov 2025 09:52:02 -0800 Subject: [PATCH 1/3] Export SVG plots to PNG at higher resolution --- .../org/labkey/api/attachments/SvgSource.java | 18 ++++- .../VisualizationController.java | 72 +++++++++---------- 2 files changed, 52 insertions(+), 38 deletions(-) diff --git a/api/src/org/labkey/api/attachments/SvgSource.java b/api/src/org/labkey/api/attachments/SvgSource.java index 0e5e542aebe..166f9765f44 100644 --- a/api/src/org/labkey/api/attachments/SvgSource.java +++ b/api/src/org/labkey/api/attachments/SvgSource.java @@ -3,6 +3,7 @@ import org.apache.batik.anim.dom.SVGDOMImplementation; import org.apache.batik.transcoder.TranscoderException; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; import org.labkey.api.util.PageFlowUtil; import org.labkey.api.view.NotFoundException; @@ -19,6 +20,8 @@ public class SvgSource { private final String _filteredSvg; + private Float _height = null; + public SvgSource(String svg) { if (StringUtils.isBlank(svg)) @@ -29,11 +32,19 @@ public SvgSource(String svg) if (!svg.contains("xmlns=\"" + SVGDOMImplementation.SVG_NAMESPACE_URI + "\"") && !svg.contains("xmlns='" + SVGDOMImplementation.SVG_NAMESPACE_URI + "'")) svg = svg.replace(" { @@ -740,8 +738,9 @@ public void validate(Object o, Errors errors) * Content-type of request must be text/xml, not any kind of multipart * Returns a PNG image. */ + @SuppressWarnings("unused") @RequiresPermission(ReadPermission.class) - public class ExportImageAction extends ExportSVGAction + public static class ExportImageAction extends ExportSVGAction { @Override public ModelAndView handleRequest() throws Exception @@ -753,7 +752,14 @@ public ModelAndView handleRequest() throws Exception DocumentConversionService svc = DocumentConversionService.get(); if (null != svc) - svc.svgToPng(getSVGSource(), response.getOutputStream()); + { + // Ensure high resolution image even if browser submits a small SVG. See Issue 53390. + SvgSource svgSource = getSVGSource(); + Float height = svgSource.getHeight(); + if (height != null) + height = Math.max(height * 2, 2000); + svc.svgToPng(svgSource, response.getOutputStream(), height); + } return null; } @@ -764,8 +770,9 @@ public ModelAndView handleRequest() throws Exception * Content-type of request must be text/xml, not any kind of multipart * Returns a PDF document containing the visualization as a scalable vector graphic */ + @SuppressWarnings("unused") @RequiresPermission(ReadPermission.class) - public class ExportPDFAction extends ExportSVGAction + public static class ExportPDFAction extends ExportSVGAction { @Override public ModelAndView handleRequest() throws Exception @@ -1133,74 +1140,65 @@ public ApiResponse execute(SaveVisualizationForm form, BindException errors) thr } } - @RequiresPermission(ReadPermission.class) - public class TimeChartWizardAction extends SimpleViewAction + private abstract class AbstractChartWizardAction extends SimpleViewAction { - String _navTitle = "Chart Wizard"; + private String _navTitle = "Chart Wizard"; @Override public ModelAndView getView(ChartWizardReportForm form, BindException errors) throws Exception { - form.setAllowToggleMode(true); form.setRenderType("time_chart"); + setHelpTopic("timeChart"); + + form.setAllowToggleMode(true); // issue 27439: allow chart wizard report lookup by name if reportId not provided Report report = getReport(form); if (form.getReportId() == null && report != null && report.getDescriptor() != null) form.setReportId(report.getDescriptor().getReportId()); - JspView timeChartWizard = new JspView<>("/org/labkey/visualization/views/chartWizard.jsp", form); + JspView timeChartWizard = new JspView<>("/org/labkey/visualization/views/chartWizard.jsp", form); timeChartWizard.setTitle(_navTitle); timeChartWizard.setFrame(WebPartView.FrameType.NONE); - VBox boxView = new VBox(timeChartWizard); if (report != null) - { _navTitle = report.getDescriptor().getReportName(); - } - return boxView; + return timeChartWizard; } @Override public void addNavTrail(NavTree root) { - setHelpTopic("timeChart"); root.addChild(_navTitle); } } @RequiresPermission(ReadPermission.class) - @Action(ActionType.SelectData.class) // TODO rename to just ChartWizardAction - public class GenericChartWizardAction extends SimpleViewAction + @Action(ActionType.SelectData.class) + public class TimeChartWizardAction extends AbstractChartWizardAction { - String _navTitle = "Chart Wizard"; - @Override public ModelAndView getView(ChartWizardReportForm form, BindException errors) throws Exception { - form.setAllowToggleMode(true); - - // issue 27439: allow chart wizard report lookup by name if reportId not provided - Report report = getReport(form); - if (form.getReportId() == null && report != null && report.getDescriptor() != null) - form.setReportId(report.getDescriptor().getReportId()); - - JspView view = new JspView<>("/org/labkey/visualization/views/chartWizard.jsp", form); - view.setTitle(_navTitle); - view.setFrame(WebPartView.FrameType.NONE); - - if (report != null) - _navTitle = report.getDescriptor().getReportName(); + form.setRenderType("time_chart"); + setHelpTopic("timeChart"); - return view; + return super.getView(form, errors); } + } + @RequiresPermission(ReadPermission.class) + @Action(ActionType.SelectData.class) + // TODO rename to just ChartWizardAction + public class GenericChartWizardAction extends AbstractChartWizardAction + { @Override - public void addNavTrail(NavTree root) + public ModelAndView getView(ChartWizardReportForm form, BindException errors) throws Exception { setHelpTopic("reportsAndViews"); - root.addChild(_navTitle); + + return super.getView(form, errors); } } From c65f3c5e22936ad1db6507ad1869299fa98ad3e6 Mon Sep 17 00:00:00 2001 From: labkey-tchad Date: Fri, 7 Nov 2025 14:59:48 -0800 Subject: [PATCH 2/3] AbstractChartWizardAction shouldn't set renderType or helpTopic --- .../labkey/visualization/VisualizationController.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/visualization/src/org/labkey/visualization/VisualizationController.java b/visualization/src/org/labkey/visualization/VisualizationController.java index c907d4dce78..c55ec658702 100644 --- a/visualization/src/org/labkey/visualization/VisualizationController.java +++ b/visualization/src/org/labkey/visualization/VisualizationController.java @@ -1147,9 +1147,6 @@ private abstract class AbstractChartWizardAction extends SimpleViewAction timeChartWizard = new JspView<>("/org/labkey/visualization/views/chartWizard.jsp", form); - timeChartWizard.setTitle(_navTitle); - timeChartWizard.setFrame(WebPartView.FrameType.NONE); + JspView chartWizard = new JspView<>("/org/labkey/visualization/views/chartWizard.jsp", form); + chartWizard.setTitle(_navTitle); + chartWizard.setFrame(WebPartView.FrameType.NONE); if (report != null) _navTitle = report.getDescriptor().getReportName(); - return timeChartWizard; + return chartWizard; } @Override From 410397b196b9851dc83d04413a6c7e9cb4732940 Mon Sep 17 00:00:00 2001 From: Adam Rauch Date: Sat, 8 Nov 2025 08:44:49 -0800 Subject: [PATCH 3/3] CS -> CI to restore previous behavior --- api/src/org/labkey/api/attachments/SvgSource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/org/labkey/api/attachments/SvgSource.java b/api/src/org/labkey/api/attachments/SvgSource.java index 166f9765f44..bf7c068a45d 100644 --- a/api/src/org/labkey/api/attachments/SvgSource.java +++ b/api/src/org/labkey/api/attachments/SvgSource.java @@ -44,7 +44,7 @@ public SvgSource(String svg) svg = svg.replaceAll("xlink:title", "title"); // Reject hrefs. See #45819. - if (Strings.CS.contains(svg, "xlink:href")) + if (Strings.CI.contains(svg, "xlink:href")) throw new RuntimeException(new TranscoderException("The security settings do not allow any external resources to be referenced from the document")); _filteredSvg = svg;