1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #pragma implementation "image.h"
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
24 #include "../png/png.h"
25 #include "wx/filefn.h"
27 //-----------------------------------------------------------------------------
29 //-----------------------------------------------------------------------------
31 class wxImageRefData
: public wxObjectRefData
36 ~wxImageRefData(void);
40 unsigned char *m_data
;
42 unsigned char m_maskRed
,m_maskGreen
,m_maskBlue
;
46 wxImageRefData::wxImageRefData(void)
50 m_data
= (unsigned char*) NULL
;
58 wxImageRefData::~wxImageRefData(void)
60 if (m_data
) free( m_data
);
63 wxList
wxImage::sm_handlers
;
65 //-----------------------------------------------------------------------------
67 #define M_IMGDATA ((wxImageRefData *)m_refData)
69 #if !USE_SHARED_LIBRARIES
70 IMPLEMENT_DYNAMIC_CLASS(wxImage
, wxObject
)
77 wxImage::wxImage( int width
, int height
)
79 Create( width
, height
);
82 wxImage::wxImage( const wxString
& name
, long type
)
84 LoadFile( name
, type
);
87 wxImage::wxImage( const wxImage
& image
)
92 wxImage::wxImage( const wxImage
* image
)
94 if (image
) Ref(*image
);
97 void wxImage::Create( int width
, int height
)
99 m_refData
= new wxImageRefData();
101 M_IMGDATA
->m_data
= (unsigned char *) malloc( width
*height
*3 );
102 if (M_IMGDATA
->m_data
)
104 for (int l
= 0; l
< width
*height
*3; l
++) M_IMGDATA
->m_data
[l
] = 0;
106 M_IMGDATA
->m_width
= width
;
107 M_IMGDATA
->m_height
= height
;
108 M_IMGDATA
->m_ok
= TRUE
;
116 void wxImage::Destroy()
121 bool wxImage::Ok() const
123 return (M_IMGDATA
&& M_IMGDATA
->m_ok
);
126 char unsigned *wxImage::GetData() const
128 if (!Ok()) return (char unsigned *)NULL
;
130 return M_IMGDATA
->m_data
;
133 void wxImage::SetData( char unsigned *WXUNUSED(data
) )
137 void wxImage::SetMaskColour( unsigned char r
, unsigned char g
, unsigned char b
)
141 M_IMGDATA
->m_maskRed
= r
;
142 M_IMGDATA
->m_maskGreen
= g
;
143 M_IMGDATA
->m_maskBlue
= b
;
144 M_IMGDATA
->m_hasMask
= TRUE
;
147 unsigned char wxImage::GetMaskRed() const
151 return M_IMGDATA
->m_maskRed
;
154 unsigned char wxImage::GetMaskGreen() const
158 return M_IMGDATA
->m_maskGreen
;
161 unsigned char wxImage::GetMaskBlue() const
165 return M_IMGDATA
->m_maskBlue
;
168 void wxImage::SetMask( bool mask
)
172 M_IMGDATA
->m_hasMask
= mask
;
175 bool wxImage::HasMask() const
177 if (!Ok()) return FALSE
;
179 return M_IMGDATA
->m_hasMask
;
182 int wxImage::GetWidth() const
184 return (M_IMGDATA
? M_IMGDATA
->m_width
: 0);
187 int wxImage::GetHeight() const
189 return (M_IMGDATA
? M_IMGDATA
->m_height
: 0);
192 bool wxImage::LoadFile( const wxString
& filename
, long type
)
196 if (!wxFileExists(filename
))
198 wxLogWarning( "Image file does not exist." );
203 m_refData
= new wxImageRefData
;
205 wxImageHandler
*handler
= FindHandler(type
);
209 wxLogWarning( "No image handler for type %d defined.", type
);
214 return handler
->LoadFile( this, filename
);
217 bool wxImage::SaveFile( const wxString
& filename
, int type
)
219 wxImageHandler
*handler
= FindHandler(type
);
223 wxLogWarning( "No image handler for type %d defined.", type
);
228 return handler
->SaveFile( this, filename
);
231 void wxImage::AddHandler( wxImageHandler
*handler
)
233 sm_handlers
.Append( handler
);
236 void wxImage::InsertHandler( wxImageHandler
*handler
)
238 sm_handlers
.Insert( handler
);
241 bool wxImage::RemoveHandler( const wxString
& name
)
243 wxImageHandler
*handler
= FindHandler(name
);
246 sm_handlers
.DeleteObject(handler
);
253 wxImageHandler
*wxImage::FindHandler( const wxString
& name
)
255 wxNode
*node
= sm_handlers
.First();
258 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
259 if (handler
->GetName() == name
) return handler
;
262 return (wxImageHandler
*)NULL
;
265 wxImageHandler
*wxImage::FindHandler( const wxString
& extension
, long bitmapType
)
267 wxNode
*node
= sm_handlers
.First();
270 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
271 if ( handler
->GetExtension() == extension
&&
272 (bitmapType
== -1 || handler
->GetType() == bitmapType
) )
276 return (wxImageHandler
*)NULL
;
279 wxImageHandler
*wxImage::FindHandler( long bitmapType
)
281 wxNode
*node
= sm_handlers
.First();
284 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
285 if (handler
->GetType() == bitmapType
) return handler
;
291 void wxImage::InitStandardHandlers()
293 AddHandler( new wxBMPHandler
);
294 AddHandler( new wxPNGHandler
);
297 void wxImage::CleanUpHandlers()
299 wxNode
*node
= sm_handlers
.First();
302 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
303 wxNode
*next
= node
->Next();
310 //-----------------------------------------------------------------------------
312 //-----------------------------------------------------------------------------
314 #if !USE_SHARED_LIBRARIES
315 IMPLEMENT_DYNAMIC_CLASS(wxImageHandler
,wxObject
)
318 bool wxImageHandler::LoadFile( wxImage
*WXUNUSED(image
), const wxString
& WXUNUSED(name
) )
323 bool wxImageHandler::SaveFile( wxImage
*WXUNUSED(image
), const wxString
& WXUNUSED(name
) )
328 //-----------------------------------------------------------------------------
330 //-----------------------------------------------------------------------------
332 #if !USE_SHARED_LIBRARIES
333 IMPLEMENT_DYNAMIC_CLASS(wxPNGHandler
,wxImageHandler
)
336 bool wxPNGHandler::LoadFile( wxImage
*image
, const wxString
& name
)
341 unsigned char *ptr
, **lines
, *ptr2
;
342 int transp
,bit_depth
,color_type
,interlace_type
;
343 png_uint_32 width
, height
;
349 png_ptr
= png_create_read_struct( PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
);
350 if (!png_ptr
) return FALSE
;
352 info_ptr
= png_create_info_struct( png_ptr
);
355 png_destroy_read_struct( &png_ptr
, NULL
, NULL
);
359 if (setjmp(png_ptr
->jmpbuf
))
361 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
365 if (info_ptr
->color_type
== PNG_COLOR_TYPE_RGB_ALPHA
)
367 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
371 f
= fopen( name
, "rb" );
372 png_init_io( png_ptr
, f
);
374 png_read_info( png_ptr
, info_ptr
);
375 png_get_IHDR( png_ptr
, info_ptr
, &width
, &height
, &bit_depth
, &color_type
, &interlace_type
, NULL
, NULL
);
377 if (color_type
== PNG_COLOR_TYPE_PALETTE
) png_set_expand( png_ptr
);
379 png_set_strip_16( png_ptr
);
380 png_set_packing( png_ptr
);
381 if (png_get_valid( png_ptr
, info_ptr
, PNG_INFO_tRNS
)) png_set_expand( png_ptr
);
382 png_set_filler( png_ptr
, 0xff, PNG_FILLER_AFTER
);
384 image
->Create( width
, height
);
388 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
392 lines
= (unsigned char **)malloc( height
* sizeof(unsigned char *) );
396 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
400 for (i
= 0; i
< height
; i
++)
402 if ((lines
[i
] = (unsigned char *)malloc(width
* (sizeof(unsigned char) * 4))) == NULL
)
405 for (unsigned int n
= 0; n
< i
; n
++) free( lines
[n
] );
407 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
412 png_read_image( png_ptr
, lines
);
413 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
414 ptr
= image
->GetData();
415 if ((color_type
== PNG_COLOR_TYPE_GRAY
) ||
416 (color_type
== PNG_COLOR_TYPE_GRAY_ALPHA
))
418 for (unsigned int y
= 0; y
< height
; y
++)
421 for (unsigned int x
= 0; x
< width
; x
++)
423 unsigned char r
= *ptr2
++;
424 unsigned char a
= *ptr2
++;
443 for (unsigned int y
= 0; y
< height
; y
++)
446 for (unsigned int x
= 0; x
< width
; x
++)
448 unsigned char r
= *ptr2
++;
449 unsigned char g
= *ptr2
++;
450 unsigned char b
= *ptr2
++;
451 unsigned char a
= *ptr2
++;
461 if ((r
== 255) && (g
== 0) && (b
== 255)) r
= 254;
469 for (i
= 0; i
< height
; i
++) free( lines
[i
] );
472 image
->SetMaskColour( 255, 0, 255 );
474 image
->SetMask( FALSE
);
480 bool wxPNGHandler::SaveFile( wxImage
*image
, const wxString
& name
)
482 FILE *f
= fopen( name
, "wb" );
485 png_structp png_ptr
= png_create_write_struct( PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
);
492 png_infop info_ptr
= png_create_info_struct(png_ptr
);
493 if (info_ptr
== NULL
)
496 png_destroy_write_struct( &png_ptr
, (png_infopp
)NULL
);
500 if (setjmp(png_ptr
->jmpbuf
))
503 png_destroy_write_struct( &png_ptr
, (png_infopp
)NULL
);
507 png_init_io( png_ptr
, f
);
508 png_set_IHDR( png_ptr
, info_ptr
, image
->GetWidth(), image
->GetHeight(), 8,
509 PNG_COLOR_TYPE_RGB_ALPHA
, PNG_INTERLACE_NONE
,
510 PNG_COMPRESSION_TYPE_BASE
, PNG_FILTER_TYPE_BASE
);
517 png_set_sBIT( png_ptr
, info_ptr
, &sig_bit
);
518 png_write_info( png_ptr
, info_ptr
);
519 png_set_shift( png_ptr
, &sig_bit
);
520 png_set_packing( png_ptr
);
522 unsigned char *data
= (unsigned char *)malloc( image
->GetWidth()*4 );
526 png_destroy_write_struct( &png_ptr
, (png_infopp
)NULL
);
530 for (int y
= 0; y
< image
->GetHeight(); y
++)
532 unsigned char *ptr
= image
->GetData() + (y
* image
->GetWidth() * 3);
533 for (int x
= 0; x
< image
->GetWidth(); x
++)
535 data
[(x
<< 2) + 0] = *ptr
++;
536 data
[(x
<< 2) + 1] = *ptr
++;
537 data
[(x
<< 2) + 2] = *ptr
++;
538 if ((data
[(x
<< 2) + 0] == image
->GetMaskRed()) &&
539 (data
[(x
<< 2) + 1] == image
->GetMaskGreen()) &&
540 (data
[(x
<< 2) + 2] == image
->GetMaskBlue()))
541 data
[(x
<< 2) + 3] = 0;
543 data
[(x
<< 2) + 3] = 255;
545 png_bytep row_ptr
= data
;
546 png_write_rows( png_ptr
, &row_ptr
, 1 );
549 png_write_end( png_ptr
, info_ptr
);
550 png_destroy_write_struct( &png_ptr
, (png_infopp
)NULL
);
557 //-----------------------------------------------------------------------------
559 //-----------------------------------------------------------------------------
561 #if !USE_SHARED_LIBRARIES
562 IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler
,wxImageHandler
)
565 bool wxBMPHandler::LoadFile( wxImage
*image
, const wxString
& name
)
568 unsigned char *data
, *ptr
;
569 int done
, i
, bpp
, planes
, comp
, ncolors
, line
, column
,
570 linesize
, linepos
, rshift
= 0, gshift
= 0, bshift
= 0;
573 long int dbuf
[4], dword
, rmask
= 0, gmask
= 0, bmask
= 0, offset
,
578 unsigned char r
, g
, b
;
585 #define BI_BITFIELDS 3
590 file
= fopen(name
, "r");
596 * Reading the bmp header
599 fread(&bbuf
, 1, 2, file
);
601 fread(dbuf
, 4, 4, file
);
606 fread(dbuf
, 4, 2, file
);
607 int width
= (int)dbuf
[0];
608 int height
= (int)dbuf
[1];
611 fprintf(stderr
, "IMLIB ERROR: Image width > 32767 pixels for file\n");
617 fprintf(stderr
, "IMLIB ERROR: Image height > 32767 pixels for file\n");
621 fread(&word
, 2, 1, file
);
623 fread(&word
, 2, 1, file
);
625 if (bpp
!= 1 && bpp
!= 4 && bpp
!= 8 && bpp
&& 16 && bpp
!= 24 && bpp
!= 32)
627 fprintf(stderr
, "IMLIB ERROR: unknown bitdepth in file\n");
631 fread(dbuf
, 4, 4, file
);
633 if (comp
!= BI_RGB
&& comp
!= BI_RLE4
&& comp
!= BI_RLE8
&& comp
!= BI_BITFIELDS
)
635 fprintf(stderr
, "IMLIB ERROR: unknown encoding in Windows BMP file\n");
639 fread(dbuf
, 4, 2, file
);
640 ncolors
= (int)dbuf
[0];
643 /* some more sanity checks */
644 if (((comp
== BI_RLE4
) && (bpp
!= 4)) || ((comp
== BI_RLE8
) && (bpp
!= 8)) || ((comp
== BI_BITFIELDS
) && (bpp
!= 16 && bpp
!= 32)))
646 fprintf(stderr
, "IMLIB ERROR: encoding of BMP doesn't match bitdepth\n");
652 cmap
= (struct _cmap
*)malloc(sizeof(struct _cmap
) * ncolors
);
656 fprintf(stderr
, "IMLIB ERROR: Cannot allocate RAM for color map in BMP file\n");
664 image
->Create( width
, height
);
665 ptr
= image
->GetData();
668 fprintf(stderr
, "IMLIB ERROR: Cannot allocate RAM for RGB data in file\n");
676 * Reading the palette, if it exists.
678 if (bpp
< 16 && ncolors
!= 0)
680 for (i
= 0; i
< ncolors
; i
++)
682 fread(bbuf
, 1, 4, file
);
688 else if (bpp
== 16 || bpp
== 32)
690 if (comp
== BI_BITFIELDS
)
694 fread(dbuf
, 4, 3, file
);
698 /* find shift amount.. ugly, but i can't think of a better way */
699 for (bit
= 0; bit
< bpp
; bit
++)
701 if (bmask
& (1 << bit
))
703 if (gmask
& (1 << bit
))
705 if (rmask
& (1 << bit
))
730 * REading the image data
732 fseek(file
, offset
, SEEK_SET
);
735 /* set the whole image to the background color */
736 if (bpp
< 16 && (comp
== BI_RLE4
|| comp
== BI_RLE8
))
738 for (i
= 0; i
< width
* height
; i
++)
748 #define poffset (line * width * 3 + column * 3)
751 * BMPs are stored upside down... hmmmmmmmmmm....
754 linesize
= ((width
* bpp
+ 31) / 32) * 4;
755 for (line
= (height
- 1); line
>= 0; line
--)
758 for (column
= 0; column
< width
;)
770 for (bit
= 0; bit
< 8; bit
++)
772 index
= ((byte
& (0x80 >> bit
)) ? 1 : 0);
773 ptr
[poffset
] = cmap
[index
].r
;
774 ptr
[poffset
+ 1] = cmap
[index
].g
;
775 ptr
[poffset
+ 2] = cmap
[index
].b
;
783 fprintf(stderr
, "can't deal with 4bit encoded yet.\n");
792 for (nibble
= 0; nibble
< 2; nibble
++)
794 index
= ((byte
& (0xF0 >> nibble
* 4)) >> (!nibble
* 4));
797 ptr
[poffset
] = cmap
[index
].r
;
798 ptr
[poffset
+ 1] = cmap
[index
].g
;
799 ptr
[poffset
+ 2] = cmap
[index
].b
;
816 /* column = width; */
827 linepos
= column
* bpp
/ 8;
835 for (i
= 0; i
< absolute
; i
++)
839 ptr
[poffset
] = cmap
[byte
].r
;
840 ptr
[poffset
+ 1] = cmap
[byte
].g
;
841 ptr
[poffset
+ 2] = cmap
[byte
].b
;
850 for (i
= 0; i
< first
; i
++)
852 ptr
[poffset
] = cmap
[byte
].r
;
853 ptr
[poffset
+ 1] = cmap
[byte
].g
;
854 ptr
[poffset
+ 2] = cmap
[byte
].b
;
862 ptr
[poffset
] = cmap
[byte
].r
;
863 ptr
[poffset
+ 1] = cmap
[byte
].g
;
864 ptr
[poffset
+ 2] = cmap
[byte
].b
;
872 linepos
+= fread(&bbuf
, 1, 3, file
);
873 ptr
[poffset
] = (unsigned char)bbuf
[2];
874 ptr
[poffset
+ 1] = (unsigned char)bbuf
[1];
875 ptr
[poffset
+ 2] = (unsigned char)bbuf
[0];
882 linepos
+= fread(&word
, 2, 1, file
);
883 temp
= (word
& rmask
) >> rshift
;
885 temp
= (word
& gmask
) >> gshift
;
886 ptr
[poffset
+ 1] = temp
;
887 temp
= (word
& bmask
) >> gshift
;
888 ptr
[poffset
+ 2] = temp
;
895 linepos
+= fread(&dword
, 4, 1, file
);
896 temp
= (dword
& rmask
) >> rshift
;
898 temp
= (dword
& gmask
) >> gshift
;
899 ptr
[poffset
+ 1] = temp
;
900 temp
= (dword
& bmask
) >> bshift
;
901 ptr
[poffset
+ 2] = temp
;
905 while ((linepos
< linesize
) && (comp
!= 1) && (comp
!= 2))
907 int temp
= fread(&byte
, 1, 1, file
);
914 if (cmap
) free(cmap
);
916 image
->SetMask( FALSE
);