You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by da...@apache.org on 2011/06/21 22:05:55 UTC

svn commit: r1138156 - in /commons/proper/sanselan/trunk/src: main/java/org/apache/sanselan/formats/ico/IcoImageParser.java test/java/org/apache/sanselan/formats/ico/IcoRoundtripTest.java

Author: damjan
Date: Tue Jun 21 20:05:54 2011
New Revision: 1138156

URL: http://svn.apache.org/viewvc?rev=1138156&view=rev
Log:
Fix use of the alpha channel for 32 bit BI_RGB compressed ICO files.
Test this.


Modified:
    commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/ico/IcoImageParser.java
    commons/proper/sanselan/trunk/src/test/java/org/apache/sanselan/formats/ico/IcoRoundtripTest.java

Modified: commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/ico/IcoImageParser.java
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/ico/IcoImageParser.java?rev=1138156&r1=1138155&r2=1138156&view=diff
==============================================================================
--- commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/ico/IcoImageParser.java (original)
+++ commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/ico/IcoImageParser.java Tue Jun 21 20:05:54 2011
@@ -341,21 +341,43 @@ public class IcoImageParser extends Imag
         int ColorsUsed = read4Bytes("ColorsUsed", is, "Not a Valid ICO File"); // ColorsUsed (4 bytes), we don?t use this (0)
         int ColorsImportant = read4Bytes("ColorsImportant", is,
                 "Not a Valid ICO File"); // ColorsImportant (4 bytes), we don?t use this (0)
+        int RedMask = 0;
+        int GreenMask = 0;
+        int BlueMask = 0;
+        int AlphaMask = 0;
+        if (Compression == 3)
+        {
+            RedMask = read4Bytes("RedMask", is, "Not a Valid ICO File");
+            GreenMask = read4Bytes("GreenMask", is, "Not a Valid ICO File");
+            BlueMask = read4Bytes("BlueMask", is, "Not a Valid ICO File");
+        }
+        byte[] RestOfFile = readByteArray("RestOfFile", is.available(), is);
 
         if (Size != 40)
             throw new ImageReadException("Not a Valid ICO File: Wrong bitmap header size " + Size);
         if (Planes != 1)
             throw new ImageReadException("Not a Valid ICO File: Planes can't be " + Planes);
 
+        if (Compression == 0 && BitCount == 32)
+        {
+            // 32 BPP RGB icons need an alpha channel, but BMP files don't have
+            // one unless BI_BITFIELDS is used...
+            Compression = 3;
+            RedMask = 0x00ff0000;
+            GreenMask = 0x0000ff00;
+            BlueMask = 0x000000ff;
+            AlphaMask = 0xff000000;
+        }
+
         BitmapHeader header = new BitmapHeader(Size, Width, Height, Planes,
                 BitCount, Compression, SizeImage, XPelsPerMeter, YPelsPerMeter,
                 ColorsUsed, ColorsImportant);
 
-        int bitmapPixelsOffset = 14 + 40 + ((Compression == 3) ? 3*4 : 0) +
+        int bitmapPixelsOffset = 14 + 56 +
                 4 * ((ColorsUsed == 0 && BitCount <= 8) ? (1 << BitCount) : ColorsUsed);
-        int bitmapSize = 14 + iconData.length;
+        int bitmapSize = 14 + 56 + RestOfFile.length;
 
-        ByteArrayOutputStream baos = new ByteArrayOutputStream(14 + iconData.length);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream(bitmapSize);
         BinaryOutputStream bos = new BinaryOutputStream(baos,
                 BinaryOutputStream.BYTE_ORDER_LITTLE_ENDIAN);
 
@@ -365,7 +387,7 @@ public class IcoImageParser extends Imag
         bos.write4Bytes(0);
         bos.write4Bytes(bitmapPixelsOffset);
 
-        bos.write4Bytes(Size);
+        bos.write4Bytes(56);
         bos.write4Bytes(Width);
         bos.write4Bytes(Height / 2);
         bos.write2Bytes(Planes);
@@ -376,7 +398,11 @@ public class IcoImageParser extends Imag
         bos.write4Bytes(YPelsPerMeter);
         bos.write4Bytes(ColorsUsed);
         bos.write4Bytes(ColorsImportant);
-        bos.write(iconData, 40, iconData.length - 40);
+        bos.write4Bytes(RedMask);
+        bos.write4Bytes(GreenMask);
+        bos.write4Bytes(BlueMask);
+        bos.write4Bytes(AlphaMask);
+        bos.write(RestOfFile);
         bos.flush();
 
         ByteArrayInputStream bmpInputStream = new ByteArrayInputStream(baos.toByteArray());
@@ -402,41 +428,44 @@ public class IcoImageParser extends Imag
             throw ioEx;
         }
 
