1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     Implements a PNG reader class + handler 
   4 // Author:      David Webster 
   8 // Copyright:   (c) David Webster 
   9 // Licence:     wxWindows license 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  25 #include "wx/palette.h" 
  26 #include "wx/bitmap.h" 
  32 #include "wx/os2/pngread.h" 
  35 #include "../png/png.h" 
  38 extern "C" void png_read_init 
PNGARG((png_structp png_ptr
)); 
  39 extern "C" void png_write_init 
PNGARG((png_structp png_ptr
)); 
  41 #ifndef GlobalAllocPtr 
  42 #define     GlobalPtrHandle(lp)         \ 
  43                 ((HGLOBAL)GlobalHandle(lp)) 
  45 #define     GlobalLockPtr(lp)                \ 
  46                 ((BOOL)GlobalLock(GlobalPtrHandle(lp))) 
  47 #define     GlobalUnlockPtr(lp)      \ 
  48                 GlobalUnlock(GlobalPtrHandle(lp)) 
  50 #define     GlobalAllocPtr(flags, cb)        \ 
  51                 (GlobalLock(GlobalAlloc((flags), (cb)))) 
  52 #define     GlobalReAllocPtr(lp, cbNew, flags)       \ 
  53                 (GlobalUnlockPtr(lp), GlobalLock(GlobalReAlloc(GlobalPtrHandle(lp) , (cbNew), (flags)))) 
  54 #define     GlobalFreePtr(lp)                \ 
  55                 (GlobalUnlockPtr(lp), (BOOL)GlobalFree(GlobalPtrHandle(lp))) 
  59 void ima_png_error(png_struct 
*png_ptr
, char *message
) 
  61 //        wxMessageBox(message, "PNG error"); 
  63   longjmp(png_ptr
->jmpbuf
, 1); 
  67 // static wxGifReaderIter* iter; 
  68 wxPalette 
*wxCopyPalette(const wxPalette 
*cmap
); 
  70 wxPNGReader::wxPNGReader() 
  73   RawImage 
= NULL
;      //  Image data 
  75   Width 
= 0; Height 
= 0;       //  Dimensions 
  76   Depth 
= 0;           // (bits x pixel) 
  77   ColorType 
= 0;        // Bit 1 = Palette used 
  81   EfeWidth 
= 0;         // Efective Width 
  89 wxPNGReader::wxPNGReader ( wxChar
* ImageFileName 
) 
  93   RawImage 
= NULL
;      //  Image data 
  95   Width 
= 0; Height 
= 0;       //  Dimensions 
  96   Depth 
= 0;           // (bits x pixel) 
  97   ColorType 
= 0;        // Bit 1 = Palette used 
 101   EfeWidth 
= 0;         // Efective Width 
 107   imageOK 
= ReadFile (ImageFileName
); 
 111 wxPNGReader::Create(int width
, int height
, int depth
, int colortype
) 
 113   Width 
= width
; Height 
= height
; Depth 
= depth
; 
 114   ColorType 
= (colortype
>=0) ? colortype
: ((Depth
>8) ? COLORTYPE_COLOR
: 0); 
 117 //   GlobalFreePtr(lpbi); 
 122   lpbi 
= 0; // TODO: wxDibCreate(Depth, Width, Height); 
 124     RawImage 
= 0; //TODO: (ImagePointerType)wxDibPtr(lpbi); 
 125     EfeWidth 
= (long)(((long)Width
*Depth 
+ 31) / 32) * 4; 
 130 wxPNGReader::~wxPNGReader ( ) 
 133 // TODO:   GlobalFreePtr(lpbi); 
 139 int wxPNGReader::GetIndex(int x
, int y
) 
 141   if (!Inside(x
, y
) || (Depth
>8)) return -1; 
 143   ImagePointerType ImagePointer 
= RawImage 
+ EfeWidth
*y 
+ (x
*Depth 
>> 3); 
 144   int index 
