mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-03 19:45:28 -04:00
#442 SVG BaseURI issue fix
This commit is contained in:
parent
62538c3db9
commit
cc5af0134c
@ -110,24 +110,25 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
public BufferedImage read(int pIndex, ImageReadParam pParam) throws IOException {
|
||||
checkBounds(pIndex);
|
||||
|
||||
String baseURI = null;
|
||||
|
||||
if (pParam instanceof SVGReadParam) {
|
||||
SVGReadParam svgParam = (SVGReadParam) pParam;
|
||||
// Set IIOParams as hints
|
||||
|
||||
// Get the base URI
|
||||
// This must be done before converting the params to hints
|
||||
String baseURI = svgParam.getBaseURI();
|
||||
rasterizer.transcoderInput.setURI(baseURI);
|
||||
|
||||
// Set ImageReadParams as hints
|
||||
// Note: The cast to Map invokes a different method that preserves
|
||||
// unset defaults, DO NOT REMOVE!
|
||||
rasterizer.setTranscodingHints((Map) paramsToHints(svgParam));
|
||||
|
||||
// Get the base URI (not a hint)
|
||||
baseURI = svgParam.getBaseURI();
|
||||
}
|
||||
|
||||
Dimension size;
|
||||
if (pParam != null && (size = pParam.getSourceRenderSize()) != null) {
|
||||
// Use size...
|
||||
Dimension size = null;
|
||||
if (pParam != null) {
|
||||
size = pParam.getSourceRenderSize();
|
||||
}
|
||||
else {
|
||||
if (size == null) {
|
||||
size = new Dimension(getWidth(pIndex), getHeight(pIndex));
|
||||
}
|
||||
|
||||
@ -137,7 +138,6 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
try {
|
||||
processImageStarted(pIndex);
|
||||
|
||||
rasterizer.transcoderInput.setURI(baseURI);
|
||||
BufferedImage image = rasterizer.getImage();
|
||||
|
||||
Graphics2D g = destination.createGraphics();
|
||||
@ -155,10 +155,16 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
return destination;
|
||||
}
|
||||
catch (TranscoderException e) {
|
||||
throw new IIOException(e.getMessage(), e);
|
||||
Throwable cause = unwrapException(e);
|
||||
throw new IIOException(cause.getMessage(), cause);
|
||||
}
|
||||
}
|
||||
|
||||
private static Throwable unwrapException(TranscoderException ex) {
|
||||
// The TranscoderException is generally useless...
|
||||
return ex.getException() != null ? ex.getException() : ex;
|
||||
}
|
||||
|
||||
private TranscodingHints paramsToHints(SVGReadParam pParam) throws IOException {
|
||||
TranscodingHints hints = new TranscodingHints();
|
||||
// Note: We must allow generic ImageReadParams, so converting to
|
||||
@ -174,8 +180,8 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
}
|
||||
|
||||
if (size != null) {
|
||||
hints.put(ImageTranscoder.KEY_WIDTH, new Float(size.getWidth()));
|
||||
hints.put(ImageTranscoder.KEY_HEIGHT, new Float(size.getHeight()));
|
||||
hints.put(ImageTranscoder.KEY_WIDTH, (float) size.getWidth());
|
||||
hints.put(ImageTranscoder.KEY_HEIGHT, (float) size.getHeight());
|
||||
}
|
||||
|
||||
// Set area of interest
|
||||
@ -185,16 +191,16 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
|
||||
// Avoid that the batik transcoder scales the AOI up to original image size
|
||||
if (size == null) {
|
||||
hints.put(ImageTranscoder.KEY_WIDTH, new Float(region.getWidth()));
|
||||
hints.put(ImageTranscoder.KEY_HEIGHT, new Float(region.getHeight()));
|
||||
hints.put(ImageTranscoder.KEY_WIDTH, (float) region.getWidth());
|
||||
hints.put(ImageTranscoder.KEY_HEIGHT, (float) region.getHeight());
|
||||
}
|
||||
else {
|
||||
// Need to resize here...
|
||||
double xScale = size.getWidth() / origSize.getWidth();
|
||||
double yScale = size.getHeight() / origSize.getHeight();
|
||||
|
||||
hints.put(ImageTranscoder.KEY_WIDTH, new Float(region.getWidth() * xScale));
|
||||
hints.put(ImageTranscoder.KEY_HEIGHT, new Float(region.getHeight() * yScale));
|
||||
hints.put(ImageTranscoder.KEY_WIDTH, (float) (region.getWidth() * xScale));
|
||||
hints.put(ImageTranscoder.KEY_HEIGHT, (float) (region.getHeight() * yScale));
|
||||
}
|
||||
}
|
||||
else if (size != null) {
|
||||
@ -219,7 +225,7 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ImageReadParam getDefaultReadParam() {
|
||||
public SVGReadParam getDefaultReadParam() {
|
||||
return new SVGReadParam();
|
||||
}
|
||||
|
||||
@ -255,7 +261,7 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
*/
|
||||
private class Rasterizer extends SVGAbstractTranscoder /*ImageTranscoder*/ {
|
||||
|
||||
BufferedImage image = null;
|
||||
private BufferedImage image;
|
||||
private TranscoderInput transcoderInput;
|
||||
private float defaultWidth;
|
||||
private float defaultHeight;
|
||||
@ -266,17 +272,19 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
private TranscoderException exception;
|
||||
private BridgeContext context;
|
||||
|
||||
public BufferedImage createImage(final int width, final int height) {
|
||||
return ImageUtil.createTransparent(width, height);//, BufferedImage.TYPE_INT_ARGB);
|
||||
private BufferedImage createImage(final int width, final int height) {
|
||||
return ImageUtil.createTransparent(width, height); // BufferedImage.TYPE_INT_ARGB
|
||||
}
|
||||
|
||||
// This is cheating... We don't fully transcode after all
|
||||
protected void transcode(Document document, final String uri, final TranscoderOutput output) throws TranscoderException {
|
||||
// Sets up root, curTxf & curAoi
|
||||
// ----
|
||||
if ((document != null) && !(document.getImplementation() instanceof SVGDOMImplementation)) {
|
||||
DOMImplementation impl = (DOMImplementation) hints.get(KEY_DOM_IMPLEMENTATION);
|
||||
document = DOMUtilities.deepCloneDocument(document, impl);
|
||||
if (document != null) {
|
||||
if (!(document.getImplementation() instanceof SVGDOMImplementation)) {
|
||||
DOMImplementation impl = (DOMImplementation) hints.get(KEY_DOM_IMPLEMENTATION);
|
||||
document = DOMUtilities.deepCloneDocument(document, impl);
|
||||
}
|
||||
|
||||
if (uri != null) {
|
||||
try {
|
||||
@ -346,8 +354,8 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
processReadAborted();
|
||||
return null;
|
||||
}
|
||||
processImageProgress(10f);
|
||||
|
||||
processImageProgress(10f);
|
||||
|
||||
// Hacky workaround below...
|
||||
if (gvtRoot == null) {
|
||||
@ -369,6 +377,7 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
}
|
||||
ctx = context;
|
||||
// /Hacky
|
||||
|
||||
if (abortRequested()) {
|
||||
processReadAborted();
|
||||
return null;
|
||||
@ -489,11 +498,9 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
// now we are sure that the aoi is the image size
|
||||
Shape raoi = new Rectangle2D.Float(0, 0, width, height);
|
||||
// Warning: the renderer's AOI must be in user space
|
||||
renderer.repaint(curTxf.createInverse().
|
||||
createTransformedShape(raoi));
|
||||
renderer.repaint(curTxf.createInverse().createTransformedShape(raoi));
|
||||
// NOTE: repaint above cause nullpointer exception with fonts..???
|
||||
|
||||
|
||||
BufferedImage rend = renderer.getOffScreen();
|
||||
renderer = null; // We're done with it...
|
||||
|
||||
@ -558,18 +565,40 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
return image;
|
||||
}
|
||||
|
||||
protected int getDefaultWidth() throws TranscoderException {
|
||||
int getDefaultWidth() throws TranscoderException {
|
||||
init();
|
||||
return (int) (defaultWidth + 0.5);
|
||||
return (int) Math.ceil(defaultWidth);
|
||||
}
|
||||
|
||||
protected int getDefaultHeight() throws TranscoderException {
|
||||
int getDefaultHeight() throws TranscoderException {
|
||||
init();
|
||||
return (int) (defaultHeight + 0.5);
|
||||
return (int) Math.ceil(defaultHeight);
|
||||
}
|
||||
|
||||
public void setInput(final TranscoderInput pInput) {
|
||||
void setInput(final TranscoderInput pInput) {
|
||||
transcoderInput = pInput;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UserAgent createUserAgent() {
|
||||
return new SVGImageReaderUserAgent();
|
||||
}
|
||||
|
||||
private class SVGImageReaderUserAgent extends SVGAbstractTranscoderUserAgent {
|
||||
@Override
|
||||
public void displayError(Exception e) {
|
||||
displayError(e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayError(String message) {
|
||||
displayMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayMessage(String message) {
|
||||
processWarningOccurred(message.replaceAll("[\\r\\n]+", " "));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,18 +34,26 @@ import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.event.IIOReadWarningListener;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ImagingOpException;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* SVGImageReaderTest
|
||||
@ -146,4 +154,97 @@ public class SVGImageReaderTest extends ImageReaderAbstractTest<SVGImageReader>
|
||||
BufferedImage imageBlue = reader.read(0, param);
|
||||
assertEquals(0x0000FF, imageBlue.getRGB(50, 50) & 0xFFFFFF);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmbeddedBaseURI() throws URISyntaxException, IOException {
|
||||
URL resource = getClassLoaderResource("/svg/barChart.svg");
|
||||
|
||||
SVGImageReader reader = createReader();
|
||||
|
||||
TestData data = new TestData(resource, (Dimension) null);
|
||||
try (ImageInputStream stream = data.getInputStream()) {
|
||||
reader.setInput(stream);
|
||||
|
||||
IIOReadWarningListener listener = mock(IIOReadWarningListener.class);
|
||||
reader.addIIOReadWarningListener(listener);
|
||||
|
||||
SVGReadParam param = reader.getDefaultReadParam();
|
||||
param.setBaseURI(resource.toURI().toASCIIString());
|
||||
BufferedImage image = reader.read(0, param);
|
||||
|
||||
assertNotNull(image);
|
||||
assertEquals(450, image.getWidth());
|
||||
assertEquals(500, image.getHeight());
|
||||
|
||||
// CSS and embedded resources all go!
|
||||
verifyZeroInteractions(listener);
|
||||
}
|
||||
finally {
|
||||
reader.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmbeddedBeforeBaseURI() throws URISyntaxException, IOException {
|
||||
// Asking for metadata, width, height etc, before attempting to read using a param,
|
||||
// will cause the document to be parsed without a base URI.
|
||||
// This will work, but may not use the CSS...
|
||||
URL resource = getClassLoaderResource("/svg/barChart.svg");
|
||||
|
||||
SVGImageReader reader = createReader();
|
||||
|
||||
TestData data = new TestData(resource, (Dimension) null);
|
||||
try (ImageInputStream stream = data.getInputStream()) {
|
||||
reader.setInput(stream);
|
||||
|
||||
IIOReadWarningListener listener = mock(IIOReadWarningListener.class);
|
||||
reader.addIIOReadWarningListener(listener);
|
||||
|
||||
assertEquals(450, reader.getWidth(0));
|
||||
assertEquals(500, reader.getHeight(0));
|
||||
|
||||
// Expect the warning about the missing CSS
|
||||
verify(listener, atMost(1)).warningOccurred(any(ImageReader.class), anyString());
|
||||
reset(listener);
|
||||
|
||||
SVGReadParam param = reader.getDefaultReadParam();
|
||||
param.setBaseURI(resource.toURI().toASCIIString());
|
||||
BufferedImage image = reader.read(0, param);
|
||||
|
||||
assertNotNull(image);
|
||||
assertEquals(450, image.getWidth());
|
||||
assertEquals(500, image.getHeight());
|
||||
|
||||
// No more warnings now that the base URI is set
|
||||
verifyZeroInteractions(listener);
|
||||
}
|
||||
finally {
|
||||
reader.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmbeddedNoBaseURI() throws IOException {
|
||||
// With no base URI, we will throw an exception, about the missing embedded resource
|
||||
URL resource = getClassLoaderResource("/svg/barChart.svg");
|
||||
|
||||
SVGImageReader reader = createReader();
|
||||
|
||||
TestData data = new TestData(resource, (Dimension) null);
|
||||
try (ImageInputStream stream = data.getInputStream()) {
|
||||
reader.setInput(stream);
|
||||
|
||||
BufferedImage image = reader.read(0);
|
||||
|
||||
assertNotNull(image);
|
||||
assertEquals(450, image.getWidth());
|
||||
assertEquals(500, image.getHeight());
|
||||
}
|
||||
catch (IIOException allowed) {
|
||||
assertTrue(allowed.getMessage().contains("batikLogo.svg")); // The embedded resource we don't find
|
||||
}
|
||||
finally {
|
||||
reader.dispose();
|
||||
}
|
||||
}
|
||||
}
|
117
imageio/imageio-batik/src/test/resources/svg/barChart.svg
Normal file
117
imageio/imageio-batik/src/test/resources/svg/barChart.svg
Normal file
@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<?xml-stylesheet type="text/css" href="style/test.css" ?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
-->
|
||||
<!-- ========================================================================= -->
|
||||
<!-- Illustrates how SVG can be used for high quality graphs. -->
|
||||
<!-- -->
|
||||
<!-- @author vincent.hardy@eng.sun.com -->
|
||||
<!-- @author neeme.praks@one.lv -->
|
||||
<!-- @version $Id: barChart.svg 1733420 2016-03-03 07:41:59Z gadams $ -->
|
||||
<!-- ========================================================================= -->
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="body" width="450" height="500" xml:space="preserve" viewBox="0 0 450 500">
|
||||
<title>Bar Chart</title>
|
||||
|
||||
<g id="barChart" transform="translate(40, 100)" fill-rule="evenodd" clip-rule="evenodd" stroke="none" class="legend"
|
||||
stroke-width="1" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" style="text-anchor:start">
|
||||
|
||||
<g id="GridAndLegend" style="stroke:none;">
|
||||
<g stroke="black">
|
||||
|
||||
<!-- "floor" and "wall" -->
|
||||
<path fill="lightgray" stroke="darkgray" d="M 27,240 l 15,-15 v -224 l -15,15" />
|
||||
<path fill="lightgray" stroke="darkgray" d="M 41,225 v -224 h 316 v 224" />
|
||||
<path fill="darkgray" stroke="none" d="M 27,240 l 15,-15 h 316 l -15,15" />
|
||||
|
||||
<!-- axis lines -->
|
||||
<path d="M 27,240 h 316"/>
|
||||
<path d="M 27,240 v -224"/>
|
||||
|
||||
<!-- value axis major gridlines -->
|
||||
<g style="fill:none;">
|
||||
<path d="M 27,202 l 15,-15 h 316" />
|
||||
<path d="M 27,165 l 15,-15 h 316" />
|
||||
<path d="M 27,127 l 15,-15 h 316" />
|
||||
<path d="M 27, 90 l 15,-15 h 316" />
|
||||
<path d="M 27, 53 l 15,-15 h 316" />
|
||||
</g>
|
||||
|
||||
<!-- category axis major ticks -->
|
||||
<path d="M 27,245 v -5"/>
|
||||
<path d="M 106,245 v -5"/>
|
||||
<path d="M 185,245 v -5"/>
|
||||
<path d="M 264,245 v -5"/>
|
||||
|
||||
<!-- value axis minor ticks -->
|
||||
<path d="M 22,240 h 5"/>
|
||||
<path d="M 22,202 h 5"/>
|
||||
<path d="M 22,165 h 5"/>
|
||||
<path d="M 22,127 h 5"/>
|
||||
<path d="M 22, 90 h 5"/>
|
||||
<path d="M 22, 53 h 5"/>
|
||||
<path d="M 22, 15 h 5"/>
|
||||
</g>
|
||||
|
||||
<text transform="matrix(1 0 0 1 54 256)">Shoe</text>
|
||||
<text transform="matrix(1 0 0 1 142 256)">Car</text>
|
||||
<text transform="matrix(1 0 0 1 211 256)">Travel</text>
|
||||
<text transform="matrix(1 0 0 1 285 256)">Computer</text>
|
||||
|
||||
<text transform="matrix(1 0 0 1 13 247)"><tspan x="0" y="0">0</tspan></text>
|
||||
<text transform="matrix(1 0 0 1 6 209)"><tspan x="0" y="0">10</tspan></text>
|
||||
<text transform="matrix(1 0 0 1 6 171)"><tspan x="0" y="0">20</tspan></text>
|
||||
<text transform="matrix(1 0 0 1 6 134)"><tspan x="0" y="0">30</tspan></text>
|
||||
<text transform="matrix(1 0 0 1 6 96)"><tspan x="0" y="0">40</tspan></text>
|
||||
<text transform="matrix(1 0 0 1 6 60)"><tspan x="0" y="0">50</tspan></text>
|
||||
<text transform="matrix(1 0 0 1 6 22)"><tspan x="0" y="0">60</tspan></text>
|
||||
</g>
|
||||
|
||||
<g id="ShoeBar">
|
||||
<path style="fill:#8686E0;" d="M 86,240 v -37 l 15 -15 v 37 l -15,15 z"/>
|
||||
<path style="fill:#5B5B97;" d="M 86,203 h -39 l 15 -15 h 39 l -15,15 z"/>
|
||||
<path style="fill:#7575C3;" d="M 47,203 v 37 h 39 v -37 H 47 z"/>
|
||||
</g>
|
||||
<g id="CarBar">
|
||||
<path style="fill:#8686E0;" d="M 165,240 v -74 l 15 -15 v 74 l -15,15 z"/>
|
||||
<path style="fill:#5B5B97;" d="M 165,166 h -39 l 15 -15 h 39 l -15,15 z"/>
|
||||
<path style="fill:#7575C3;" d="M 126,166 v 74 h 39 v -74 h -39 z"/>
|
||||
</g>
|
||||
<g id="TravelBar">
|
||||
<path style="fill:#8686E0;" d="M 244,240 v -37 l 15 -15 v 37 l -15,15 z"/>
|
||||
<path style="fill:#5B5B97;" d="M 244,203 h -39 l 15 -15 h 39 l -15,15 z"/>
|
||||
<path style="fill:#7575C3;" d="M 205,203 v 37 h 39 v -37 h -39 z"/>
|
||||
</g>
|
||||
<g id="ComputerBar">
|
||||
<path style="fill:#8686E0;" d="M 323,240 v -224 l 15 -15 v 224 l -15,15 z"/>
|
||||
<path style="fill:#5B5B97;" d="M 323, 16 h -39 l 15 -15 h 39 l -15,15 z"/>
|
||||
<path style="fill:#7575C3;" d="M 284, 16 v 224 h 39 v -224 h -39 z"/>
|
||||
</g>
|
||||
|
||||
</g>
|
||||
|
||||
<!-- ============================================================= -->
|
||||
<!-- Batik sample mark -->
|
||||
<!-- ============================================================= -->
|
||||
<use xlink:href="batikLogo.svg#Batik_Tag_Box" />
|
||||
|
||||
</svg>
|
29
imageio/imageio-batik/src/test/resources/svg/style/test.css
Normal file
29
imageio/imageio-batik/src/test/resources/svg/style/test.css
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
.title {
|
||||
font-family: Arial, Helvetica;
|
||||
font-size: 16pt;
|
||||
text-anchor: middle;
|
||||
}
|
||||
.legend {
|
||||
font-family: Arial, Helvetica;
|
||||
font-size: 10pt;
|
||||
text-anchor: middle;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user