Menu

#294 JPEG-XR on Linux

None
pending
5
2021-04-04
2019-05-15
Grant Boyle
No

I've been trying to get FreeImage working with JPEG-XR images on Linux (Ubuntu 18.10, debian buster). I ran into an issue where the process would be unable to open such images.

I've been looking into the cause and this is what I think is happening:

  • JPEG-XR uses GUIDs to specify the pixel types of the image
  • LibJXR defines a GUID structure to hold such GUIDs
  • the definition depends on _WINDOWS_ to select between long and int members
  • FreeImage.h defines _WINDOWS_ on all platforms if it isn't already
  • the resulting GUID struct is longer than on Windows
  • the load process does not populate all bytes as a result
  • during open, FreeImage first reads the image pixel type GUID
  • the it calls CopyPixels which also reads the image pixel type GUID
  • it then compares the GUIDs to see if they are identical
  • this comparision uses memcmp
  • since there are uninitialized bytes in the GUIDs, they don't match
  • LibJXR then goes off looking for a conversion function
  • it does not find one and reports the image as being in an unsupported format

If I replace _WINDOWS_ with _WIN32 in LibJXR it gets further. The api test seems to work with this change but fails on one of the memIO tests otherwise.

Discussion

  • Grant Boyle

    Grant Boyle - 2019-07-30

    Notes:

    • FreeImage.h line 132 defines WINDOWS macro
    • guiddef.h line 44 uses if to set the GUID structure
    • PluginJXR.cpp line 1022 uses IsEqualGUID to compare input and output formats
    • guiddef.h line 184 shows it is defined in terms of memcmp
    • debugging shows the type is 24-bytes long rather than 16

    Source\FreeImage.h

       131  #ifndef _WINDOWS_
       132  #define _WINDOWS_
       133  
       134  #ifndef FALSE
       135  #define FALSE 0
       136  #endif
       137  #ifndef TRUE
       138  #define TRUE 1
       139  #endif
       140  #ifndef NULL
       141  #define NULL 0
       142  #endif
       143  
       144  #ifndef SEEK_SET
       145  #define SEEK_SET  0
       146  #define SEEK_CUR  1
       147  #define SEEK_END  2
       148  #endif
    

    Source\LibJXR\common\include\guiddef.h

        33  #ifndef GUID_DEFINED
        34  #define GUID_DEFINED
        35  #if defined(__midl)
        36  typedef struct {
        37      unsigned long  Data1;
        38      unsigned short Data2;
        39      unsigned short Data3;
        40      byte           Data4[ 8 ];
        41  } GUID;
        42  #else
        43  typedef struct _GUID {
        44  #if defined(_WINDOWS_) || !__LP64__
        45      unsigned long  Data1;
        46  #else
        47      unsigned int   Data1;
        48  #endif
        49      unsigned short Data2;
        50      unsigned short Data3;
        51      unsigned char  Data4[ 8 ];
        52  } GUID;
        53  #endif
        54  #endif
    
      ...
    
       184  __inline int IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
       185  {
       186      return !memcmp(&rguid1, &rguid2, sizeof(GUID));
       187  }    
    

    FreeImage\PluginJXR.cpp

      1006  CopyPixels(PKImageDecode *pDecoder, PKPixelFormatGUID out_guid_format, FIBITMAP *dib, int width, int height) {
      1007      PKFormatConverter *pConverter = NULL;   // pixel format converter
      1008      ERR error_code = 0; // error code as returned by the interface
      1009      BYTE *pb = NULL;    // local buffer used for pixel format conversion
      1010      
      1011      // image dimensions
      1012      const PKRect rect = {0, 0, width, height};
      1013  
      1014      try {
      1015          // get input file pixel format ...
      1016          PKPixelFormatGUID in_guid_format;
      1017          error_code = pDecoder->GetPixelFormat(pDecoder, &in_guid_format);
      1018          JXR_CHECK(error_code);
      1019          
      1020          // is a format conversion needed ?
      1021  
      1022          if(IsEqualGUID(out_guid_format, in_guid_format)) {
      1023              // no conversion, load bytes "as is" ...
    

    LibJXR\jxrgluelib\JXRGlue.h

       190  DEFINE_GUID(GUID_PKPixelFormat48bpp3Channels, 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x26);
    

    debugging

    (gdb) x /24bx &out_guid_format
    0x7fffffffde70:    0x24    0xc3    0xdd    0x6f    0x03    0x4e    0xfe    0x4b
    0x7fffffffde78:    0xb1    0x85    0x3d    0x77    0x76    0x8d    0xc9    0x26
    0x7fffffffde80:    0x24    0xc3    0xdd    0x6f    0x03    0x4e    0xfe    0x4b
    (gdb) x /24bx &in_guid_format
    0x7fffffffde90:    0x24    0xc3    0xdd    0x6f    0x03    0x4e    0xfe    0x4b
    0x7fffffffde98:    0xb1    0x85    0x3d    0x77    0x76    0x8d    0xc9    0x26
    0x7fffffffdea0:    0xe0    0x3d    0x58    0x55    0x55    0x55    0x00    0x00
    (gdb) print out_guid_format
    $1 = {Data1 = 5475899973597774628, Data2 = 34225, Data3 = 30525, Data4 = "v\215\311&$\303\335o"}
    (gdb) print in_guid_format
    $2 = {Data1 = 5475899973597774628, Data2 = 34225, Data3 = 30525, Data4 = "v\215\311&\340=XU"}
    (gdb) print sizeof(out_guid_format)
    $3 = 24
    (gdb) print sizeof(in_guid_format)
    $4 = 24
    
     

    Last edit: Grant Boyle 2019-07-30
  • Hervé Drolon

    Hervé Drolon - 2020-06-01
    • assigned_to: Hervé Drolon
    • Group: -->
     
  • Hervé Drolon

    Hervé Drolon - 2021-04-04
    • status: open --> pending
     
  • Hervé Drolon

    Hervé Drolon - 2021-04-04

    fixed in the SVN

     

Log in to post a comment.

MongoDB Logo MongoDB