MagickWand writes a bitmap incompatible with Win32 LoadImage

Questions and postings pertaining to the development of ImageMagick, feature enhancements, and ImageMagick internals. ImageMagick source code and algorithms are discussed here. Usage questions which are too arcane for the normal user list should also be posted here.
Post Reply
168gr
Posts: 47
Joined: 2013-01-09T22:46:19-07:00
Authentication code: 6789

MagickWand writes a bitmap incompatible with Win32 LoadImage

Post by 168gr »

I'm back with another question and some hard to understand (to me) behavior of the ImageMagick API ...

I'm using some code from Microsoft's online tutorials (referenced and copied below) to load a bitmap file and then subsequently display it in a win32 GUI program with BitBlt(). It works perfectly with bitmap files from any source, except those written by MagickWand.

Test program and output is below. Image files follow that. This is what I did:

1) Using MS Paint, I made a simple 100x50 image with a squiggly line.

2) Saved it as a 24-bit bitmap, named bitmap_made_by_ms_paint.bmp

3) Then saved the same image as a jpeg, named jpeg_made_by_ms_paint.jpg

4) Run test program.

4a) The program first tests the MS-provided LoadImage() routine to load bitmap_made_by_ms_paint.bmp - success.

4b) The program then uses MagickWand to read jpeg_made_by_ms_paint.jpg and immediately writes the image to bitmap_made_by_magick_wand.bmp - success.

4c) The program then tests the MS-provided LoadImage() routine to load bitmap_made_by_magick_wand.bmp - fails.

5) Swear at computer.

Other image editing programs (Paint, Gimp, Windows Explorer, Firefox, IE) can open all three image files. They look identical.

Where's the problem? Does MagickWand write a bitmap in some non-standard format? Is Microsoft's LoadImage (and their example wrapper LoadBitmapFromBMPFile) buggy? Am I doing something else wrong?

Thank you.

Code: Select all

pgg@g550 ~/test
$ ls -l
total 80
-rwxr-xr-x  1 pgg None 15054 Feb  3 12:05 bitmap_made_by_ms_paint.bmp
drwxr-xr-x+ 1 pgg None     0 Jan 30 22:41 include
-rwxr-xr-x  1 pgg None  2653 Feb  3 12:05 jpeg_made_by_ms_paint.jpg
-rwxr-xr-x  1 pgg None  3419 Feb  3 12:16 test.c
-rwxr-xr-x  1 pgg None 57120 Feb  3 12:16 test.exe

pgg@g550 ~/test
$ cat test.c
#include <windows.h>
#include <wchar.h>
#include <stdio.h>
#include <string.h>
#include <wand/magick_wand.h>



// From MS Support Article 158898   http://support.microsoft.com/kb/158898
BOOL LoadBitmapFromBMPFile (LPTSTR szFileName, HBITMAP *phBitmap, HPALETTE *phPalette )
{
  BITMAP bm;

  *phBitmap = NULL;
  *phPalette = NULL;

  // Load image into a DIBSection
  *phBitmap = (HBITMAP)LoadImage( NULL, szFileName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE );

  if( *phBitmap == NULL ) {
    fprintf( stderr, "LoadImage() failed to load image file.\n" );
    return FALSE;
  }

  // Get color depth of the DIBSection
  GetObject( *phBitmap, sizeof(BITMAP), &bm );

  // If the DIBSection is 256 color or less, it has a color table
  if( ( bm.bmBitsPixel * bm.bmPlanes ) <= 8 )
  {
    HDC hMemDC;
    HBITMAP hOldBitmap;
    RGBQUAD rgb[256];
    LPLOGPALETTE pLogPal;
    WORD i;

    // Create a memory DC and select the DIBSection into it
    hMemDC = CreateCompatibleDC( NULL );
    hOldBitmap = (HBITMAP)SelectObject( hMemDC, *phBitmap );

    // Get the DIBSection's color table
    GetDIBColorTable( hMemDC, 0, 256, rgb );

    // Create a palette from the color table
    pLogPal = (LOGPALETTE *)malloc( sizeof(LOGPALETTE) + (256*sizeof(PALETTEENTRY)) );
    pLogPal->palVersion = 0x300;
    pLogPal->palNumEntries = 256;
    for( i = 0; i < 256; i++ ) {
      pLogPal->palPalEntry[i].peRed = rgb[i].rgbRed;
      pLogPal->palPalEntry[i].peGreen = rgb[i].rgbGreen;
      pLogPal->palPalEntry[i].peBlue = rgb[i].rgbBlue;
      pLogPal->palPalEntry[i].peFlags = 0;
    }
    *phPalette = CreatePalette( pLogPal );

    // Clean up
    free( pLogPal );
    SelectObject( hMemDC, hOldBitmap );
    DeleteDC( hMemDC );
  } else { // it has no color table, so use a halftone palette
    HDC hRefDC;
    hRefDC = GetDC( NULL );
    *phPalette = CreateHalftonePalette( hRefDC );
    ReleaseDC( NULL, hRefDC );
  }

  return TRUE;
}


