1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     Implements a PNG reader class + handler 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart and Markus Holzem 
   9 // Licence:     wxWindows license 
  10 ///////////////////////////////////////////////////////////////////////////// 
  13 #pragma implementation "pngread.h" 
  14 #pragma implementation "pnghand.h" 
  17 // For compilers that support precompilation, includes "wx.h". 
  18 #include "wx/wxprec.h" 
  35 #include "wx/palette.h" 
  36 #include "wx/bitmap.h" 
  38 #include "wx/msw/pngread.h" 
  39 #include "wx/msw/dibutils.h" 
  42 #include "../png/png.h" 
  45 extern "C" void png_read_init 
PNGARG((png_structp png_ptr
)); 
  46 extern "C" void png_write_init 
PNGARG((png_structp png_ptr
)); 
  48 #ifndef GlobalAllocPtr 
  49 #define     GlobalPtrHandle(lp)         \ 
  50                 ((HGLOBAL)GlobalHandle(lp)) 
  52 #define     GlobalLockPtr(lp)                \ 
  53                 ((BOOL)GlobalLock(GlobalPtrHandle(lp))) 
  54 #define     GlobalUnlockPtr(lp)      \ 
  55                 GlobalUnlock(GlobalPtrHandle(lp)) 
  57 #define     GlobalAllocPtr(flags, cb)        \ 
  58                 (GlobalLock(GlobalAlloc((flags), (cb)))) 
  59 #define     GlobalReAllocPtr(lp, cbNew, flags)       \ 
  60                 (GlobalUnlockPtr(lp), GlobalLock(GlobalReAlloc(GlobalPtrHandle(lp) , (cbNew), (flags)))) 
  61 #define     GlobalFreePtr(lp)                \ 
  62                 (GlobalUnlockPtr(lp), (BOOL)GlobalFree(GlobalPtrHandle(lp))) 
  67 ima_png_error(png_struct 
*png_ptr
, char *message
) 
  69 //        wxMessageBox(message, "PNG error"); 
  71   longjmp(png_ptr
->jmpbuf
, 1); 
  75 // static wxGifReaderIter* iter; 
  76 wxPalette 
*wxCopyPalette(const wxPalette 
*cmap
); 
  78 wxPNGReader::wxPNGReader() 
  81   RawImage 
= NULL
;      //  Image data 
  83   Width 
= 0; Height 
= 0;       //  Dimensions 
  84   Depth 
= 0;           // (bits x pixel) 
  85   ColorType 
= 0;        // Bit 1 = Palette used 
  89   EfeWidth 
= 0;         // Efective Width 
  97 wxPNGReader::wxPNGReader ( wxChar
* ImageFileName 
) 
 101   RawImage 
= NULL
;      //  Image data 
 103   Width 
= 0; Height 
= 0;       //  Dimensions 
 104   Depth 
= 0;           // (bits x pixel) 
 105   ColorType 
= 0;        // Bit 1 = Palette used 
 106                   // Bit 2 = Color used 
 107                   // Bit 3 = Alpha used 
 109   EfeWidth 
= 0;         // Efective Width 
 115   imageOK 
= ReadFile (ImageFileName
); 
 119 wxPNGReader::Create(int width
, int height
, int depth
, int colortype
) 
 121   Width 
= width
; Height 
= height
; Depth 
= depth
; 
 122   ColorType 
= (colortype
>=0) ? colortype
: ((Depth
>8) ? COLORTYPE_COLOR
: 0); 
 126    GlobalFreePtr((unsigned int) lpbi
); 
 134   lpbi 
= DibCreate(Depth
, Width
, Height
); 
 136     RawImage 
= (ImagePointerType
)DibPtr(lpbi
); 
 137     EfeWidth 
= (long)(((long)Width
*Depth 
+ 31) / 32) * 4; 
 142 wxPNGReader::~wxPNGReader ( ) 
 146    GlobalFreePtr((unsigned int) lpbi
); 
 155 int wxPNGReader::GetIndex(int x
, int y
) 
 157   if (!Inside(x
, y
) || (Depth
>8)) return -1; 
 159   ImagePointerType ImagePointer 
