You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xmlgraphics.apache.org by me...@apache.org on 2012/07/25 11:49:29 UTC
svn commit: r1365504 - in /xmlgraphics/commons/trunk:
src/java/org/apache/xmlgraphics/ps/ImageEncodingHelper.java status.xml
test/java/org/apache/xmlgraphics/StandardTestSuite.java
test/java/org/apache/xmlgraphics/ps/ImageEncodingHelperTestCase.java
Author: mehdi
Date: Wed Jul 25 09:49:29 2012
New Revision: 1365504
URL: http://svn.apache.org/viewvc?rev=1365504&view=rev
Log:
Bugfix#53599: Performance improvement to bitmap image encoding with RGB DirectColorModel
Modified:
xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/ImageEncodingHelper.java
xmlgraphics/commons/trunk/status.xml
xmlgraphics/commons/trunk/test/java/org/apache/xmlgraphics/StandardTestSuite.java
xmlgraphics/commons/trunk/test/java/org/apache/xmlgraphics/ps/ImageEncodingHelperTestCase.java
Modified: xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/ImageEncodingHelper.java
URL: http://svn.apache.org/viewvc/xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/ImageEncodingHelper.java?rev=1365504&r1=1365503&r2=1365504&view=diff
==============================================================================
--- xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/ImageEncodingHelper.java (original)
+++ xmlgraphics/commons/trunk/src/java/org/apache/xmlgraphics/ps/ImageEncodingHelper.java Wed Jul 25 09:49:29 2012
@@ -20,10 +20,12 @@
package org.apache.xmlgraphics.ps;
import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
+import java.awt.image.DirectColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.PixelInterleavedSampleModel;
import java.awt.image.Raster;
@@ -31,6 +33,7 @@ import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.io.IOException;
import java.io.OutputStream;
+import java.util.Arrays;
import org.apache.xmlgraphics.image.GraphicsUtil;
@@ -111,6 +114,10 @@ public class ImageEncodingHelper {
}
private void writeRGBTo(OutputStream out) throws IOException {
+ boolean encoded = encodeRenderedImageWithDirectColorModelAsRGB(image, out);
+ if (encoded) {
+ return;
+ }
encodeRenderedImageAsRGB(image, out);
}
@@ -122,7 +129,7 @@ public class ImageEncodingHelper {
*/
public static void encodeRenderedImageAsRGB(RenderedImage image, OutputStream out)
throws IOException {
- Raster raster = image.getData();
+ Raster raster = getRaster(image);
Object data;
int nbands = raster.getNumBands();
int dataType = raster.getDataBuffer().getDataType();
@@ -143,13 +150,13 @@ public class ImageEncodingHelper {
data = new double[nbands];
break;
default:
- throw new IllegalArgumentException("Unknown data buffer type: "
- + dataType);
+ throw new IllegalArgumentException("Unknown data buffer type: " + dataType);
}
ColorModel colorModel = image.getColorModel();
int w = image.getWidth();
int h = image.getHeight();
+
byte[] buf = new byte[w * 3];
for (int y = 0; y < h; y++) {
int idx = -1;
@@ -164,6 +171,67 @@ public class ImageEncodingHelper {
}
/**
+ * Writes a RenderedImage to an OutputStream. This method optimizes the encoding
+ * of the {@link DirectColorModel} as it is returned by {@link ColorModel#getRGBdefault}.
+ * @param image the image
+ * @param out the OutputStream to write the pixels to
+ * @return true if this method encoded this image, false if the image is incompatible
+ * @throws IOException if an I/O error occurs
+ */
+ public static boolean encodeRenderedImageWithDirectColorModelAsRGB(
+ RenderedImage image, OutputStream out) throws IOException {
+ ColorModel cm = image.getColorModel();
+ if (cm.getColorSpace() != ColorSpace.getInstance(ColorSpace.CS_sRGB)) {
+ return false; //Need to go through color management
+ }
+ if (!(cm instanceof DirectColorModel)) {
+ return false; //Only DirectColorModel is supported here
+ }
+ DirectColorModel dcm = (DirectColorModel)cm;
+ final int[] templateMasks = new int[]
+ {0x00ff0000 /*R*/, 0x0000ff00 /*G*/, 0x000000ff /*B*/, 0xff000000 /*A*/};
+ int[] masks = dcm.getMasks();
+ if (!Arrays.equals(templateMasks, masks)) {
+ return false; //no flexibility here right now, might never be used anyway
+ }
+
+ Raster raster = getRaster(image);
+ int dataType = raster.getDataBuffer().getDataType();
+ if (dataType != DataBuffer.TYPE_INT) {
+ return false; //not supported
+ }
+
+ int w = image.getWidth();
+ int h = image.getHeight();
+
+ int[] data = new int[w];
+ byte[] buf = new byte[w * 3];
+ for (int y = 0; y < h; y++) {
+ int idx = -1;
+ raster.getDataElements(0, y, w, 1, data);
+ for (int x = 0; x < w; x++) {
+ int rgb = data[x];
+ buf[++idx] = (byte)(rgb >> 16);
+ buf[++idx] = (byte)(rgb >> 8);
+ buf[++idx] = (byte)(rgb);
+ }
+ out.write(buf);
+ }
+
+ return true;
+ }
+
+ private static Raster getRaster(RenderedImage image) {
+ if (image instanceof BufferedImage) {
+ return ((BufferedImage)image).getRaster();
+ } else {
+ //Note: this copies the image data (double memory consumption)
+ //TODO Investigate encoding in stripes: RenderedImage.copyData(WritableRaster)
+ return image.getData();
+ }
+ }
+
+ /**
* Converts a byte array containing 24 bit RGB image data to a grayscale
* image.
*
Modified: xmlgraphics/commons/trunk/status.xml
URL: http://svn.apache.org/viewvc/xmlgraphics/commons/trunk/status.xml?rev=1365504&r1=1365503&r2=1365504&view=diff
==============================================================================
--- xmlgraphics/commons/trunk/status.xml (original)
+++ xmlgraphics/commons/trunk/status.xml Wed Jul 25 09:49:29 2012
@@ -27,6 +27,7 @@
<person name="Adrian Cumiskey" email="acumiskey@apache.org" id="AC"/>
<person name="Christian Geisert" email="chrisg@apache.org" id="CG"/>
<person name="Vincent Hennebert" email="vhennebert@apache.org" id="VH"/>
+ <person name="Mehdi Houshmand" email="mehdi@apache.org" id="MH"/>
<person name="Clay Leeds" email="clay@apache.org" id="CL"/>
<person name="Jeremias Märki" email="jeremias@apache.org" id="JM"/>
<person name="Cameron McCormack" email="cam@apache.org" id="CM"/>
@@ -41,6 +42,9 @@
</contexts>
<changes>
<release version="Trunk" date="n/a">
+ <action context="Code" dev="MH" type="fix" fixes-bug="53599" due-to="JM and MH collaboration">
+ Performance improvement of DirectColorMode bitmap images
+ </action>
<action context="Code" dev="MH" type="fix" fixes-bug="53570" due-to="Robert Meyer">
Set the systemID of the StreamSource within the DataURIResolver
</action>
Modified: xmlgraphics/commons/trunk/test/java/org/apache/xmlgraphics/StandardTestSuite.java
URL: http://svn.apache.org/viewvc/xmlgraphics/commons/trunk/test/java/org/apache/xmlgraphics/StandardTestSuite.java?rev=1365504&r1=1365503&r2=1365504&view=diff
==============================================================================
--- xmlgraphics/commons/trunk/test/java/org/apache/xmlgraphics/StandardTestSuite.java (original)
+++ xmlgraphics/commons/trunk/test/java/org/apache/xmlgraphics/StandardTestSuite.java Wed Jul 25 09:49:29 2012
@@ -23,6 +23,7 @@ import junit.framework.Test;
import junit.framework.TestSuite;
import org.apache.xmlgraphics.image.codec.png.PNGEncoderTest;
+import org.apache.xmlgraphics.ps.ImageEncodingHelperTestCase;
import org.apache.xmlgraphics.ps.PSEscapeTestCase;
import org.apache.xmlgraphics.ps.dsc.ListenerTestCase;
import org.apache.xmlgraphics.ps.dsc.events.DSCValueParserTestCase;
@@ -54,6 +55,7 @@ public class StandardTestSuite {
suite.addTest(new TestSuite(ServiceTest.class));
suite.addTest(new TestSuite(ClasspathResourceTest.class));
suite.addTest(new TestSuite(PSEscapeTestCase.class));
+ suite.addTest(new TestSuite(ImageEncodingHelperTestCase.class));
suite.addTest(new TestSuite(DSCValueParserTestCase.class));
suite.addTest(new TestSuite(DSCToolsTestCase.class));
suite.addTest(new TestSuite(ListenerTestCase.class));
Modified: xmlgraphics/commons/trunk/test/java/org/apache/xmlgraphics/ps/ImageEncodingHelperTestCase.java
URL: http://svn.apache.org/viewvc/xmlgraphics/commons/trunk/test/java/org/apache/xmlgraphics/ps/ImageEncodingHelperTestCase.java?rev=1365504&r1=1365503&r2=1365504&view=diff
==============================================================================
--- xmlgraphics/commons/trunk/test/java/org/apache/xmlgraphics/ps/ImageEncodingHelperTestCase.java (original)
+++ xmlgraphics/commons/trunk/test/java/org/apache/xmlgraphics/ps/ImageEncodingHelperTestCase.java Wed Jul 25 09:49:29 2012
@@ -19,16 +19,27 @@
package org.apache.xmlgraphics.ps;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
+import java.awt.image.DataBuffer;
+import java.awt.image.DirectColorModel;
+import java.awt.image.WritableRaster;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import junit.framework.TestCase;
import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
public class ImageEncodingHelperTestCase extends TestCase {
@@ -52,6 +63,26 @@ public class ImageEncodingHelperTestCase
}
/**
+ * Tests encodeRenderedImageWithDirectColorModeAsRGB(). Tests the optimised method against the
+ * non-optimised method(encodeRenderedImageAsRGB) to ensure the BufferedImage produced are the
+ * same.
+ * @throws IOException if an I/O error occurs.
+ */
+ public void testEncodeRenderedImageWithDirectColorModelAsRGB() throws IOException {
+ BufferedImage image = new BufferedImage(100, 75, BufferedImage.TYPE_INT_ARGB);
+ image = prepareImage(image);
+
+ ByteArrayOutputStream optimized = new ByteArrayOutputStream();
+ ImageEncodingHelper.encodeRenderedImageWithDirectColorModelAsRGB(image, optimized);
+
+ ByteArrayOutputStream nonoptimized = new ByteArrayOutputStream();
+ ImageEncodingHelper.encodeRenderedImageAsRGB(image, nonoptimized);
+
+ assertTrue(Arrays.equals(nonoptimized.toByteArray(), optimized.toByteArray()));
+
+ }
+
+ /**
* Tests a BGR versus RBG image. Debugging shows the BGR follows the optimizeWriteTo() (which is intended).
* The bytes are compared with the RBG image, which happens to follow the writeRGBTo().
*
@@ -75,4 +106,45 @@ public class ImageEncodingHelperTestCase
assertTrue(Arrays.equals(baosBGR.toByteArray(), baosRGB.toByteArray()));
}
+ /**
+ * Tests encodeRenderedImageWithDirectColorModeAsRGB(). Uses mocking to test the method
+ * implementation.
+ * @throws FileNotFoundException if expected file was not found.
+ * @throws IOException if an I/O error occurs.
+ */
+ public void testMockedEncodeRenderedImageWithDirectColorModelAsRGB() throws IOException {
+ BufferedImage image = mock(BufferedImage.class);
+ final int[] templateMasks = new int[] { 0x00ff0000 /*R*/, 0x0000ff00 /*G*/,
+ 0x000000ff /*B*/, 0xff000000 /*A*/};
+ DirectColorModel dcm = new DirectColorModel(255, templateMasks[0], templateMasks[1],
+ templateMasks[2], templateMasks[3]);
+
+ WritableRaster raster = mock(WritableRaster.class);
+ DataBuffer buffer = mock(DataBuffer.class);
+
+ when(image.getColorModel()).thenReturn(dcm);
+ when(image.getRaster()).thenReturn(raster);
+ when(raster.getDataBuffer()).thenReturn(buffer);
+ when(buffer.getDataType()).thenReturn(DataBuffer.TYPE_INT);
+ when(image.getWidth()).thenReturn(3);
+ when(image.getHeight()).thenReturn(3);
+ final int expectedValue = 1 + 2 << 8 + 3 << 16;
+ Answer<Object> ans = new Answer<Object>() {
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ int[] data = (int[]) args[4];
+ Arrays.fill(data, expectedValue);
+ return null;
+ }
+ };
+ when(raster.getDataElements(anyInt(), anyInt(), anyInt(), anyInt(), anyObject()))
+ .thenAnswer(ans);
+
+ ByteArrayOutputStream optimized = new ByteArrayOutputStream();
+ ImageEncodingHelper.encodeRenderedImageWithDirectColorModelAsRGB(image, optimized);
+
+ byte[] expectedByteArray = new byte[27];
+ Arrays.fill(expectedByteArray, (byte) expectedValue);
+ assertTrue(Arrays.equals(expectedByteArray, optimized.toByteArray()));
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: commits-help@xmlgraphics.apache.org