= (int)(*ImagePointer
); 
 148 bool wxPNGReader::GetRGB(int x
, int y
, byte
* r
, byte
* g
, byte
* b
) 
 150   if (!Inside(x
, y
)) return FALSE
; 
 153    return Palette
->GetRGB(GetIndex(x
, y
), r
, g
, b
); 
 154 /*   PALETTEENTRY entry; 
 155    ::GetPaletteEntries((HPALETTE) Palette->GetHPALETTE(), GetIndex(x, y), 1, &entry); 
 158    *b = entry.peBlue;  */ 
 160    ImagePointerType ImagePointer 
= RawImage 
+ EfeWidth
*y 
+ (x
*Depth 
>> 3); 
 161    *b 
= ImagePointer
[0]; 
 162    *g 
= ImagePointer
[1]; 
 163    *r 
= ImagePointer
[2]; 
 169 bool wxPNGReader::SetIndex(int x
, int y
, int index
) 
 171   if (!Inside(x
, y
) || (Depth
>8)) return FALSE
; 
 173   ImagePointerType ImagePointer 
= RawImage 
+ EfeWidth
*y 
+ (x
*Depth 
>> 3); 
 174   *ImagePointer 
= index
; 
 179 bool wxPNGReader::SetRGB(int x
, int y
, byte r
, byte g
, byte b
) 
 181   if (!Inside(x
, y
)) return FALSE
; 
 183   if (ColorType 
& COLORTYPE_PALETTE
) 
 185    if (!Palette
) return FALSE
; 
 186    SetIndex(x
, y
, Palette
->GetPixel(r
, g
, b
)); 
 189    ImagePointerType ImagePointer 
= RawImage 
+ EfeWidth
*y 
+ (x
*Depth 
>> 3); 
 198 bool wxPNGReader::SetPalette(wxPalette
* colourmap
) 
 202   ColorType 
|= (COLORTYPE_PALETTE 
| COLORTYPE_COLOR
); 
 204 // TODO:  return (wxDibSetUsage(lpbi, (HPALETTE) Palette->GetHPALETTE(), WXIMA_COLORS ) != 0); 
 209 wxPNGReader::SetPalette(int n
, byte 
*r
, byte 
*g
, byte 
*b
) 
 211   Palette 
= new wxPalette(); 
 217   Palette
->Create(n
, r
, g
, b
); 
 218   ColorType 
|= (COLORTYPE_PALETTE 
| COLORTYPE_COLOR
); 
 219 // TODO:  return (wxDibSetUsage(lpbi, (HPALETTE) Palette->GetHPALETTE(), WXIMA_COLORS ) != 0); 
 224 wxPNGReader::SetPalette(int n
, rgb_color_struct 
*rgb_struct
) 
 226   Palette 
= new wxPalette(); 
 230   byte r
[256], g
[256], b
[256]; 
 232   for(int i
=0; i
<n
; i
++) 
 234    r
[i
] = rgb_struct
[i
].red
; 
 235    g
[i
] = rgb_struct
[i
].green
; 
 236    b
[i
] = rgb_struct
[i
].blue
; 
 238   // Added by JACS copying from Andrew Davison's additions 
 239   // to GIF-reading code 
 240   // Make transparency colour black... 
 242     r
[bgindex
] = g
[bgindex
] = b
[bgindex
] = 0; 
 244   Palette
->Create(n
, r
, g
, b
); 
 245   ColorType 
|= (COLORTYPE_PALETTE 
| COLORTYPE_COLOR
); 
 246 // TODO:  return (wxDibSetUsage(lpbi, (HPALETTE) Palette->GetHPALETTE(), WXIMA_COLORS ) != 0); 
 250 void wxPNGReader::NullData() 
 256 wxBitmap
* wxPNGReader::GetBitmap() 
 258     wxBitmap 