= RawImage 
+ EfeWidth
*y 
+ (x
*Depth 
>> 3); 
 160   int index 
= (int)(*ImagePointer
); 
 164 bool wxPNGReader::GetRGB(int x
, int y
, byte
* r
, byte
* g
, byte
* b
) 
 166   if (!Inside(x
, y
)) return FALSE
; 
 169    return Palette
->GetRGB(GetIndex(x
, y
), r
, g
, b
); 
 170 /*   PALETTEENTRY entry; 
 171    ::GetPaletteEntries((HPALETTE) Palette->GetHPALETTE(), GetIndex(x, y), 1, &entry); 
 174    *b = entry.peBlue;  */ 
 176    ImagePointerType ImagePointer 
= RawImage 
+ EfeWidth
*y 
+ (x
*Depth 
>> 3); 
 177    *b 
= ImagePointer
[0]; 
 178    *g 
= ImagePointer
[1]; 
 179    *r 
= ImagePointer
[2]; 
 185 bool wxPNGReader::SetIndex(int x
, int y
, int index
) 
 187   if (!Inside(x
, y
) || (Depth
>8)) return FALSE
; 
 189   ImagePointerType ImagePointer 
= RawImage 
+ EfeWidth
*y 
+ (x
*Depth 
>> 3); 
 190   *ImagePointer 
= index
; 
 195 bool wxPNGReader::SetRGB(int x
, int y
, byte r
, byte g
, byte b
) 
 197   if (!Inside(x
, y
)) return FALSE
; 
 199   if (ColorType 
& COLORTYPE_PALETTE
) 
 201    if (!Palette
) return FALSE
; 
 202    SetIndex(x
, y
, Palette
->GetPixel(r
, g
, b
)); 
 205    ImagePointerType ImagePointer 
= RawImage 
+ EfeWidth
*y 
+ (x
*Depth 
>> 3); 
 214 bool wxPNGReader::SetPalette(wxPalette
* colourmap
) 
 218   ColorType 
|= (COLORTYPE_PALETTE 
| COLORTYPE_COLOR
); 
 220   return (DibSetUsage(lpbi
, (HPALETTE
) Palette
->GetHPALETTE(), WXIMA_COLORS 
) != 0); 
 224 wxPNGReader::SetPalette(int n
, byte 
*r
, byte 
*g
, byte 
*b
) 
 226   Palette 
= new wxPalette(); 
 232   Palette
->Create(n
, r
, g
, b
); 
 233   ColorType 
|= (COLORTYPE_PALETTE 
| COLORTYPE_COLOR
); 
 234   return (DibSetUsage(lpbi
, (HPALETTE
) Palette
->GetHPALETTE(), WXIMA_COLORS 
) != 0); 
 238 wxPNGReader::SetPalette(int n
, rgb_color_struct 
*rgb_struct
) 
 240   Palette 
= new wxPalette(); 
 244   byte r
[256], g
[256], b
[256]; 
 246   for(int i
=0; i
<n
; i
++) 
 248    r
[i
] = rgb_struct
[i
].red
; 
 249    g
[i
] = rgb_struct
[i
].green
; 
 250    b
[i
] = rgb_struct
[i
].blue
; 
 252   // Added by JACS copying from Andrew Davison's additions 
 253   // to GIF-reading code 
 254   // Make transparency colour black... 
 256     r
[bgindex
] = g
[bgindex
] = b
[bgindex
] = 0; 
 258   Palette
->Create(n
, r
, g
, b
); 
 259   ColorType 
|= (COLORTYPE_PALETTE 
| COLORTYPE_COLOR
); 
 260   return (DibSetUsage(lpbi
, (HPALETTE
) Palette
->GetHPALETTE(), WXIMA_COLORS 
) != 0); 
 263 void wxPNGReader::NullData() 
 269 wxBitmap
* wxPNGReader::GetBitmap() 
 271     wxBitmap 
