1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.platform.svg.internal

File BatikSVGRasterizer.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

18
53
8
1
182
136
22
0.42
6.62
8
2.75

Classes

Class Line # Actions
BatikSVGRasterizer 58 53 0% 22 0
1.0100%
 

Contributing tests

This file is covered by 13 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.platform.svg.internal;
21   
22    import java.io.File;
23    import java.io.FileOutputStream;
24    import java.io.IOException;
25    import java.io.OutputStream;
26    import java.io.StringReader;
27   
28    import javax.inject.Inject;
29    import javax.inject.Named;
30    import javax.inject.Singleton;
31    import javax.servlet.http.HttpServletResponse;
32   
33    import org.apache.batik.transcoder.SVGAbstractTranscoder;
34    import org.apache.batik.transcoder.TranscoderException;
35    import org.apache.batik.transcoder.TranscoderInput;
36    import org.apache.batik.transcoder.TranscoderOutput;
37    import org.apache.batik.transcoder.image.PNGTranscoder;
38    import org.apache.commons.io.FileUtils;
39    import org.apache.commons.lang3.exception.ExceptionUtils;
40    import org.slf4j.Logger;
41    import org.xwiki.component.annotation.Component;
42    import org.xwiki.container.Container;
43    import org.xwiki.container.servlet.ServletResponse;
44    import org.xwiki.model.reference.DocumentReference;
45    import org.xwiki.model.reference.DocumentReferenceResolver;
46    import org.xwiki.platform.svg.SVGRasterizer;
47    import org.xwiki.resource.temporary.TemporaryResourceReference;
48    import org.xwiki.resource.temporary.TemporaryResourceStore;
49   
50    /**
51    * The straight-forward implementation of the {@link SVGRasterizer} role using Batik.
52    *
53    * @version $Id: cd74e08fd09d5040f3e210cf67fe26e34557d84c $
54    * @since 8.0M1
55    */
56    @Component
57    @Singleton
 
58    public class BatikSVGRasterizer implements SVGRasterizer
59    {
60    private static final String TEMP_DIR_NAME = "svg";
61   
62    private static final String RASTER_FILE_EXTENSION = ".png";
63   
64    @Inject
65    private Logger logger;
66   
67    @Inject
68    private TemporaryResourceStore temporaryResourceStore;
69   
70    @Inject
71    @Named("current")
72    private DocumentReferenceResolver<String> currentDocumentResolver;
73   
74    @Inject
75    private Container container;
76   
 
77  7 toggle @Override
78    public File rasterizeToTemporaryFile(String content, int width, int height) throws IOException
79    {
80  7 String fileName = getTemporaryFileName(content, width, height);
81  7 TemporaryResourceReference reference = new TemporaryResourceReference(TEMP_DIR_NAME, fileName, null);
82  7 File out = this.temporaryResourceStore.getTemporaryFile(reference);
83  6 if (rasterizeToFile(content, out, width, height)) {
84  3 return out;
85    }
86  3 return null;
87    }
88   
 
89  5 toggle @Override
90    public TemporaryResourceReference rasterizeToTemporaryResource(String content, int width, int height)
91    throws IOException
92    {
93  5 return rasterizeToTemporaryResource(content, width, height, getCurrentDocument());
94    }
95   
 
96  5 toggle @Override
97    public TemporaryResourceReference rasterizeToTemporaryResource(String content, int width, int height,
98    DocumentReference targetContext) throws IOException
99    {
100  5 String fileName = getTemporaryFileName(content, width, height);
101  5 TemporaryResourceReference reference = new TemporaryResourceReference(TEMP_DIR_NAME, fileName, targetContext);
102  5 File out = this.temporaryResourceStore.getTemporaryFile(reference);
103  5 if (rasterizeToFile(content, out, width, height)) {
104  2 return reference;
105    }
106  3 return null;
107    }
108   
 
109  3 toggle @Override
110    public void rasterizeToResponse(String content, int width, int height) throws IOException
111    {
112  3 if (!(this.container.getResponse() instanceof ServletResponse)) {
113  1 return;
114    }
115  2 HttpServletResponse response = ((ServletResponse) this.container.getResponse()).getHttpServletResponse();
116  2 File result = rasterizeToTemporaryFile(content, width, height);
117  2 if (result == null) {
118  1 return;
119    }
120  1 response.setContentLength((int) result.length());
121  1 response.setContentType("image/png");
122  1 OutputStream os = response.getOutputStream();
123  1 FileUtils.copyFile(result, os);
124  1 os.flush();
125    }
126   
 
127  12 toggle private boolean rasterizeToFile(String content, File out, int width, int height) throws IOException
128    {
129  12 if (!out.getParentFile().exists() && !out.getParentFile().mkdirs()) {
130  3 this.logger.debug("Failed to create temporary folder [{}].", out.getParentFile().getAbsolutePath());
131  3 return false;
132  9 } else if (out.exists() && out.isFile()) {
133  2 this.logger.debug("Reusing existing temporary raster image: {}", out.getAbsolutePath());
134  2 return true;
135    } else {
136  7 try (OutputStream fout = new FileOutputStream(out)) {
137  6 this.logger.debug("Rasterizing to temp file: {}", out.getAbsolutePath());
138  6 TranscoderInput input = new TranscoderInput(new StringReader(content));
139  6 TranscoderOutput output = new TranscoderOutput(fout);
140  6 boolean success = rasterize(input, output, width, height);
141  6 if (!success) {
142  3 out.delete();
143    }
144  6 return success;
145    }
146    }
147    }
148   
 
149  6 toggle private boolean rasterize(TranscoderInput input, TranscoderOutput output, int width, int height)
150    {
151  6 PNGTranscoder transcoder = new PNGTranscoder();
152   
153  6 if (width > 0) {
154  3 transcoder.addTranscodingHint(SVGAbstractTranscoder.KEY_WIDTH, new Float(width));
155    }
156  6 if (height > 0) {
157  3 transcoder.addTranscodingHint(SVGAbstractTranscoder.KEY_HEIGHT, new Float(height));
158    }
159   
160    // Set maximum width and height to 8k to avoid DoS attacks
161  6 transcoder.addTranscodingHint(SVGAbstractTranscoder.KEY_MAX_WIDTH, new Float(8192));
162  6 transcoder.addTranscodingHint(SVGAbstractTranscoder.KEY_MAX_HEIGHT, new Float(8192));
163   
164  6 try {
165  6 transcoder.transcode(input, output);
166  3 return true;
167    } catch (TranscoderException ex) {
168  3 this.logger.warn("Failed to rasterize SVG image: {}", ExceptionUtils.getRootCauseMessage(ex));
169    }
170  3 return false;
171    }
172   
 
173  12 toggle private String getTemporaryFileName(String content, int width, int height)
174    {
175  12 return Math.abs(content.hashCode()) + RASTER_FILE_EXTENSION;
176    }
177   
 
178  5 toggle private DocumentReference getCurrentDocument()
179    {
180  5 return this.currentDocumentResolver.resolve("");
181    }
182    }