*bitmap 
= new wxBitmap
; 
 259     if ( InstantiateBitmap(bitmap
) ) 
 268 bool wxPNGReader::InstantiateBitmap(wxBitmap 
*bitmap
) 
 272   HDC dc = ::CreateCompatibleDC(NULL); 
 276         // tmpBitmap is a dummy, to satisfy ::CreateCompatibleDC (it 
 277         // is a memory dc that must have a bitmap selected into it) 
 278         HDC dc2 = GetDC(NULL); 
 279         HBITMAP tmpBitmap = ::CreateCompatibleBitmap(dc2, GetWidth(), GetHeight()); 
 280         ReleaseDC(NULL, dc2); 
 281         HBITMAP oldBitmap = (HBITMAP) ::SelectObject(dc, tmpBitmap); 
 285             ::SelectPalette(dc, (HPALETTE) Palette->GetHPALETTE(), FALSE); 
 286         ::RealizePalette(dc); 
 289     HBITMAP hBitmap = ::CreateDIBitmap(dc, lpbi, 
 290         CBM_INIT, RawImage, (LPBITMAPINFO) lpbi, DIB_PAL_COLORS); 
 292         ::SelectPalette(dc, NULL, TRUE); 
 293         ::SelectObject(dc, oldBitmap); 
 294         ::DeleteObject(tmpBitmap); 
 299           bitmap->SetHBITMAP((WXHBITMAP) hBitmap); 
 300           bitmap->SetWidth(GetWidth()); 
 301           bitmap->SetHeight(GetHeight()); 
 302           bitmap->SetDepth(GetDepth()); 
 303           if ( GetDepth() > 1 && Palette ) 
 304             bitmap->SetPalette(*Palette); 
 308           // Make a mask if appropriate 
 311             wxMask *mask = CreateMask(); 
 312             bitmap->SetMask(mask); 
 329 wxPalette 
*wxCopyPalette(const wxPalette 
*cmap
) 
 331   // To get number of entries... 
 333 // TODO:  ::GetObject((HPALETTE) cmap->GetHPALETTE(), sizeof(WORD), &count); 
 336   LOGPALETTE* logPal = (LOGPALETTE*) 
 337      new BYTE[sizeof(LOGPALETTE) + count*sizeof(PALETTEENTRY)]; 
 338   logPal->palVersion = 0x300; 
 339   logPal->palNumEntries = count; 
 340   ::GetPaletteEntries((HPALETTE) cmap->GetHPALETTE(), 0, count, logPal->palPalEntry); 
 342   HPALETTE hPalette = ::CreatePalette(logPal); 
 345   wxPalette 
*newCmap 
= new wxPalette
; 
 346 // TODO:  newCmap->SetHPALETTE((WXHPALETTE) hPalette); 
 350 wxMask 
*wxPNGReader::CreateMask() 
 354     HBITMAP hBitmap = ::CreateBitmap(GetWidth(), GetHeight(), 1, 1, NULL); 
 356   HDC dc = ::CreateCompatibleDC(NULL); 
 357     HBITMAP oldBitmap = (HBITMAP) ::SelectObject(dc, hBitmap); 
 359     int bgIndex = GetBGIndex(); 
 363     for (x=0; x<GetWidth(); x++) 
 365         for (y=0; y<GetHeight(); y++) 
 367             int index = GetIndex(x, y); 
 368             if ( index == bgIndex ) 
 369                 ::SetPixel(dc, x, GetHeight() - y - 1, RGB(0, 0, 0)); 
 371                 ::SetPixel(dc, x, GetHeight() - y - 1, RGB(255, 255, 255)); 
 375     ::SelectObject(dc, oldBitmap); 
 377     wxMask 
*mask 
= new wxMask
; 
 378 // TODO:    mask->SetMaskBitmap((WXHBITMAP) hBitmap); 
 382 bool wxPNGReader::ReadFile(wxChar 
* ImageFileName
) 
 385         wxStrcpy(filename
, ImageFileName
); 
 388     FILE *fp 