*bitmap 
= new wxBitmap
; 
 272     if ( InstantiateBitmap(bitmap
) ) 
 281 bool wxPNGReader::InstantiateBitmap(wxBitmap 
*bitmap
) 
 283   HDC dc 
= ::CreateCompatibleDC(NULL
); 
 287         // tmpBitmap is a dummy, to satisfy ::CreateCompatibleDC (it 
 288         // is a memory dc that must have a bitmap selected into it) 
 289         HDC dc2 
= GetDC(NULL
); 
 290         HBITMAP tmpBitmap 
= ::CreateCompatibleBitmap(dc2
, GetWidth(), GetHeight()); 
 291         ReleaseDC(NULL
, dc2
); 
 292         HBITMAP oldBitmap 
= (HBITMAP
) ::SelectObject(dc
, tmpBitmap
); 
 296             ::SelectPalette(dc
, (HPALETTE
) Palette
->GetHPALETTE(), FALSE
); 
 297         ::RealizePalette(dc
); 
 300     HBITMAP hBitmap 
= ::CreateDIBitmap(dc
, lpbi
, 
 301         CBM_INIT
, RawImage
, (LPBITMAPINFO
) lpbi
, DIB_PAL_COLORS
); 
 303         ::SelectPalette(dc
, NULL
, TRUE
); 
 304         ::SelectObject(dc
, oldBitmap
); 
 305         ::DeleteObject(tmpBitmap
); 
 310           bitmap
->SetHBITMAP((WXHBITMAP
) hBitmap
); 
 311           bitmap
->SetWidth(GetWidth()); 
 312           bitmap
->SetHeight(GetHeight()); 
 313           bitmap
->SetDepth(GetDepth()); 
 314           if ( GetDepth() > 1 && Palette 
) 
 315             bitmap
->SetPalette(*Palette
); 
 319           // Make a mask if appropriate 
 322             wxMask 
*mask 
= CreateMask(); 
 323             bitmap
->SetMask(mask
); 
 338 wxPalette 
*wxCopyPalette(const wxPalette 
*cmap
) 
 340   // To get number of entries... 
 342   ::GetObject((HPALETTE
) cmap
->GetHPALETTE(), sizeof(WORD
), &count
); 
 344   LOGPALETTE
* logPal 
= (LOGPALETTE
*) 
 345      new BYTE
[sizeof(LOGPALETTE
) + count
*sizeof(PALETTEENTRY
)]; 
 346   logPal
->palVersion 
= 0x300; 
 347   logPal
->palNumEntries 
= count
; 
 348   ::GetPaletteEntries((HPALETTE
) cmap
->GetHPALETTE(), 0, count
, logPal
->palPalEntry
); 
 350   HPALETTE hPalette 
= ::CreatePalette(logPal
); 
 353   wxPalette 
*newCmap 
= new wxPalette
; 
 354   newCmap
->SetHPALETTE((WXHPALETTE
) hPalette
); 
 358 wxMask 
*wxPNGReader::CreateMask() 
 360     HBITMAP hBitmap 
= ::CreateBitmap(GetWidth(), GetHeight(), 1, 1, NULL
); 
 362   HDC dc 
= ::CreateCompatibleDC(NULL
); 
 363     HBITMAP oldBitmap 
= (HBITMAP
) ::SelectObject(dc
, hBitmap
); 
 365     int bgIndex 
= GetBGIndex(); 
 369     for (x
=0; x
<GetWidth(); x
++) 
 371         for (y
=0; y
<GetHeight(); y
++) 
 373             int index 
= GetIndex(x
, y
); 
 374             if ( index 
== bgIndex 
) 
 375                 ::SetPixel(dc
, x
, GetHeight() - y 
- 1, RGB(0, 0, 0)); 
 377                 ::SetPixel(dc
, x
, GetHeight() - y 
- 1, RGB(255, 255, 255)); 
 381     ::SelectObject(dc
, oldBitmap
); 
 382     wxMask 
*mask 
= new wxMask
; 
 383     mask
