none
Image has wrong Image.PixelFormat on Windows 7, not on XP

    Question

  • Loading an image using System.Drawing.Image.FromFile and then examining the pixelformat - on Windows XP x64 (or x86) the format is a valid value such as PixelFormat24bppRGB but on Windows 7 (x64 or x86) the value returned is 8207, which is not a member of the PixelFormat enumeration.

    This problem occurs using .NET framework 3.5 and 4.0

    The code used is:

    using System;
    using System.Drawing;

    public class itype {

        public static void Main( string[] args ) {

            Image image = Image.FromFile( args[0] );

            Console.WriteLine( "pixelformat of " + args[0] +
                           " = " + image.PixelFormat );
        }
    }

    An image which shows this problem can be downloaded from http://www.xmlpdf.com/images/test.jpg

     

    lundi 3 mai 2010 00:26

Toutes les réponses

  • We are also having the same problem. It was working on Windows Server 2008 but on Windows Server 2008 R2, the PixelFormat enum value changed to 8207 from Format24bppRgb. And when we do Graphics.FromImage(bitmap) for this PixelFormat ( ie., 8207) we get "Out of Memory" Exception. 

     Thanks and Regards,

    Diwakar

    mercredi 5 mai 2010 19:12
  • As everyone who posts to these forums has a Windows Live Id, posting to Skydrive will make your image available to all potential responders.  It's very frustrating when you post inaccessible links.  Where did the image come from?  The JPEG format is well defined, but some vendors modify it for their own purposes.
    mercredi 5 mai 2010 21:31
  • In what way is a simple url like http://www.xmlpdf.com/images/test.jpg inaccessible ?  Please explain that.

    The problem is not with that specific image, I have several images from different sources which exhibit the problem and the other poster above also has the problem.  These images work on XP and not on Windows 7 so even if it is a problem with the image, the issue I have is that the .NET framework functions differently on different operating systems.

     

     

    mercredi 5 mai 2010 22:08
  • In what way is a simple url like http://www.xmlpdf.com/images/test.jpg inaccessible ?  Please explain that.

    When you can access it and others cannot.

    The change from WF to WPF is a major change, particularly in the handling of images.  The bitness of the OS also affects many aspects of the way things work.

    mercredi 5 mai 2010 22:25
  • The problem exists regardless of the bits of the operating system, it works on XP 32 and 64 bit and fails on Windows 7 32 and 64 bit.

    I'm not sure of the relevance of your comment about WF and WPF, there is no reference to either in the example program which shows the problem, can you expand on that thanks.

    mercredi 5 mai 2010 22:36
  • Windows 7 uses accelerated graphics (WPF).  It doesn't deal well with GDI graphics (WF).  If your image was saved by a Microsoft program, it should open in all versions of Windows from the version it was saved on.  If it was saved by a not-Microsoft program, it may not open in all or any version(s) of Windows.
    mercredi 5 mai 2010 22:47
  • Hi JohnWein,

       I had shared a console applciation(.NET) at http://cid-a669f35f6388dbce.skydrive.live.com/browse.aspx/.Public And the image is also uploaded that is used in the application. The application works on one machine(Windows Server 2008) and it doesnt work on other (Windows Server 2008 R2). I had also shared the screenshots of both machine configurations. Please let me know what more information do you need to get the problem reproduced at your end.

    Also, I do not know where the image came from. It was given to us by our design team. I am using 64-bit versions of the OS but the problem is reported on both 32-bit and 64-bit OS.

    Thank and Regards,

    Diwakar

    jeudi 6 mai 2010 15:53
  • Will it load on both systems if you remove PropertyItem 0? 

    New Bitmap() --> Bitmap.RemovePropertyItem(() --> Bitmap.Save --> New Bitmap()

    jeudi 6 mai 2010 21:58
  • Removing the first property item does not fix the problem.
    vendredi 7 mai 2010 01:06
  • The problem is that there are some values missing from the Image.PixelFormat enumeration.  8207 is pixel format PixelFormat32bppCMYK (based on GdiPlusHeaders.h).  For some reason this value is not part of the PixelFormat enumeration.

    When the problem image is loaded on Windows XP, the .NET framework converts it from CMYK to RGB and thus it matches a value in the enumeration such as PixelFormat32bppRGB but when the image is loaded on Windows 7 it is not converted to RGB, but remains in CMYK format.

     

    So the solution is for the application to explicitly test for the 8207 value and treat the image as having PixelFormat32bppCMYK.

    vendredi 7 mai 2010 01:35
  • Hi John,

     

    Just as you said, some formats are supported in native GDI+, but not in the GDI+ library in windows forms. Based on my understanding, the only way to solve this issue is to check the format of the image after it is loaded. If its format is not supported in windows forms, call the Clone method to convert it to a common format which exists in windows forms. I created a managed C++ project to write a wrapper class. The wrapper class has a method called LoadImage to load an image, whose format must exist in windows forms. The code snippets below shows the details:

    The native GDIHelper class:
    .h
    #pragma once

     

    #include "Stdafx.h"

    #include <GdiPlus.h>

     

    class GDIHelper

    {

    public:

        static Gdiplus::Bitmap *ConvertImage(Gdiplus::Bitmap *srcImage, Gdiplus::PixelFormat destFormat);

    };

             .cpp

             #include "StdAfx.h"

    #include "GDIHelper.h"

    using namespace Gdiplus;

     

    Bitmap *GDIHelper::ConvertImage(Bitmap  *srcImage, PixelFormat destFormat)

    {

        if(srcImage == NULL) return NULL;

     

        //Create the new image

        UINT width = srcImage->GetWidth();

        UINT height = srcImage->GetHeight();

        Bitmap *destImage = new Bitmap(width,height,destFormat);

     

        return srcImage->Clone(0,0,width,height,destFormat);

    }

     

        The managed ImageHelper class:
        .h
            
    // MyManagedLib.h

     

    #pragma once

     

    using namespace System;

    using namespace System::Drawing;

    using namespace System::Runtime::InteropServices;

    using namespace System::Drawing::Imaging;

     

    namespace MyManagedLib {

     

        public ref class ImageHelper

        {

            // TODO: Add your methods for this class here.

        public:

     

            static Image^ LoadImage(String^ picFile);

        };

    }

        .cpp

        #include "stdafx.h"

    #include "ImageHelper.h"

    #include "GDIHelper.h"

     

    Image^ MyManagedLib::ImageHelper::LoadImage(String^ picFile)

    {

        //Get the file path string.

        TCHAR* imgFile = NULL;

        IntPtr ptr = Marshal::StringToHGlobalUni(picFile);

        if(ptr != IntPtr::Zero)

        {

            imgFile = reinterpret_cast<TCHAR*>(static_cast<void*>(ptr));

        }

        else

            return nullptr;

     

        //Load the native bitmap.

        Gdiplus::Bitmap* srcImage = new Gdiplus::Bitmap(imgFile);

     

        //Check if the format exists in windows forms.

        array<int>^ formats = safe_cast<array<int>^>(Enum::GetValues(PixelFormat::typeid));

        BOOL formatExists = FALSE;

        for(int i = 0; i < formats->Length; i++)

        {

            UINT format = formats[i];

            if(format == srcImage->GetPixelFormat())

            {

                formatExists = TRUE;

                break;

            }

        }

     

        //if the format does not exist in windows forms, convert it.

        if(formatExists == FALSE)

            srcImage = GDIHelper::ConvertImage(srcImage,PixelFormat24bppRGB);

     

        //Convert the native bitmap to a managed bitmap.

        int width = srcImage->GetWidth();

        int height = srcImage->GetHeight();

        PixelFormat format = safe_cast<PixelFormat>(srcImage->GetPixelFormat());

     

        Gdiplus::BitmapData* bitmapData = new Gdiplus::BitmapData();

        Gdiplus::Rect rect( 0, 0, width, height );

        srcImage->LockBits( &rect, Gdiplus::ImageLockModeRead, srcImage->GetPixelFormat(), bitmapData );

     

        Bitmap^ managedImage = gcnew Bitmap(width,height,format);

        System::Drawing::Rectangle rectangle( 0, 0, width, height);

        BitmapData^ managedData = managedImage->LockBits( rectangle, ImageLockMode::WriteOnly, PixelFormat::Format24bppRgb);

        memcpy(safe_cast<void*>(managedData->Scan0),bitmapData->Scan0, width * height );

     

        srcImage->UnlockBits(bitmapData);

        managedImage->UnlockBits(managedData);

        Marshal::FreeHGlobal(ptr);

        delete bitmapData; delete srcImage;

     

        return managedImage;

    }

     

        Comment: To use the class, you can add a reference to the generated managed C++ dll. Please change the target platform of the calling project(such as a C# WinForm project) to x86 .

     

     

    Let me know if this does not help.
    Aland Li


    Please mark the replies as answers if they help and unmark if they don't. This can be beneficial to other community members reading the thread.
    lundi 10 mai 2010 03:18
    Modérateur
  • I had no problem loading the image "PO_EDU_004_CMYK.jpg" on any system from W2K through Server2008R2.  This is not the same image referenced in the accompanying program.  The program also reads from the root of the C drive.  Do you have a permissions problem?
    lundi 10 mai 2010 07:18
  • Hi JohnWein: Actually I also did not meet any problems when loading that image. My solution is just based on OP's analysis.

    Hi John: Could you please provide more information so that we can reproduce the issue?

    Regards,
    Aland Li


    Please mark the replies as answers if they help and unmark if they don't. This can be beneficial to other community members reading the thread.
    lundi 10 mai 2010 16:00
    Modérateur
  • Hi JohnWein and Aland,

    The problem is not about loading the image from the disk. The problem is that the PixelFormat enum value changes if we load the image on Win2008R2 and W7. Also, the console application runs and creates a new bitmap on Win2003 and WIn2008 but on Win2008R2 and W7 it throws out of memory exception in function Graphics.FromImage. The console application creates a low resolution image of an existing image.

    Sorry for the image name confusion, the problem occurs with the image attached as well (ie., PO_EDU_004_CMYK.jpg).

    Thanks in advance,

    Diwakar

    lundi 10 mai 2010 16:32
  • Hi JohnWein and Aland,

    The problem is not reading the image from the disk. The problem is that the pixel format enum value changes if we are on Win2008R2 and W7. Also, the console application runs and creates a new bitmap on Win2003 and WIn2008 but on Win2008R2 and W7 it throws out of memory exception.

    Sorry for the image name confusion, it happens with the image attached as well (ie., PO_EDU_004_CMYK.jpg).


    I get the same PixelFormat on all OS's.  I ran your code and saved the resulting images.  No errors.  W7 GDI has had some problems.  Are your systems up to date?

    Your image is a little flaky.  Version 1.01, 0 dpi, 0 property item, but it doesn't seem to cause any problems.  Are you sure the image you posted is not an altered copy of the image which causes problems?

    lundi 10 mai 2010 16:57
  • As bizzare it may sound, skydrive has altered my image. If I upload the image and download it, that image works fine. I had added a zip file that contains the image. Could you please try with that image and let me know your results? I had downloaded the zip file myself and found that the problem can be reproduced.

    Edited: This might help. I had a discussion with our designer and they say that the images are coming directly from photographer and has an embedded color profile in them. Also, these images look fine in an image editor but do not show up on the browser. That is why the image shared by John is not shown in the browser but it is downloadable(you wont get a 404) using a download manager and can be opened in a image editor. Skydrive knows how to deal with these images.

    Thanks in advance,
    Diwakar

    lundi 10 mai 2010 17:27
  • The only difference now, is that the image is reported as PixelFormat 8207 on Server2008R2.  No problem loading or drawing.  Of course the image file is significantly different.
    lundi 10 mai 2010 19:16
  • Right, the pixelformat of the image changed. And, if we run my console application, the console application fails with OutOfMemoryException. Loading and drawing of that image is not a problem but in the console application I resize the image to create another bitmap image and it fails. And it fails because the pixelFormat changed. Ideally, the pixelformat shouldnt change based on OS.

    Also, the console application runs and creates a new bitmap on Win2003 and WIn2008 but on Win2008R2 and W7 it throws out of memory exception in function Graphics.FromImage.

    Thanks and Regards,

    Diwakar

    lundi 10 mai 2010 19:26
  • Your code that checked for an indexed image didn''t make sense to me since you can only get a graphics from a non-indexed image, so I replace it with:

            private static Bitmap DownsampleImage(Bitmap srcImg, int destW, int destH, float dstDPI)
            {
                
    Bitmap bmPhoto = new Bitmap(destW, destH,PixelFormat.Format32bppRgb);
                bmPhoto.SetResolution(dstDPI, dstDPI);
                
    Graphics grPhoto = Graphics.FromImage(bmPhoto);
                grPhoto.InterpolationMode = 
    InterpolationMode.HighQualityBicubic;
                grPhoto.DrawImage(srcImg,
                                  
    new System.Drawing.Rectangle(0, 0, bmPhoto.Width, bmPhoto.Height),
                                  
    new System.Drawing.Rectangle(0, 0, srcImg.Width, srcImg.Height),
                                  
    GraphicsUnit.Pixel);
                grPhoto.Dispose();
                
    return bmPhoto;
            }

    lundi 10 mai 2010 19:57
  • I want the image to be down sampled in the same format as that of the original image and not in PixelFormat.Format32bppRgb. For indexed images only I want the images to be down sampled to PixelFormat.Format32bppRgb. If we want to get rid of the indexed images logic, here is how I want the code should look like and this does not work.

            private static Bitmap DownsampleImage(Bitmap srcImg, int destW, int destH, float dstDPI)
            {
                
    Bitmap bmPhoto = new Bitmap(destW, destH, srcImg.PixelFormat);
                bmPhoto.SetResolution(dstDPI, dstDPI);
                
    Graphics grPhoto = Graphics.FromImage(bmPhoto);
                grPhoto.InterpolationMode = 
    InterpolationMode.HighQualityBicubic;
                grPhoto.DrawImage(srcImg,
                                  
    new System.Drawing.Rectangle(0, 0, bmPhoto.Width, bmPhoto.Height),
                                  
    new System.Drawing.Rectangle(0, 0, srcImg.Width, srcImg.Height),
                                  
    GraphicsUnit.Pixel);
                grPhoto.Dispose();
                
    return bmPhoto;
            }

    Thanks and Regards,

    Diwakar

    lundi 10 mai 2010 21:20
  • No.  You can't get a Graphics from an indexed image.  It has nothing to do with the OS.  In WF, you have to convert to non-indexed and then back.  Consider moving to WPF where it's trivial.
    lundi 10 mai 2010 21:57
  • JohnWein, indexed images will be side tracking the conversation. The image I attached is not an indexed image. My last post has code that I would want to look like and it was working before and is not working in Win2008R2. We can safely remove the indexed images logic and I want the downsampled images (assuming that the input image will always be an non-indexed image into my program) to be with the same pixelformat as the original.

    Thanks in advance,

    Diwakar

    lundi 10 mai 2010 22:04
  • JohnWein, indexed images will be side tracking the conversation. The image I attached is not an indexed image. My last post has code that I would want to look like and it was working before and is not working in Win2008R2. We can safely remove the indexed images logic and I want the downsampled images (assuming that the input will always be an non-indexed image) to be with the same pixelformat as the original.

    Thanks in advance,

    Diwakar

    Your code wasn't working.  It hid the format.  Your code could not have worked on any OS for indexed images.  You can't get a Graphics from an indexed image.  Move to WPF if you must handle Photoshop images or use the Adobe SDK. 

    lundi 10 mai 2010 22:14
  • I found out the issue:

    The enum PixelFormat32bppCMYK (8207) is defined in GdiPlusPixelFormats.h as…

     

    #define    PixelFormat32bppCMYK       (15 | (32 << 8))

     

    This is a new format that was added for GDI+ 1.1.  There is no wrapper for it in System.Drawing.  Now, I do not know why this was working in earlier versions of windows and not working in Win7 and W2008 R2. I am looking for a workaround on how to get it working in WIN2008R2.

     

    mercredi 19 mai 2010 18:46
  • It worked on the earlier versions because you didn't try to get a graphics from an indexed bitmap.  Your problem isn't with this image. Try this code:

    using System;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Drawing.Imaging;
    namespace ConsoleApplication1
    {
        
    class Program
        {
            
    static void Main(string[] args)
            {
                
    int dpi = 72;
                
    string path = "PO_EDU_004_CMYK.jpg";
                
    using (Bitmap sourceBitmap = new Bitmap(path))
                {
                    
    float destWidth = sourceBitmap.Width / sourceBitmap.HorizontalResolution * dpi;

                    
    float conversionFactor = (float)destWidth / (float)sourceBitmap.Width;

                    
    int width = Convert.ToInt32(sourceBitmap.Width * conversionFactor);
                    
    int height = Convert.ToInt32(sourceBitmap.Height * conversionFactor);
                    
    Bitmap dstImage = DownsampleImage(sourceBitmap, width, height, dpi);
                    dstImage.Save(
    "Downsampled_" + path, ImageFormat.Jpeg);
                }
            }

            
    private static Bitmap DownsampleImage(Bitmap srcImg, int destW, int destH,
        
    float dstDPI)
            {
                
    Bitmap bmPhoto = new Bitmap(destW, destH,PixelFormat.Format32bppRgb);
                bmPhoto.SetResolution(dstDPI, dstDPI);
                
    Graphics grPhoto = Graphics.FromImage(bmPhoto);
                grPhoto.InterpolationMode = 
    InterpolationMode.HighQualityBicubic;
                grPhoto.DrawImage(srcImg,
                                  
    new System.Drawing.Rectangle(0, 0, bmPhoto.Width, bmPhoto.Height),
                                  
    new System.Drawing.Rectangle(0, 0, srcImg.Width, srcImg.Height),
                                  
    GraphicsUnit.Pixel);
                grPhoto.Dispose();
                
    return bmPhoto;
            }
        }
    }

    mercredi 19 mai 2010 21:21
  • Hi,

    I am writing to check the status of the issue on your side. Could you please let me know if the suggestion works for you? If you have any questions or concerns, please feel free to let me know. I will be more than happy to be of assistance.

     

    Regards,
    Aland Li


    Please mark the replies as answers if they help and unmark if they don't. This can be beneficial to other community members reading the thread.
    mercredi 26 mai 2010 02:10
    Modérateur
  • Hi, i have a similar problem.

    I want to detect CMYK images because they cannot be displayed in Internet Explorer.

    They way i try to detect this, is by checking the System.Drawing.Image.Flags, like so:

    bool isRGB = ((((ImageFlags)img.Flags) & ImageFlags.ColorSpaceRgb) == ImageFlags.ColorSpaceRgb);
    bool isYCCK = ((((ImageFlags)img.Flags) & ImageFlags.ColorSpaceYcck) == ImageFlags.ColorSpaceYcck);
    bool isYCBCR = ((((ImageFlags)img.Flags) & ImageFlags.ColorSpaceYcbcr) == ImageFlags.ColorSpaceYcbcr);
    bool isCMYK = ((((ImageFlags)img.Flags) & ImageFlags.ColorSpaceCmyk) == ImageFlags.ColorSpaceCmyk);
    

    If i understand it correctly, this should be the way to do this.

    However, this works perfect on Vista, but it doens't work on Windows7.

    The problem is that img.Flags returns a different value in Vista and Windows7 !!

    Any idea why this is returning a different value ? Or how to detect CMYK in Windows7 ?

    Thanks in advance!

    mercredi 4 août 2010 07:50
  • A lot of image code changed between Vista and Win7.  Vista and earlier used GDI+.  Win7 uses accelerated graphics (WPF).  Use WPF to determine the image type on all OS's.  CMYK32 is a valid PixelFormat.
    mercredi 4 août 2010 08:14
  • I already tried to use WPF, like this :

    System.Windows.Media.Imaging.BitmapImage bitmap = new System.Windows.Media.Imaging.BitmapImage(new Uri(file.FullName));
    bool isCMYK = (bitmap.Format == System.Windows.Media.PixelFormats.Cmyk32);

    This returns the same on all OS's.

    However, it doesn't detect CMYK images correctly !

    For CMYK images, the format is also "Bgr32" !!!

    Am i doing something wrong ?

     

    mercredi 4 août 2010 09:03
  • I already tried to use WPF, like this :

    System.Windows.Media.Imaging.BitmapImage bitmap = new System.Windows.Media.Imaging.BitmapImage(new Uri(file.FullName));
    
    bool isCMYK = (bitmap.Format == System.Windows.Media.PixelFormats.Cmyk32);
    
    

    This returns the same on all OS's.

    However, it doesn't detect CMYK images correctly !

    For CMYK images, the format is also "Bgr32" !!!

    Am i doing something wrong ?

     


    I'd trust the Windows software.  Convert your Bgr32 image to CMYK32 (use FormatConvertedBitmap) and try again.
    mercredi 4 août 2010 09:12
  • I'm pretty sure it is already a CMYK image because:

    1) It doesn't display in Internet Explorer;

    2) In Vista, System.Windows.Drawing.Image detects it as CMYK;

    3) In Photoshop CS3, it says it's CMYK/8.

     

    Here is the image: http://static.rad.be/cmykimage.jpg

    (The image will not display in IE, so don't think the link is broken, just right click, save as...)

     

    It's not that i don't want to trust the windows software, but the windows software is the only one claiming it to be RGB, so that makes it suspicious :)

     

    Maybe there is something wrong with my image ?

    If someone has a CMYK image that gets detected correctly by WPF, please share it !

    mercredi 4 août 2010 09:47
  • If someone has a CMYK image that gets detected correctly by WPF, please share it !
    The CMYK32 image you made in WPF wasn't detected by WPF???
    mercredi 4 août 2010 10:02
  • i didn't make one .... i made the image in PhotoShop because that is where the images i need to test come from.
    mercredi 4 août 2010 10:08
  • You'll probably need a 3rd party library.  PhotoShop uses many proprietary formats.  An example is their CMYK in a pseudo JPEG container.
    mercredi 4 août 2010 10:21
  • That would suck...

    Anyway ... i solved it by making a webservice on a non-win7 machine. Programs (on vista and win7) call the webservice to get the correct answer.

    To be honest i still think this is a "bug". If GDI can detect it, why not WPF ...

    I still hope someone can point me in the right direction.

    mercredi 4 août 2010 12:22
  • You should file a bug report at Microsoft.Connect.
    mercredi 4 août 2010 13:22
  • Hi,

    You could submit a feedback from:
    https://connect.microsoft.com/VisualStudio

    Regards,
    Aland Li

    MSDN Subscriber Support in Forum
    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please mark the replies as answers if they help and unmark if they don't. This can be beneficial to other community members reading the thread.
    jeudi 5 août 2010 14:11
    Modérateur
  • Hi

     

    I've similar problem, I have to detect color space and dpi, so i used for this TiffDecoder and JPEGDecoder (Windows forms, System.Windows.Media.Imaging)

     

    Testing File -> CMYK / 300DPI  (file is correct )

    WINDOWS XP, VISTA (testing on all version of .net framework, and about ten different files made in photoshop or corel, all CMYK, dpi from 300 to 600) -> offen show RGB (bgr32), sometimes wrong determine DPI but correct show color space

    WINDOWS 7 -> it's all ok

     

    Earlier i try used http://bitmiracle.com/libtiff/ to read tiff but it's crash on files from corel.

    Any suggestion ?

     

    cheers,

    jeudi 7 octobre 2010 05:45
  • Which version of C++ does this code apply? Do you have a compiled dll that you can share with us?
    mardi 27 mars 2012 18:28