= fopen(wxConvFile
.cWX2MB(filename
), "rb"); 
 392     /* allocate the necessary structures */ 
 393     png_struct 
*png_ptr 
= new (png_struct
); 
 400     png_info 
*info_ptr 
= new (png_info
); 
 408     /* set error handling */ 
 409     if (setjmp(png_ptr
->jmpbuf
)) 
 411         png_read_destroy(png_ptr
, info_ptr
, (png_info 
*)0); 
 416         /* If we get here, we had a problem reading the file */ 
 419     //png_set_error(ima_png_error, NULL); 
 421     /* initialize the structures, info first for error handling */ 
 422     png_info_init(info_ptr
); 
 423     png_read_init(png_ptr
); 
 425     /* set up the input control */ 
 426     png_init_io(png_ptr
, fp
); 
 428     /* read the file information */ 
 429     png_read_info(png_ptr
, info_ptr
); 
 431     /* allocate the memory to hold the image using the fields 
 433     png_color_16 my_background
={ 0, 31, 127, 255, 0 }; 
 435     if (info_ptr
->valid 
& PNG_INFO_bKGD
) 
 437         png_set_background(png_ptr
, &(info_ptr
->background
), 
 438                 PNG_BACKGROUND_GAMMA_FILE
, 1, 1.0); 
 439         if ( info_ptr
->num_palette 
> 0 ) 
 440             bgindex 
= info_ptr
->background
.index
; 
 443         png_set_background(png_ptr
, &my_background
, 
 444                 PNG_BACKGROUND_GAMMA_SCREEN
, 0, 1.0); 
 446         // Added by JACS: guesswork! 
 447         if ( info_ptr
->num_trans 
!= 0 ) 
 448             bgindex 
= info_ptr
->num_trans 
- 1 ; 
 451     /* tell libpng to strip 16 bit depth files down to 8 bits */ 
 452     if (info_ptr
->bit_depth 
== 16) 
 453         png_set_strip_16(png_ptr
); 
 455     int pixel_depth
=(info_ptr
->pixel_depth
<24) ? info_ptr
->pixel_depth
: 24; 
 456     Create(info_ptr
->width
, info_ptr
->height
, pixel_depth
, 
 457             info_ptr
->color_type
); 
 459     if (info_ptr
->num_palette
>0) 
 461         SetPalette((int)info_ptr
->num_palette
, (rgb_color_struct
*)info_ptr
->palette
); 
 464     int row_stride 
= info_ptr
->width 
* ((pixel_depth
+7)>>3); 
 465     //  printf("P = %d D = %d RS= %d ", info_ptr->num_palette, info_ptr->pixel_depth,row_stride); 
 466     //  printf("CT = %d TRS = %d BD= %d ", info_ptr->color_type, info_ptr->valid & PNG_INFO_tRNS,info_ptr->bit_depth); 
 468     byte 
*row_pointers 
= new byte
[row_stride
]; 
 470     /* turn on interlace handling */ 
 472     if (info_ptr
->interlace_type
) 
 473         number_passes 
= png_set_interlace_handling(png_ptr
); 
 476     //  printf("NP = %d ", number_passes); 
 478     // don't use the object to prevent warnings from VC++ about "unportable 
 479     // interaction between setjmp and C++ object destruction" (this is a correct 
 480     // warning, of course!) 
 481     wxPNGReaderIter 
*iter 
= new wxPNGReaderIter(this); 
 482     for (int pass
=0; pass
< number_passes
; pass
++) 
 487             //(unsigned char *)iter.GetRow(); 
 488             if (info_ptr
->interlace_type
)  { 
 490                     iter
->GetRow(row_pointers
, row_stride
); 
 491                 png_read_row(png_ptr
, row_pointers
, NULL
); 
 494                 png_read_row(png_ptr
, row_pointers
, NULL
); 
 496             iter
->SetRow(row_pointers
, row_stride
); 
 498         } while(iter
->PrevRow()); 
 499         //  printf("Y=%d ",y); 
 503     delete[] row_pointers