->SetMaskBitmap((WXHBITMAP
) hBitmap
); 
 387 bool wxPNGReader::ReadFile(wxChar 
* ImageFileName
) 
 392         wxStrcpy(filename
, ImageFileName
); 
 399     fp 
= fopen(wxConvFile
.cWX2MB(filename
), "rb"); 
 403     /* allocate the necessary structures */ 
 404     png_ptr 
= new (png_struct
); 
 411     info_ptr 
= new (png_info
); 
 418     /* set error handling */ 
 419     if (setjmp(png_ptr
->jmpbuf
)) 
 421         png_read_destroy(png_ptr
, info_ptr
, (png_info 
*)0); 
 426         /* If we get here, we had a problem reading the file */ 
 429     //png_set_error(ima_png_error, NULL); 
 431     /* initialize the structures, info first for error handling */ 
 432     png_info_init(info_ptr
); 
 433     png_read_init(png_ptr
); 
 435     /* set up the input control */ 
 436     png_init_io(png_ptr
, fp
); 
 438     /* read the file information */ 
 439     png_read_info(png_ptr
, info_ptr
); 
 441     /* allocate the memory to hold the image using the fields 
 443     png_color_16 my_background
={ 0, 31, 127, 255, 0 }; 
 445     if (info_ptr
->valid 
& PNG_INFO_bKGD
) 
 447         png_set_background(png_ptr
, &(info_ptr
->background
), 
 448                 PNG_BACKGROUND_GAMMA_FILE
, 1, 1.0); 
 449         if ( info_ptr
->num_palette 
> 0 ) 
 450             bgindex 
= info_ptr
->background
.index
; 
 453         png_set_background(png_ptr
, &my_background
, 
 454                 PNG_BACKGROUND_GAMMA_SCREEN
, 0, 1.0); 
 456         // Added by JACS: guesswork! 
 457         if ( info_ptr
->num_trans 
!= 0 ) 
 458             bgindex 
= info_ptr
->num_trans 
- 1 ; 
 461     /* tell libpng to strip 16 bit depth files down to 8 bits */ 
 462     if (info_ptr
->bit_depth 
== 16) 
 463         png_set_strip_16(png_ptr
); 
 465     int pixel_depth
=(info_ptr
->pixel_depth
<24) ? info_ptr
->pixel_depth
: 24; 
 466     Create(info_ptr
->width
, info_ptr
->height
, pixel_depth
, 
 467             info_ptr
->color_type
); 
 469     if (info_ptr
->num_palette
>0) 
 471         SetPalette((int)info_ptr
->num_palette
, (rgb_color_struct
*)info_ptr
->palette
); 
 474     int row_stride 
= info_ptr
->width 
* ((pixel_depth
+7)>>3); 
 475     //  printf("P = %d D = %d RS= %d ", info_ptr->num_palette, info_ptr->pixel_depth,row_stride); 
 476     //  printf("CT = %d TRS = %d BD= %d ", info_ptr->color_type, info_ptr->valid & PNG_INFO_tRNS,info_ptr->bit_depth); 
 478     byte 
*row_pointers 
= new byte
[row_stride
]; 
 480     /* turn on interlace handling */ 
 481     if (info_ptr
->interlace_type
) 
 482         number_passes 
= png_set_interlace_handling(png_ptr
); 
 485     //  printf("NP = %d ", number_passes); 
 487     // don't use the object to prevent warnings from VC++ about "unportable 
 488     // interaction between setjmp and C++ object destruction" (this is a correct 
 489     // warning, of course!) 
 490     wxPNGReaderIter 
*iter 
= new wxPNGReaderIter(this); 
 491     for (int pass
=0; pass
< number_passes
; pass
++) 
 496             //(unsigned char *)iter.GetRow(); 
 497             if (info_ptr
->interlace_type
)  { 
 499                     iter
->GetRow(row_pointers
, row_stride
); 
 500                 png_read_row(png_ptr
, row_pointers
, NULL
); 
 503                 png_read_row(png_ptr
, row_pointers
, NULL
); 
 505             iter
->SetRow(row_pointers
, row_stride
); 
 507         } while(iter
->PrevRow()); 
 508         //  printf("Y=%d ",y); 
 512     delete[] row_pointers
