diff --git a/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java b/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java index 4c7903bfe84..89f735d8793 100644 --- a/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java +++ b/jdk/src/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java @@ -55,6 +55,7 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.sun.imageio.plugins.common.LZWCompressor; import com.sun.imageio.plugins.common.PaletteBuilder; +import sun.awt.image.ByteComponentRaster; public class GIFImageWriter extends ImageWriter { private static final boolean DEBUG = false; // XXX false for release! @@ -905,10 +906,18 @@ public class GIFImageWriter extends ImageWriter { LZWCompressor compressor = new LZWCompressor(stream, initCodeSize, false); + /* At this moment we know that input image is indexed image. + * We can directly copy data iff: + * - no subsampling required (periodX = 1, periodY = 0) + * - we can access data directly (image is non-tiled, + * i.e. image data are in single block) + * - we can calculate offset in data buffer (next 3 lines) + */ boolean isOptimizedCase = periodX == 1 && periodY == 1 && - sampleModel instanceof ComponentSampleModel && image.getNumXTiles() == 1 && image.getNumYTiles() == 1 && + sampleModel instanceof ComponentSampleModel && + image.getTile(0, 0) instanceof ByteComponentRaster && image.getTile(0, 0).getDataBuffer() instanceof DataBufferByte; int numRowsWritten = 0; @@ -921,11 +930,14 @@ public class GIFImageWriter extends ImageWriter { if (DEBUG) System.out.println("Writing interlaced"); if (isOptimizedCase) { - Raster tile = image.getTile(0, 0); + ByteComponentRaster tile = + (ByteComponentRaster)image.getTile(0, 0); byte[] data = ((DataBufferByte)tile.getDataBuffer()).getData(); ComponentSampleModel csm = (ComponentSampleModel)tile.getSampleModel(); int offset = csm.getOffset(sourceXOffset, sourceYOffset, 0); + // take into account the raster data offset + offset += tile.getDataOffset(0); int lineStride = csm.getScanlineStride(); writeRowsOpt(data, offset, lineStride, compressor, diff --git a/jdk/test/javax/imageio/plugins/gif/EncodeSubImageTest.java b/jdk/test/javax/imageio/plugins/gif/EncodeSubImageTest.java new file mode 100644 index 00000000000..407242161c2 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/gif/EncodeSubImageTest.java @@ -0,0 +1,161 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6795544 + * + * @summary Test verifes that Image I/O gif writer correctly handles + * buffered images based on translated reasters (typically + * produced by getSubImage() method). + * + * @run main EncodeSubImageTest gif + */ + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.awt.image.Raster; +import java.io.File; +import java.io.IOException; +import javax.imageio.IIOImage; +import javax.imageio.ImageIO; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.stream.ImageOutputStream; + +public class EncodeSubImageTest { + private static String format = "gif"; + private static ImageWriter writer; + private static String file_suffix; + private static final int subSampleX = 2; + private static final int subSampleY = 2; + + public static void main(String[] args) throws IOException { + if (args.length > 0) { + format = args[0]; + } + + writer = ImageIO.getImageWritersByFormatName(format).next(); + + file_suffix =writer.getOriginatingProvider().getFileSuffixes()[0]; + + BufferedImage src = createTestImage(); + EncodeSubImageTest m1 = new EncodeSubImageTest(src); + m1.doTest("test_src"); + + BufferedImage sub = src.getSubimage(subImageOffset, subImageOffset, + src.getWidth() - 2 * subImageOffset, + src.getHeight() - 2 * subImageOffset); + EncodeSubImageTest m2 = new EncodeSubImageTest(sub); + m2.doTest("test_sub"); + } + + BufferedImage img; + + public EncodeSubImageTest(BufferedImage img) { + this.img = img; + } + + public void doTest(String prefix) throws IOException { + System.out.println(prefix); + File f = new File(prefix + file_suffix); + write(f, false); + verify(f, false); + + System.out.println(prefix + "_subsampled"); + f = new File(prefix + "_subsampled"); + write(f, true); + verify(f, true); + + System.out.println(prefix + ": Test PASSED."); + } + + private static final int subImageOffset = 10; + + private void verify(File f, boolean isSubsampled) { + BufferedImage dst = null; + try { + dst = ImageIO.read(f); + } catch (IOException e) { + throw new RuntimeException("Test FAILED: can't readin test image " + + f.getAbsolutePath(), e); + } + if (dst == null) { + throw new RuntimeException("Test FAILED: no dst image available."); + } + + checkPixel(dst, 0, 0, isSubsampled); + + checkPixel(dst, img.getWidth() / 2, img.getHeight() / 2, isSubsampled); + } + + private void checkPixel(BufferedImage dst, int x, int y, + boolean isSubsampled) + { + int dx = isSubsampled ? x / subSampleX : x; + int dy = isSubsampled ? y / subSampleY : y; + int src_rgb = img.getRGB(x, y); + System.out.printf("src_rgb: %x\n", src_rgb); + + int dst_rgb = dst.getRGB(dx, dy); + System.out.printf("dst_rgb: %x\n", dst_rgb); + + if (src_rgb != dst_rgb) { + throw new RuntimeException("Test FAILED: invalid color in dst"); + } + } + + private static BufferedImage createTestImage() { + int w = 100; + int h = 100; + + BufferedImage src = new BufferedImage(w, h, + BufferedImage.TYPE_BYTE_INDEXED); + Graphics g = src.createGraphics(); + g.setColor(Color.red); + g.fillRect(0, 0, w, h); + g.setColor(Color.green); + g.fillRect(subImageOffset, subImageOffset, + w - 2 * subImageOffset, h - 2* subImageOffset); + g.setColor(Color.blue); + g.fillRect(2 * subImageOffset, 2 * subImageOffset, + w - 4 * subImageOffset, h - 4 * subImageOffset); + g.dispose(); + + return src; + } + + private void write(File f, boolean subsample) throws IOException { + ImageOutputStream ios = ImageIO.createImageOutputStream(f); + + writer.setOutput(ios); + ImageWriteParam p = writer.getDefaultWriteParam(); + if (subsample) { + p.setSourceSubsampling(subSampleX, subSampleY, 0, 0); + } + writer.write(null, new IIOImage(img, null, null), p); + ios.close(); + writer.reset(); + } +}