; 
 505     /* read the rest of the file, getting any additional chunks 
 507     png_read_end(png_ptr
, info_ptr
); 
 509     /* clean up after the read, and free any memory allocated */ 
 510     png_read_destroy(png_ptr
, info_ptr
, (png_info 
*)0); 
 512     /* free the structures */ 
 524 /* write a png file */ 
 526 bool wxPNGReader::SaveFile(wxChar 
* ImageFileName
) 
 529    wxStrcpy(filename
, ImageFileName
); 
 531   wxPNGReaderIter 
iter(this); 
 537   fp 
= fopen(wxConvFile
.cWX2MB(filename
), "wb"); 
 541   /* allocate the necessary structures */ 
 542   png_ptr 
= new (png_struct
); 
 549   info_ptr 
= new (png_info
); 
 557   /* set error handling */ 
 558   if (setjmp(png_ptr
->jmpbuf
)) 
 560     png_write_destroy(png_ptr
); 
 565     /* If we get here, we had a problem reading the file */ 
 568         //png_set_error(ima_png_error, NULL); 
 570 //  printf("writig pg %s ", filename); 
 571    /* initialize the structures */ 
 572   png_info_init(info_ptr
); 
 573   png_write_init(png_ptr
); 
 575   int row_stride 
= GetWidth() * ((GetDepth()+7)>>3); 
 576   /* set up the output control */ 
 577    png_init_io(png_ptr
, fp
); 
 579   /* set the file information here */ 
 580   info_ptr
->width 
= GetWidth(); 
 581   info_ptr
->height 
= GetHeight(); 
 582   info_ptr
->pixel_depth 
= GetDepth(); 
 583   info_ptr
->channels 
= (GetDepth()>8) ? 3: 1; 
 584   info_ptr
->bit_depth 
= GetDepth()/info_ptr
->channels
; 
 585   info_ptr
->color_type 
= GetColorType(); 
 586   info_ptr
->compression_type 
= info_ptr
->filter_type 
= info_ptr
->interlace_type
=0; 
 588   info_ptr
->rowbytes 
= row_stride
; 
 591 // 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); 
 592   /* set the palette if there is one */ 
 593   if ((GetColorType() & COLORTYPE_PALETTE
) && GetPalette()) 
 595 //    printf("writing paleta[%d %d %x]",GetColorType() ,COLORTYPE_PALETTE, GetPalette()); 
 596     info_ptr
->valid 
|= PNG_INFO_PLTE
; 
 597     info_ptr
->palette 
= new png_color
[256]; 
 598     info_ptr
->num_palette 
= 256; 
 599     for (int i
=0; i
<256; i
++) 
 600      GetPalette()->GetRGB(i
, &info_ptr
->palette
[i
].red
, &info_ptr
->palette
[i
].green
, &info_ptr
->palette
[i
].blue
); 
 602 //    printf("Paleta [%d %d %x]",GetColorType() ,COLORTYPE_PALETTE, GetPalette()); 
 605    /* optional significant bit chunk */ 
 606 //   info_ptr->valid |= PNG_INFO_sBIT; 
 607 //   info_ptr->sig_bit = true_bit_depth; 
 609   /* optional gamma chunk */ 
 610 //   info_ptr->valid |= PNG_INFO_gAMA; 
 611 //   info_ptr->gamma = gamma; 
 613   /* other optional chunks */ 
 615    /* write the file information */ 
 616    png_write_info(png_ptr
, info_ptr
); 
 618    /* set up the transformations you want.  Note that these are 
 619       all optional.  Only call them if you want them */ 
 621   /* shift the pixels up to a legal bit depth and fill in 
 622       as appropriate to correctly scale the image */ 
 623 //   png_set_shift(png_ptr, &(info_ptr->sig_bit)); 
 625   /* pack pixels into bytes */ 
 626 //   png_set_packing(png_ptr); 
 628   /* flip bgr pixels to rgb */ 
 629 //   png_set_bgr(png_ptr); 
 631    /* swap bytes of 16 bit files to most significant bit first */ 
 632 //   png_set_swap(png_ptr); 
 634    /* get rid of filler bytes, pack rgb into 3 bytes */ 
 635 //   png_set_rgbx(png_ptr); 
 637 /* If you are only writing one row at a time, this works */ 
 639   byte 