; 
 514     /* read the rest of the file, getting any additional chunks 
 516     png_read_end(png_ptr
, info_ptr
); 
 518     /* clean up after the read, and free any memory allocated */ 
 519     png_read_destroy(png_ptr
, info_ptr
, (png_info 
*)0); 
 521     /* free the structures */ 
 533 /* write a png file */ 
 535 bool wxPNGReader::SaveFile(wxChar 
* ImageFileName
) 
 538    wxStrcpy(filename
, ImageFileName
); 
 540   wxPNGReaderIter 
iter(this); 
 546   fp 
= fopen(wxConvFile
.cWX2MB(filename
), "wb"); 
 550   /* allocate the necessary structures */ 
 551   png_ptr 
= new (png_struct
); 
 558   info_ptr 
= new (png_info
); 
 566   /* set error handling */ 
 567   if (setjmp(png_ptr
->jmpbuf
)) 
 569     png_write_destroy(png_ptr
); 
 574     /* If we get here, we had a problem reading the file */ 
 577         //png_set_error(ima_png_error, NULL); 
 579 //  printf("writig pg %s ", filename); 
 580    /* initialize the structures */ 
 581   png_info_init(info_ptr
); 
 582   png_write_init(png_ptr
); 
 584   int row_stride 
= GetWidth() * ((GetDepth()+7)>>3); 
 585   /* set up the output control */ 
 586    png_init_io(png_ptr
, fp
); 
 588   /* set the file information here */ 
 589   info_ptr
->width 
= GetWidth(); 
 590   info_ptr
->height 
= GetHeight(); 
 591   info_ptr
->pixel_depth 
= GetDepth(); 
 592   info_ptr
->channels 
= (GetDepth()>8) ? 3: 1; 
 593   info_ptr
->bit_depth 
= GetDepth()/info_ptr
->channels
; 
 594   info_ptr
->color_type 
= GetColorType(); 
 595   info_ptr
->compression_type 
= info_ptr
->filter_type 
= info_ptr
->interlace_type
=0; 
 597   info_ptr
->rowbytes 
= row_stride
; 
 600 // printf("P = %d D = %d RS= %d GD= %d CH= %d ", info_ptr->pixel_depth, info_ptr->bit_depth, row_stride, GetDepth(), info_ptr->channels); 
 601   /* set the palette if there is one */ 
 602   if ((GetColorType() & COLORTYPE_PALETTE
) && GetPalette()) 
 604 //    printf("writing paleta[%d %d %x]",GetColorType() ,COLORTYPE_PALETTE, GetPalette()); 
 605     info_ptr
->valid 
|= PNG_INFO_PLTE
; 
 606     info_ptr
->palette 
= new png_color
[256]; 
 607     info_ptr
->num_palette 
= 256; 
 608     for (int i
=0; i
<256; i
++) 
 609      GetPalette()->GetRGB(i
, &info_ptr
->palette
[i
].red
, &info_ptr
->palette
[i
].green
, &info_ptr
->palette
[i
].blue
); 
 611 //    printf("Paleta [%d %d %x]",GetColorType() ,COLORTYPE_PALETTE, GetPalette()); 
 614    /* optional significant bit chunk */ 
 615 //   info_ptr->valid |= PNG_INFO_sBIT; 
 616 //   info_ptr->sig_bit = true_bit_depth; 
 618   /* optional gamma chunk */ 
 619 //   info_ptr->valid |= PNG_INFO_gAMA; 
 620 //   info_ptr->gamma = gamma; 
 622   /* other optional chunks */ 
 624    /* write the file information */ 
 625    png_write_info(png_ptr
, info_ptr
); 
 627    /* set up the transformations you want.  Note that these are 
 628       all optional.  Only call them if you want them */ 
 630   /* shift the pixels up to a legal bit depth and fill in 
 631       as appropriate to correctly scale the image */ 
 632 //   png_set_shift(png_ptr, &(info_ptr->sig_bit)); 
 634   /* pack pixels into bytes */ 
 635 //   png_set_packing(png_ptr); 
 637   /* flip bgr pixels to rgb */ 
 638 //   png_set_bgr(png_ptr); 
 640    /* swap bytes of 16 bit files to most significant bit first */ 
 641 //   png_set_swap(png_ptr); 
 643    /* get rid of filler bytes, pack rgb into 3 bytes */ 
 644 //   png_set_rgbx(png_ptr); 
 646 /* If you are only writing one row at a time, this works */ 
 648   byte 
