Index: src/java/org/apache/xmlgraphics/ps/ImageEncodingHelper.java =================================================================== --- src/java/org/apache/xmlgraphics/ps/ImageEncodingHelper.java (revision 1345021) +++ src/java/org/apache/xmlgraphics/ps/ImageEncodingHelper.java (working copy) @@ -47,6 +47,7 @@ private ColorModel encodedColorModel; private boolean firstTileDump; private boolean enableCMYK; + private boolean isBGR; /** * Main constructor @@ -234,7 +235,17 @@ Raster raster = image.getTile(0, 0); DataBuffer buffer = raster.getDataBuffer(); if (buffer instanceof DataBufferByte) { - out.write(((DataBufferByte)buffer).getData()); + byte[] bytes = ((DataBufferByte) buffer).getData(); + // see determineEncodingColorModel() to see why we permute B and R here + if (isBGR) { + for (int i = 0; i < bytes.length; i += 3) { + out.write(bytes[i + 2]); + out.write(bytes[i + 1]); + out.write(bytes[i]); + } + } else { + out.write(bytes); + } return true; } } @@ -285,12 +296,26 @@ piSampleModel = (PixelInterleavedSampleModel)sampleModel; int[] offsets = piSampleModel.getBandOffsets(); for (int i = 0; i < offsets.length; i++) { - if (offsets[i] != i) { + if (offsets[i] != i && offsets[i] != offsets.length - 1 - i) { //Don't encode directly as samples are not next to each other //i.e. offsets are not 012 (RGB) or 0123 (CMYK) + // let also pass 210 BGR and 3210 (KYMC); 3210 will be skipped below + // if 210 (BGR) the B and R bytes will be permuted later in optimizeWriteTo() return; } } + // check if we are in a BGR case; this is added here as a workaround for bug fix + // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6549882 that causes some PNG + // images to be loaded as BGR with the consequence that performance was being impacted + this.isBGR = false; + if (offsets.length == 3 && offsets[0] == 2 && offsets[1] == 1 && offsets[2] == 0) { + this.isBGR = true; + } + // make sure we did not get here due to a KMYC image + if (offsets.length == 4 && offsets[0] == 3 && offsets[1] == 2 && offsets[2] == 1 + && offsets[3] == 0) { + return; + } } if (cm.getTransferType() == DataBuffer.TYPE_BYTE && buffer.getOffset() == 0 Index: test/java/org/apache/xmlgraphics/ps/ImageEncodingHelperTestCase.java =================================================================== --- test/java/org/apache/xmlgraphics/ps/ImageEncodingHelperTestCase.java (revision 0) +++ test/java/org/apache/xmlgraphics/ps/ImageEncodingHelperTestCase.java (revision 0) @@ -0,0 +1,78 @@ +/* + * 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. + */ + +/* $Id$ */ + +package org.apache.xmlgraphics.ps; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.Arrays; + +import junit.framework.TestCase; + +import org.apache.commons.io.output.ByteArrayOutputStream; + +public class ImageEncodingHelperTestCase extends TestCase { + + private BufferedImage prepareImage(BufferedImage image) { + Graphics2D ig = image.createGraphics(); + ig.scale(.5, .5); + ig.setPaint(new Color(128, 0, 0)); + ig.fillRect(0, 0, 100, 50); + ig.setPaint(Color.orange); + ig.fillRect(100, 0, 100, 50); + ig.setPaint(Color.yellow); + ig.fillRect(0, 50, 100, 50); + ig.setPaint(Color.red); + ig.fillRect(100, 50, 100, 50); + ig.setPaint(new Color(255, 127, 127)); + ig.fillRect(0, 100, 100, 50); + ig.setPaint(Color.black); + ig.draw(new Rectangle2D.Double(0.5, 0.5, 199, 149)); + ig.dispose(); + return image; + } + + /** + * 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(). + * + * @throws IOException + */ + public void testRGBAndBGRImages() throws IOException { + BufferedImage imageBGR = new BufferedImage(100, 75, BufferedImage.TYPE_3BYTE_BGR); + imageBGR = prepareImage(imageBGR); + BufferedImage imageRGB = new BufferedImage(100, 75, BufferedImage.TYPE_INT_BGR); + imageRGB = prepareImage(imageRGB); + + ImageEncodingHelper imageEncodingHelperBGR = new ImageEncodingHelper(imageBGR); + ImageEncodingHelper imageEncodingHelperRGB = new ImageEncodingHelper(imageRGB); + + ByteArrayOutputStream baosBGR = new ByteArrayOutputStream(); + imageEncodingHelperBGR.encode(baosBGR); + + ByteArrayOutputStream baosRGB = new ByteArrayOutputStream(); + imageEncodingHelperRGB.encode(baosRGB); + + assertTrue(Arrays.equals(baosBGR.toByteArray(), baosRGB.toByteArray())); + } + +}