*row_pointers 
= new byte
[row_stride
]; 
 642 //    (unsigned char *)iter.GetRow(); 
 643     iter
.GetRow(row_pointers
, row_stride
); 
 644     png_write_row(png_ptr
, row_pointers
); 
 645   } while(iter
.PrevRow()); 
 647         delete[] row_pointers
; 
 649 /* write the rest of the file */ 
 650    png_write_end(png_ptr
, info_ptr
); 
 652   /* clean up after the write, and free any memory allocated */ 
 653    png_write_destroy(png_ptr
); 
 655    /* if you malloced the palette, free it here */ 
 656    if (info_ptr
->palette
) 
 657     delete[] (info_ptr
->palette
); 
 659   /* free the structures */ 
 670 static int Power(int x
, int y
) 
 674     for ( i 
= 0; i 
< y
; i
++) 
 681 static char hexArray
[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 
 682   'C', 'D', 'E', 'F' }; 
 684 static void DecToHex(int dec
, char *buf
) 
 686   int firstDigit 
= (int)(dec
/16.0); 
 687   int secondDigit 
= (int)(dec 
- (firstDigit
*16.0)); 
 688   buf
[0] = hexArray
[firstDigit
]; 
 689   buf
[1] = hexArray
[secondDigit
]; 
 694 bool wxPNGReader::SaveXPM(wxChar 
*filename
, wxChar 
*name
) 
 698         wxStrcpy(nameStr
, name
); 
 701         wxStrcpy(nameStr
, filename
); 
 702         wxStripExtension(nameStr
); 
 705     if ( GetDepth() > 4 ) 
 707         // Only a depth of 4 and below allowed 
 714     ofstream 
str(wxConvFile
.cWX2MB(filename
)); 
 718     int noColours 
= Power(2, GetDepth()); 
 721     str 
<< "/* XPM */\n"; 
 722     str 
<< "static char * " << nameStr 
<< "_xpm[] = {\n"; 
 723     str 
<< "\"" << GetWidth() << " " << GetHeight() << " " << noColours 
<< " 1\",\n"; 
 726     int base 
= 97 ; // start from 'a' 
 728     unsigned char red
, green
, blue
; 
 731     for ( i 
= 0; i 
< noColours
; i 
++) 
 733         str 
<< "\"" << (char)(base 
+ i
) << "      c #"; 
 734         GetPalette()->GetRGB(i
, &red
, &green
, &blue
); 
 735         DecToHex(red
, hexBuf
); 
 737         DecToHex(green
, hexBuf
); 
 739         DecToHex(blue
, hexBuf
); 
 746     for ( y 
= 0; y 
< GetHeight(); y
++) 
 749         for ( x 
= 0; x 
< GetWidth(); x
++) 
 751             int index 
= GetIndex(x
, y
); 
 752             str 
<< (char)(base 
+ index
) ; 
 763 #include <wx/os2/pnghand.h> 
 765 IMPLEMENT_DYNAMIC_CLASS(wxPNGFileHandler
, wxBitmapHandler
) 
 767 bool wxPNGFileHandler::LoadFile(wxBitmap 
*bitmap
, const wxString
& name
, HPS hPs
, long flags
, 
 768     int desiredWidth
, int desiredHeight
) 
 771     if (reader
.ReadFile(WXSTRINGCAST name
)) 
 773         return reader
.InstantiateBitmap(bitmap
); 
 779 bool wxPNGFileHandler::SaveFile(wxBitmap 
*bitmap
, const wxString
& name
, int type
, const wxPalette 
*pal
)