Image.FromFile get´s wrong dimensions from phone pictures! 2nd!

Marcus Reinicke 0 Reputation points
2023-03-17T06:52:38.9833333+00:00

HI @ all!

This question is the same one that Klockner Thomas had asked in 2017.
Stanly Fan had given an answer that was rather unhelpful in my eyes.

Link to thread:

https://social.msdn.microsoft.com/Forums/vstudio/en-US/7c1b8aa5-b915-4edf-9a1d-ddd60edb57b5/imagefromfile-gets-wrong-dimensions-from-phone-pictures?forum=winforms

I have the same problem.

When I take a picture with the camera of my Galaxy S22 Ultra in full screen, transfer it to the Windows PC, this picture has the following details in Windows Explorer:

PictureDetailsExplorer

When I load the image in C# using the Image.LoadfromFile function, or in the constructor of Bitmap, the height and width values are read in reversed:

LoadFromFile

Bitmap_Constructor

Due to this issue, I have no way of knowing that this image is in Portrait orientation.

The Exif properties with the value 0x0112 doesn't help me here either, because this only stands for the orientation of the image, but it doesn't define if it was taken as landscape or as portrait.

This is not a bug of the S22, but happens with almost all phones.

Does anyone have any idea how to fix this problem?

Is there any other way to find out if a photo was taken in landscape or portrait orientation?

Thanks in advance for your effort and help.

Best Regards
Marcus

Developer technologies | C#
{count} votes

1 answer

