[Mono-bugs] [Bug 679242] New: loading PNG looses data -- seems to be forcing premultiplied alpha

bugzilla_noreply at novell.com bugzilla_noreply at novell.com
Mon Mar 14 01:03:44 EDT 2011


https://bugzilla.novell.com/show_bug.cgi?id=679242

https://bugzilla.novell.com/show_bug.cgi?id=679242#c0


           Summary: loading PNG looses data -- seems to be forcing
                    premultiplied alpha
    Classification: Mono
           Product: Mono: Runtime
           Version: 2.8.x
          Platform: i686
        OS/Version: Mac OS X 10.6
            Status: NEW
          Severity: Critical
          Priority: P5 - None
         Component: misc
        AssignedTo: mono-bugs at lists.ximian.com
        ReportedBy: danny at sooloos.com
         QAContact: mono-bugs at lists.ximian.com
          Found By: ---
           Blocker: ---


User-Agent:       Mozilla/5.0 (Windows; Windows NT 6.1) AppleWebKit/534.23
(KHTML, like Gecko) Chrome/11.0.686.3 Safari/534.23

When I load a PNG file from disk, the R/G/B values in it come premultiplied
with the Alpha.

This is bad because it looses data (if alpha is 0, the r/g/b values are totally
lost forever), and it is also inconsistent with Microsoft's .NET, which
preserves the proper values from the PNG.

Reproducible: Always

Steps to Reproduce:
using System;
using System.Drawing;
using System.Drawing.Imaging;
namespace AlphaBlend
{
    class MainClass
    {
        static void Print(string pass, Bitmap bmp)
        {
            BitmapData data =
                bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
                             ImageLockMode.ReadOnly,
                             PixelFormat.Format32bppArgb);
            unsafe {
                int j = 0;
                while (j < bmp.Height) {
                    byte *inb = (byte*)data.Scan0.ToPointer() + data.Stride*j;
                    int i = 0;
                    Console.Write(pass + ": |");
                    while (i < bmp.Width) {
                        Console.Write("{0:X2},{1:X2},{2:X2},{3:X2}|",
                                      *inb, *(inb+1), *(inb+2), *(inb+3));
                        inb += 4;
                        i++;
                    }
                    Console.WriteLine();
                    j++;
                }
            }
            bmp.UnlockBits(data);
        }
        public static void Main(string[] args)
        {
            using (Bitmap bmp = new Bitmap(4, 4, PixelFormat.Format32bppArgb))
{
                using (Graphics g = Graphics.FromImage(bmp)) {
                    for (int y = 0; y < bmp.Height; ++y)
                        for (int x = 0; x < bmp.Width; ++x)
                            bmp.SetPixel(x, y,
                                         Color.FromArgb(0x80,0xff,0xff,0xff));
                }
                Print("       half alpha white", bmp);
                bmp.Save("tmp.png");
            }
            Console.WriteLine();
            using (Bitmap bmp = (Bitmap)Image.FromFile("tmp.png")) {
                Print("loaded half alpha white", bmp);
            }

            Console.WriteLine(); Console.WriteLine();

            using (Bitmap bmp = new Bitmap(4, 4, PixelFormat.Format32bppArgb))
{
                using (Graphics g = Graphics.FromImage(bmp)) {
                    for (int y = 0; y < bmp.Height; ++y)
                        for (int x = 0; x < bmp.Width; ++x)
                            bmp.SetPixel(x, y,
                                         Color.FromArgb(0x0,0xff,0xff,0xff));
                }
                Print("         no alpha white", bmp);
                bmp.Save("tmp.png");
            }
            Console.WriteLine();
            using (Bitmap bmp = (Bitmap)Image.FromFile("tmp.png")) {
                Print("  loaded no alpha white", bmp);
            }
         }
     }
}


Actual Results:  
       half alpha white: |FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|
       half alpha white: |FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|
       half alpha white: |FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|
       half alpha white: |FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|

loaded half alpha white: |80,80,80,80|80,80,80,80|80,80,80,80|80,80,80,80|
loaded half alpha white: |80,80,80,80|80,80,80,80|80,80,80,80|80,80,80,80|
loaded half alpha white: |80,80,80,80|80,80,80,80|80,80,80,80|80,80,80,80|
loaded half alpha white: |80,80,80,80|80,80,80,80|80,80,80,80|80,80,80,80|


         no alpha white: |FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|
         no alpha white: |FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|
         no alpha white: |FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|
         no alpha white: |FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|

  loaded no alpha white: |00,00,00,00|00,00,00,00|00,00,00,00|00,00,00,00|
  loaded no alpha white: |00,00,00,00|00,00,00,00|00,00,00,00|00,00,00,00|
  loaded no alpha white: |00,00,00,00|00,00,00,00|00,00,00,00|00,00,00,00|
  loaded no alpha white: |00,00,00,00|00,00,00,00|00,00,00,00|00,00,00,00|


Expected Results:  
       half alpha white: |FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|
       half alpha white: |FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|
       half alpha white: |FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|
       half alpha white: |FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|

loaded half alpha white: |FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|
loaded half alpha white: |FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|
loaded half alpha white: |FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|
loaded half alpha white: |FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|FF,FF,FF,80|


         no alpha white: |FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|
         no alpha white: |FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|
         no alpha white: |FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|
         no alpha white: |FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|

  loaded no alpha white: |FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|
  loaded no alpha white: |FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|
  loaded no alpha white: |FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|
  loaded no alpha white: |FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|FF,FF,FF,00|

The expected results came from a windows 7 .net 4 machine compiled with csc.
The bad results came from an OS X 10.6.6 machine running Mono 2.8.2 and
compiled with dmcs. gmcs and mcs product the same incorrect result.

This problem is exceptionally annoying when trying to load OpenGl textures
using Mono, and other people on the internet are having similar issues. Some
have suggested a workaround of un-premultiplying the values by dividing the
r/g/b by the alpha/255, but not only is this a terrible fix for quality sake,
but it doesn't work at all when the alpha value is 0.

I was unsure how to mark the severity of the bug, but given that 'Critical'
includes the descriptive text of 'causes you to lose data', I chose that.

-- 
Configure bugmail: https://bugzilla.novell.com/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the QA contact for the bug.
You are the assignee for the bug.


More information about the mono-bugs mailing list