6296893: BMP Writer handles TopDown property incorrectly for some of the compression types
authorbae
Thu, 11 Jun 2009 13:47:42 +0400
changeset 3011 1ee026ded54c
parent 3010 1284f414492b
child 3012 1420628f14e4
6296893: BMP Writer handles TopDown property incorrectly for some of the compression types Reviewed-by: igor, prr
jdk/src/share/classes/com/sun/imageio/plugins/bmp/BMPImageWriter.java
jdk/test/javax/imageio/plugins/bmp/TopDownTest.java
--- a/jdk/src/share/classes/com/sun/imageio/plugins/bmp/BMPImageWriter.java	Mon Jun 08 13:56:45 2009 -0700
+++ b/jdk/src/share/classes/com/sun/imageio/plugins/bmp/BMPImageWriter.java	Thu Jun 11 13:47:42 2009 +0400
@@ -506,6 +506,19 @@
 
         writeFileHeader(fileSize, offset);
 
+        /* According to MSDN description, the top-down image layout
+         * is allowed only if compression type is BI_RGB or BI_BITFIELDS.
+         * Images with any other compression type must be wrote in the
+         * bottom-up layout.
+         */
+        if (compressionType == BMPConstants.BI_RGB ||
+            compressionType == BMPConstants.BI_BITFIELDS)
+        {
+            isTopDown = bmpParam.isTopDown();
+        } else {
+            isTopDown = false;
+        }
+
         writeInfoHeader(headerSize, bitsPerPixel);
 
         // compression
@@ -588,8 +601,6 @@
             return;
         }
 
-        isTopDown = bmpParam.isTopDown();
-
         int maxBandOffset = bandOffsets[0];
         for (int i = 1; i < bandOffsets.length; i++)
             if (bandOffsets[i] > maxBandOffset)
@@ -1299,7 +1310,7 @@
         stream.writeInt(w);
 
         // height
-        stream.writeInt(h);
+        stream.writeInt(isTopDown ? -h : h);
 
         // number of planes
         stream.writeShort(1);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/imageio/plugins/bmp/TopDownTest.java	Thu Jun 11 13:47:42 2009 +0400
@@ -0,0 +1,142 @@
+/*
+ * 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     6296893
+ * @summary Test verifies that the isTopDown flag does not cause
+ *          a writing of bmp image in wrong scanline layout.
+ * @run     main TopDownTest
+ */
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.image.BufferedImage;
+
+import java.awt.image.IndexColorModel;
+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.plugins.bmp.BMPImageWriteParam;
+import javax.imageio.stream.ImageOutputStream;
+import static java.awt.image.BufferedImage.TYPE_INT_RGB;
+import static java.awt.image.BufferedImage.TYPE_BYTE_INDEXED;
+
+public class TopDownTest {
+
+    public static void main(String[] args) throws IOException {
+        BufferedImage src = createTestImage(24);
+
+        writeWithCompression(src, "BI_BITFIELDS");
+
+        writeWithCompression(src, "BI_RGB");
+
+        src = createTestImage(8);
+        writeWithCompression(src, "BI_RLE8");
+
+        src = createTestImage(4);
+        writeWithCompression(src, "BI_RLE4");
+
+    }
+
+    private static void writeWithCompression(BufferedImage src,
+                                             String compression) throws IOException
+    {
+        System.out.println("Compression: " + compression);
+        ImageWriter writer = ImageIO.getImageWritersByFormatName("BMP").next();
+        if (writer == null) {
+            throw new RuntimeException("Test failed: no bmp writer available");
+        }
+        File fout = File.createTempFile(compression + "_", ".bmp",
+                                        new File("."));
+
+        ImageOutputStream ios = ImageIO.createImageOutputStream(fout);
+        writer.setOutput(ios);
+
+        BMPImageWriteParam param = (BMPImageWriteParam)
+                writer.getDefaultWriteParam();
+        param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
+        param.setCompressionType(compression);
+        param.setTopDown(true);
+        writer.write(null, new IIOImage(src, null, null), param);
+        writer.dispose();
+        ios.flush();
+        ios.close();
+
+        BufferedImage dst = ImageIO.read(fout);
+
+        verify(dst);
+    }
+
+    private static void verify(BufferedImage dst) {
+        int top_rgb = dst.getRGB(50, 25);
+        System.out.printf("top_rgb: %x\n", top_rgb);
+        int bot_rgb = dst.getRGB(50, 75);
+        System.out.printf("bot_rgb: %x\n", bot_rgb);
+
+        // expect to see blue color on the top of image
+        if (top_rgb != 0xff0000ff) {
+            throw new RuntimeException("Invaid top color: " +
+                        Integer.toHexString(bot_rgb));
+        }
+        if (bot_rgb != 0xffff0000) {
+            throw new RuntimeException("Invalid bottom color: " +
+                    Integer.toHexString(bot_rgb));
+        }
+    }
+
+    private static BufferedImage createTestImage(int bpp) {
+
+        BufferedImage img = null;
+        switch (bpp) {
+            case 8:
+                img = new BufferedImage(100, 100, TYPE_BYTE_INDEXED);
+                break;
+            case 4: {
+                byte[] r = new byte[16];
+                byte[] g = new byte[16];
+                byte[] b = new byte[16];
+
+                r[1] = (byte)0xff;
+                b[0] = (byte)0xff;
+
+                IndexColorModel icm = new IndexColorModel(4, 16, r, g, b);
+                img = new BufferedImage(100, 100, TYPE_BYTE_INDEXED, icm);
+                }
+                break;
+            case 24:
+            default:
+            img = new BufferedImage(100, 100, TYPE_INT_RGB);
+        }
+        Graphics g = img.createGraphics();
+        g.setColor(Color.blue);
+        g.fillRect(0, 0, 100, 50);
+        g.setColor(Color.red);
+        g.fillRect(0, 50, 100, 50);
+        g.dispose();
+        return img;
+    }
+}