-        // FIXME: get BmpImageParser to support alpha, then uncomment below
-//        boolean allAlphasZero = true;
-//        if (BitCount == 32)
-//        {
-//            for (int y = 0; allAlphasZero && y < bmpImage.getHeight(); y++)
-//            {
-//                for (int x = 0; x < bmpImage.getWidth(); x++)
-//                {
-//                    if ((bmpImage.getRGB(x, y) & 0xff000000) != 0)
-//                    {
-//                        allAlphasZero = false;
-//                        break;
-//                    }
-//                }
-//            }
-//        }
-        BufferedImage resultImage = new BufferedImage(bmpImage.getWidth(), bmpImage.getHeight(),
-                BufferedImage.TYPE_INT_ARGB);
-        for (int y = 0; y < resultImage.getHeight(); y++)
+        boolean allAlphasZero = true;
+        if (BitCount == 32)
         {
-            for (int x = 0; x < resultImage.getWidth(); x++)
+            for (int y = 0; allAlphasZero && y < bmpImage.getHeight(); y++)
             {
-                int alpha = 0xff;
-                if (transparency_map != null)
+                for (int x = 0; x < bmpImage.getWidth(); x++)
                 {
-                    int alpha_byte = 0xff & transparency_map[t_scanline_size
-                            * (bmpImage.getHeight() - y - 1) + (x / 8)];
-                    alpha = 0x01 & (alpha_byte >> (7 - (x % 8)));
-                    alpha = (alpha == 0) ? 0xff : 0x00;
+                    if ((bmpImage.getRGB(x, y) & 0xff000000) != 0)
+                    {
+                        allAlphasZero = false;
+                        break;
+                    }
                 }
-                // FIXME: get the BMP decoder to support alpha, then uncomment below
-                //if (BitCount < 32 || allAlphasZero)
+            }
+        }
+        BufferedImage resultImage;
+        if (allAlphasZero)
+        {
+            resultImage = new BufferedImage(bmpImage.getWidth(), bmpImage.getHeight(),
+                    BufferedImage.TYPE_INT_ARGB);
+            for (int y = 0; y < resultImage.getHeight(); y++)
+            {
+                for (int x = 0; x < resultImage.getWidth(); x++)
+                {
+                    int alpha = 0xff;
+                    if (transparency_map != null)
+                    {
+                        int alpha_byte = 0xff & transparency_map[t_scanline_size
+                                * (bmpImage.getHeight() - y - 1) + (x / 8)];
+                        alpha = 0x01 & (alpha_byte >> (7 - (x % 8)));
+                        alpha = (alpha == 0) ? 0xff : 0x00;
+                    }
                     resultImage.setRGB(x, y, (alpha << 24) | (0xffffff & bmpImage.getRGB(x, y)));
+                }
             }
         }
+        else
+            resultImage = bmpImage;
         return new BitmapIconData(fIconInfo, header, resultImage);
     }
 

Modified: commons/proper/sanselan/trunk/src/test/java/org/apache/sanselan/formats/ico/IcoRoundtripTest.java
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/test/java/org/apache/sanselan/formats/ico/IcoRoundtripTest.java?rev=1138156&r1=1138155&r2=1138156&view=diff
==============================================================================
--- commons/proper/sanselan/trunk/src/test/java/org/apache/sanselan/formats/ico/IcoRoundtripTest.java (original)
+++ commons/proper/sanselan/trunk/src/test/java/org/apache/sanselan/formats/ico/IcoRoundtripTest.java Tue Jun 21 20:05:54 2011
@@ -509,23 +509,22 @@ public class IcoRoundtripTest extends Ic
         writeAndReadImageData("16x16x32-no-mask", baos.toByteArray(), foreground, background);
     }
 
-    // FIXME: get the BMP decoder to support alpha, then uncomment below
-//    public void testAlphaVersusANDMask() throws IOException, ImageWriteException, ImageReadException
-//    {
-//        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-//        BinaryOutputStream bos = new BinaryOutputStream(baos,
-//                BinaryOutputStream.BYTE_ORDER_LITTLE_ENDIAN);
-//        byte[] bitmap = new GeneratorFor32BitBitmaps().generate32bitRGBABitmap(
-//                0xFF000000, 0x00000000, 0, true);
-//        writeICONDIR(bos, 0, 1, 1);
-//        writeICONDIRENTRY(bos, 16, 16, 0, 0, 1, 32, 40 + bitmap.length);
-//        writeBITMAPINFOHEADER(bos, 16, 2*16, 1, 32, 0, 0, 0);
-//        bos.write(bitmap);
-//        bos.flush();
-//        // The AND mask is fully opaque, yet the fully transparent alpha should win:
-//        writeAndReadImageData("16x16x32-alpha-vs-mask", baos.toByteArray(),
-//                0xFF000000, 0x00000000);
-//    }
+    public void testAlphaVersusANDMask() throws IOException, ImageWriteException, ImageReadException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        BinaryOutputStream bos = new BinaryOutputStream(baos,
+                BinaryOutputStream.BYTE_ORDER_LITTLE_ENDIAN);
+        byte[] bitmap = new GeneratorFor32BitBitmaps().generate32bitRGBABitmap(
+                0xFF000000, 0x00000000, 0, true);
+        writeICONDIR(bos, 0, 1, 1);
+        writeICONDIRENTRY(bos, 16, 16, 0, 0, 1, 32, 40 + bitmap.length);
+        writeBITMAPINFOHEADER(bos, 16, 2*16, 1, 32, 0, 0, 0);
+        bos.write(bitmap);
+        bos.flush();
+        // The AND mask is fully opaque, yet the fully transparent alpha should win:
+        writeAndReadImageData("16x16x32-alpha-vs-mask", baos.toByteArray(),
+                0xFF000000, 0x00000000);
+    }
 
     public void testFullyTransparent32bitRGBA() throws IOException, ImageWriteException, ImageReadException
     {