Sort by: Most helpful
  1. Castorix31 90,686 Reputation points
    2023-03-19T01:40:03.4433333+00:00

    If Explorer displays the right dimensions, maybe you can try to read them with IPropertyStore

    A test (change sFileName... ) :

                string sFileName = @"E:\Image_rotated.jpg";
                IPropertyStore pPropertyStore = null;
                Guid PropertyStoreGuid = typeof(IPropertyStore).GUID;
                HRESULT hr = SHGetPropertyStoreFromParsingName(sFileName, IntPtr.Zero, GETPROPERTYSTOREFLAGS.GPS_READWRITE, ref PropertyStoreGuid, out pPropertyStore);
                if (hr == HRESULT.S_OK)
                {
                    var pv = new PROPVARIANT();
                    hr = pPropertyStore.GetValue(PKEY_Image_Dimensions, out pv);
                    string sDimensions = Marshal.PtrToStringUni(pv.pwszVal);
                    hr = pPropertyStore.GetValue(PKEY_Image_HorizontalSize, out pv);
                    int nWidth = pv.uiVal;
                    hr = pPropertyStore.GetValue(PKEY_Image_VerticalSize, out pv);
                    int nHeight = pv.uiVal;
                    Console.WriteLine("Dimensions : {0}", sDimensions);
                    Console.WriteLine("Width : {0}", nWidth.ToString());
                    Console.WriteLine("Height : {0}", nHeight.ToString());
                    Marshal.ReleaseComObject(pPropertyStore);
                }
    
    

    with declarations :

           public enum HRESULT : int
            {
                S_OK = 0,
                S_FALSE = 1,
                E_NOINTERFACE = unchecked((int)0x80004002),
                E_NOTIMPL = unchecked((int)0x80004001),
                E_FAIL = unchecked((int)0x80004005),
                E_UNEXPECTED = unchecked((int)0x8000FFFFL)
            }
    
            [DllImport("Shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern HRESULT SHGetPropertyStoreFromParsingName(string pszPath, IntPtr pbc, GETPROPERTYSTOREFLAGS flags, ref Guid iid, [MarshalAs(UnmanagedType.Interface)] out IPropertyStore propertyStore);
    
            public enum GETPROPERTYSTOREFLAGS
            {
                GPS_DEFAULT = 0,
                GPS_HANDLERPROPERTIESONLY = 0x1,
                GPS_READWRITE = 0x2,
                GPS_TEMPORARY = 0x4,
                GPS_FASTPROPERTIESONLY = 0x8,
                GPS_OPENSLOWITEM = 0x10,
                GPS_DELAYCREATION = 0x20,
                GPS_BESTEFFORT = 0x40,
                GPS_NO_OPLOCK = 0x80,
                GPS_PREFERQUERYPROPERTIES = 0x100,
                GPS_EXTRINSICPROPERTIES = 0x200,
                GPS_EXTRINSICPROPERTIESONLY = 0x400,
                GPS_VOLATILEPROPERTIES = 0x800,
                GPS_VOLATILEPROPERTIESONLY = 0x1000,
                GPS_MASK_VALID = 0x1FFF
            }
    
            [ComImport, Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
            public interface IPropertyStore
            {
                HRESULT GetCount([Out] out uint propertyCount);
                HRESULT GetAt([In] uint propertyIndex, [Out, MarshalAs(UnmanagedType.Struct)] out PROPERTYKEY key);
                HRESULT GetValue([In, MarshalAs(UnmanagedType.Struct)] ref PROPERTYKEY key, [Out, MarshalAs(UnmanagedType.Struct)] out PROPVARIANT pv);
                HRESULT SetValue([In, MarshalAs(UnmanagedType.Struct)] ref PROPERTYKEY key, [In, MarshalAs(UnmanagedType.Struct)] ref PROPVARIANT pv);
                HRESULT Commit();
            }
    
            [StructLayout(LayoutKind.Sequential, Pack = 4)]
            public struct PROPERTYKEY
            {
                private readonly Guid _fmtid;
                private readonly uint _pid;
    
                public PROPERTYKEY(Guid fmtid, uint pid)
                {
                    _fmtid = fmtid;
                    _pid = pid;
                }  
            }
    
            public static readonly PROPERTYKEY PKEY_Title = new PROPERTYKEY(new Guid("F29F85E0-4FF9-1068-AB91-08002B27B3D9"), 2);
            public static readonly PROPERTYKEY PKEY_Keywords = new PROPERTYKEY(new Guid("F29F85E0-4FF9-1068-AB91-08002B27B3D9"), 5);
            public static readonly PROPERTYKEY PKEY_Image_HorizontalSize = new PROPERTYKEY(new Guid("6444048F-4C8B-11D1-8B70-080036B11A03"), 3);
            public static readonly PROPERTYKEY PKEY_Image_VerticalSize = new PROPERTYKEY(new Guid("6444048F-4C8B-11D1-8B70-080036B11A03"), 4);
            public static readonly PROPERTYKEY PKEY_Image_Dimensions = new PROPERTYKEY(new Guid("6444048F-4C8B-11D1-8B70-080036B11A03"), 13);
    
            [StructLayout(LayoutKind.Sequential, Pack = 0)]
            public struct PROPARRAY
            {
                public UInt32 cElems;
                public IntPtr pElems;
            }
    
            [StructLayout(LayoutKind.Explicit, Pack = 1)]
            public struct PROPVARIANT
            {
                [FieldOffset(0)]
                public ushort varType;
                [FieldOffset(2)]
                public ushort wReserved1;
                [FieldOffset(4)]
                public ushort wReserved2;
                [FieldOffset(6)]
                public ushort wReserved3;
    
                [FieldOffset(8)]
                public byte bVal;
                [FieldOffset(8)]
                public sbyte cVal;
                [FieldOffset(8)]
                public ushort uiVal;
                [FieldOffset(8)]
                public short iVal;
                [FieldOffset(8)]
                public UInt32 uintVal;
                [FieldOffset(8)]
                public Int32 intVal;
                [FieldOffset(8)]
                public UInt64 ulVal;
                [FieldOffset(8)]
                public Int64 lVal;
                [FieldOffset(8)]
                public float fltVal;
                [FieldOffset(8)]
                public double dblVal;
                [FieldOffset(8)]
                public short boolVal;
                [FieldOffset(8)]
                public IntPtr pclsidVal; // GUID ID pointer
                [FieldOffset(8)]
                public IntPtr pszVal; // Ansi string pointer
                [FieldOffset(8)]
                public IntPtr pwszVal; // Unicode string pointer
                [FieldOffset(8)]
                public IntPtr punkVal; // punkVal (interface pointer)
                [FieldOffset(8)]
                public PROPARRAY ca;
                [FieldOffset(8)]
                public System.Runtime.InteropServices.ComTypes.FILETIME filetime;
            }
    
            public enum VARENUM
            {
                VT_EMPTY = 0,
                VT_NULL = 1,
                VT_I2 = 2,
                VT_I4 = 3,
                VT_R4 = 4,
                VT_R8 = 5,
                VT_CY = 6,
                VT_DATE = 7,
                VT_BSTR = 8,
                VT_DISPATCH = 9,
                VT_ERROR = 10,
                VT_BOOL = 11,
                VT_VARIANT = 12,
                VT_UNKNOWN = 13,
                VT_DECIMAL = 14,
                VT_I1 = 16,
                VT_UI1 = 17,
                VT_UI2 = 18,
                VT_UI4 = 19,
                VT_I8 = 20,
                VT_UI8 = 21,
                VT_INT = 22,
                VT_UINT = 23,
                VT_VOID = 24,
                VT_HRESULT = 25,
                VT_PTR = 26,
                VT_SAFEARRAY = 27,
                VT_CARRAY = 28,
                VT_USERDEFINED = 29,
                VT_LPSTR = 30,
                VT_LPWSTR = 31,
                VT_RECORD = 36,
                VT_INT_PTR = 37,
                VT_UINT_PTR = 38,
                VT_FILETIME = 64,
                VT_BLOB = 65,
                VT_STREAM = 66,
                VT_STORAGE = 67,
                VT_STREAMED_OBJECT = 68,
                VT_STORED_OBJECT = 69,
                VT_BLOB_OBJECT = 70,
                VT_CF = 71,
                VT_CLSID = 72,
                VT_VERSIONED_STREAM = 73,
                VT_BSTR_BLOB = 0xfff,
                VT_VECTOR = 0x1000,
                VT_ARRAY = 0x2000,
                VT_BYREF = 0x4000,
                VT_RESERVED = 0x8000,
                VT_ILLEGAL = 0xffff,
                VT_ILLEGALMASKED = 0xfff,
                VT_TYPEMASK = 0xfff
            };
    
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.