*row_pointers 
= new byte
[row_stride
]; 
 651 //    (unsigned char *)iter.GetRow(); 
 652     iter
.GetRow(row_pointers
, row_stride
); 
 653     png_write_row(png_ptr
, row_pointers
); 
 654   } while(iter
.PrevRow()); 
 656         delete[] row_pointers
; 
 658 /* write the rest of the file */ 
 659    png_write_end(png_ptr
, info_ptr
); 
 661   /* clean up after the write, and free any memory allocated */ 
 662    png_write_destroy(png_ptr
); 
 664    /* if you malloced the palette, free it here */ 
 665    if (info_ptr
->palette
) 
 666     delete[] (info_ptr
->palette
); 
 668   /* free the structures */ 
 679 static int Power(int x
, int y
) 
 683     for ( i 
= 0; i 
< y
; i
++) 
 690 static char hexArray
[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 
 691   'C', 'D', 'E', 'F' }; 
 693 static void DecToHex(int dec
, char *buf
) 
 695   int firstDigit 
= (int)(dec
/16.0); 
 696   int secondDigit 
= (int)(dec 
- (firstDigit
*16.0)); 
 697   buf
[0] = hexArray
[firstDigit
]; 
 698   buf
[1] = hexArray
[secondDigit
]; 
 703 bool wxPNGReader::SaveXPM(wxChar 
*filename
, wxChar 
*name
) 
 707         wxStrcpy(nameStr
, name
); 
 710         wxStrcpy(nameStr
, filename
); 
 711         wxStripExtension(nameStr
); 
 714     if ( GetDepth() > 4 ) 
 716         // Only a depth of 4 and below allowed 
 723     ofstream 
str(wxConvFile
.cWX2MB(filename
)); 
 727     int noColours 
= Power(2, GetDepth()); 
 730     str 
<< "/* XPM */\n"; 
 731     str 
<< "static char * " << nameStr 
<< "_xpm[] = {\n"; 
 732     str 
<< "\"" << GetWidth() << " " << GetHeight() << " " << noColours 
<< " 1\",\n"; 
 735     int base 
= 97 ; // start from 'a' 
 737     unsigned char red
, green
, blue
; 
 740     for ( i 
= 0; i 
< noColours
; i 
++) 
 742         str 
<< "\"" << (char)(base 
+ i
) << "      c #"; 
 743         GetPalette()->GetRGB(i
, &red
, &green
, &blue
); 
 744         DecToHex(red
, hexBuf
); 
 746         DecToHex(green
, hexBuf
); 
 748         DecToHex(blue
, hexBuf
); 
 755     for ( y 
= 0; y 
< GetHeight(); y
++) 
 758         for ( x 
= 0; x 
< GetWidth(); x
++) 
 760             int index 
= GetIndex(x
, y
); 
 761             str 
<< (char)(base 
+ index
) ; 
 772 #include <wx/msw/pnghand.h> 
 774 IMPLEMENT_DYNAMIC_CLASS(wxPNGFileHandler
, wxBitmapHandler
) 
 776 bool wxPNGFileHandler::LoadFile(wxBitmap 
*bitmap
, const wxString
& name
, long flags
, 
 777     int desiredWidth
, int desiredHeight
) 
 780     if (reader
.ReadFile(WXSTRINGCAST name
)) 
 782         return reader
.InstantiateBitmap(bitmap
); 
 788 bool wxPNGFileHandler::SaveFile(wxBitmap 
*bitmap
, const wxString
& name
, int type
, const wxPalette 
*pal
)