int main() {

  MagickWand *mw = NULL;

  HBITMAP hBitmap;
  HPALETTE hPalette;


  fprintf( stderr, "** Checking LoadImage() with bitmap made with MS paint **\n" );
  if( LoadBitmapFromBMPFile( "bitmap_made_by_ms_paint.bmp", &hBitmap, &hPalette ) )
    fprintf( stderr, "LoadBitMapFromBMPFile successfully loaded 'bitmap_made_by_ms_paint.bmp'\n" );
  else
    fprintf( stderr, "LoadBitMapFromBMPFile failed to load 'bitmap_made_by_ms_paint.bmp'\n" );


  fprintf( stderr, "\n\n** Using MagickWand to convert bitmap to jpeg **\n" );
  MagickWandGenesis();
  mw = NewMagickWand();
  MagickReadImage( mw, "jpeg_made_by_ms_paint.jpg" );
  MagickWriteImage( mw, "bitmap_made_by_magick_wand.bmp" );
  DestroyMagickWand(mw);
  MagickWandTerminus();


  fprintf( stderr, "\n\n** Checking LoadImage() with bitmap made with Magick Wand**\n" );
  if( LoadBitmapFromBMPFile( "bitmap_made_by_magick_wand.bmp", &hBitmap, &hPalette ) )
    fprintf( stderr, "LoadBitMapFromBMPFile successfully loaded 'bitmap_made_by_magick_wand.bmp'\n" );
  else
    fprintf( stderr, "LoadBitMapFromBMPFile failed to load 'bitmap_made_by_magick_wand.bmp'\n" );


  return 0;
}

/*
gcc test.c -o test -lMagickWand-Q16 -lgdi32 -L/home/pgg/ImageMagick-6.8.1/lib -I/home/pgg/ImageMagick-6.8.1/include/ImageMagick -DMAGICKCORE_HDRI_ENABLE=0 -DMAGICKCORE_QUANTUM_DEPTH=16
*/


pgg@g550 ~/test
$ gcc test.c -o test -lMagickWand-Q16 -lgdi32 -L/home/pgg/ImageMagick-6.8.1/lib -I/home/pgg/ImageMagick-6.8.1/include/ImageMagick -DMAGICKCORE_HDRI_ENABLE=0 -DMAGICKCORE_QUANTUM_DEPTH=16

pgg@g550 ~/test
$ ./test.exe
** Checking LoadImage() with bitmap made with MS paint **
LoadBitMapFromBMPFile successfully loaded 'bitmap_made_by_ms_paint.bmp'


** Using MagickWand to convert bitmap to jpeg **


** Checking LoadImage() with bitmap made with Magick Wand**
LoadImage() failed to load image file.
LoadBitMapFromBMPFile failed to load 'bitmap_made_by_magick_wand.bmp'

pgg@g550 ~/test
$ ls -l
total 96
-rw-r--r--  1 pgg None 15138 Feb  3 12:17 bitmap_made_by_magick_wand.bmp
-rwxr-xr-x  1 pgg None 15054 Feb  3 12:05 bitmap_made_by_ms_paint.bmp
drwxr-xr-x+ 1 pgg None     0 Jan 30 22:41 include
-rwxr-xr-x  1 pgg None  2653 Feb  3 12:05 jpeg_made_by_ms_paint.jpg
-rwxr-xr-x  1 pgg None  3419 Feb  3 12:16 test.c
-rwxr-xr-x  1 pgg None 57120 Feb  3 12:17 test.exe
Below are the actual image files made by MS Paint and MagickWand:

bitmap_made_by_ms_paint.bmp
Image

jpeg_made_by_ms_paint.jpg
Image

bitmap_made_by_magick_wand.bmp
Image


Thank you.
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: MagickWand writes a bitmap incompatible with Win32 LoadI

Post by snibgo »

This may be a problem with DIB headers. These come in different flavours: seven, at the last count. See http://en.wikipedia.org/wiki/BMP_file_format

If I understand correctly (and I probably don't), IM understands three of them; see "convert -list format". Maybe your program implicitly expects one format, but IM is making a different one.

Perhaps you could create files of different versions ...

Code: Select all

convert x.png b.bmp
convert x.png BMP2:b2.bmp
convert x.png BMP3:b3.bmp
... and see if your program can read them.
snibgo's IM pages: im.snibgo.com
168gr
Posts: 47
Joined: 2013-01-09T22:46:19-07:00
Authentication code: 6789

Re: MagickWand writes a bitmap incompatible with Win32 LoadI

Post by 168gr »

snibgo wrote:This may be a problem with DIB headers. These come in different flavours: seven, at the last count. See http://en.wikipedia.org/wiki/BMP_file_format

If I understand correctly (and I probably don't), IM understands three of them; see "convert -list format". Maybe your program implicitly expects one format, but IM is making a different one.

Perhaps you could create files of different versions ...

Code: Select all

convert x.png b.bmp
convert x.png BMP2:b2.bmp
convert x.png BMP3:b3.bmp
... and see if your program can read them.
Excellent ... :D :D

Code: Select all

Testing 1
LoadImage() failed to load image file.
LoadBitMapFromBMPFile failed to load 'b1.bmp'

Testing 2
LoadBitMapFromBMPFile successfully loaded 'b2.bmp'

Testing 3
LoadBitMapFromBMPFile successfully loaded 'b3.bmp'

Replaced the call to MagickWriteImage with

Code: Select all

MagickWriteImage( mw, "BMP2:bitmap_made_by_magick_wand.bmp" );
And all appears to be well. :D

Thanks very much.
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: MagickWand writes a bitmap incompatible with Win32 LoadI

Post by snibgo »

Good stuff. I do like it when a wild guess turns out to be correct.
snibgo's IM pages: im.snibgo.com
Post Reply