1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #pragma implementation "image.h"
17 #include "../png/png.h"
19 //-----------------------------------------------------------------------------
21 //-----------------------------------------------------------------------------
23 class wxImageRefData
: public wxObjectRefData
28 ~wxImageRefData(void);
32 unsigned char *m_data
;
34 unsigned char m_maskRed
,m_maskGreen
,m_maskBlue
;
38 wxImageRefData::wxImageRefData(void)
42 m_data
= (unsigned char*) NULL
;
50 wxImageRefData::~wxImageRefData(void)
52 if (m_data
) free( m_data
);
55 wxList
wxImage::sm_handlers
;
57 //-----------------------------------------------------------------------------
59 #define M_IMGDATA ((wxImageRefData *)m_refData)
61 #if !USE_SHARED_LIBRARIES
62 IMPLEMENT_DYNAMIC_CLASS(wxImage
, wxObject
)
69 wxImage::wxImage( int width
, int height
)
71 Create( width
, height
);
74 wxImage::wxImage( const wxString
& name
, long type
)
76 LoadFile( name
, type
);
79 wxImage::wxImage( const wxImage
& image
)
84 wxImage::wxImage( const wxImage
* image
)
86 if (image
) Ref(*image
);
89 void wxImage::Create( int width
, int height
)
91 m_refData
= new wxImageRefData();
93 M_IMGDATA
->m_data
= (unsigned char *) malloc( width
*height
*3 );
94 if (M_IMGDATA
->m_data
)
96 for (int l
= 0; l
< width
*height
*3; l
++) M_IMGDATA
->m_data
[l
] = 0;
98 M_IMGDATA
->m_width
= width
;
99 M_IMGDATA
->m_height
= height
;
100 M_IMGDATA
->m_ok
= TRUE
;
108 void wxImage::Destroy()
113 bool wxImage::Ok() const
115 return (M_IMGDATA
&& M_IMGDATA
->m_ok
);
118 char unsigned *wxImage::GetData() const
120 if (!Ok()) return (char unsigned *)NULL
;
122 return M_IMGDATA
->m_data
;
125 void wxImage::SetData( char unsigned *WXUNUSED(data
) )
129 void wxImage::SetMaskColour( unsigned char r
, unsigned char g
, unsigned char b
)
133 M_IMGDATA
->m_maskRed
= r
;
134 M_IMGDATA
->m_maskGreen
= g
;
135 M_IMGDATA
->m_maskBlue
= b
;
136 M_IMGDATA
->m_hasMask
= TRUE
;
139 unsigned char wxImage::GetMaskRed() const
143 return M_IMGDATA
->m_maskRed
;
146 unsigned char wxImage::GetMaskGreen() const
150 return M_IMGDATA
->m_maskGreen
;
153 unsigned char wxImage::GetMaskBlue() const
157 return M_IMGDATA
->m_maskBlue
;
160 void wxImage::SetMask( bool mask
)
164 M_IMGDATA
->m_hasMask
= mask
;
167 bool wxImage::HasMask() const
169 if (!Ok()) return FALSE
;
171 return M_IMGDATA
->m_hasMask
;
174 int wxImage::GetWidth() const
176 return (M_IMGDATA
? M_IMGDATA
->m_width
: 0);
179 int wxImage::GetHeight() const
181 return (M_IMGDATA
? M_IMGDATA
->m_height
: 0);
184 bool wxImage::LoadFile( const wxString
& filename
, long type
)
188 m_refData
= new wxImageRefData
;
190 wxImageHandler
*handler
= FindHandler(type
);
194 wxLogWarning( "No image handler for type %d defined.", type
);
199 return handler
->LoadFile( this, filename
);
202 bool wxImage::SaveFile( const wxString
& filename
, int type
)
204 wxImageHandler
*handler
= FindHandler(type
);
208 wxLogWarning( "No image handler for type %d defined.", type
);
213 return handler
->SaveFile( this, filename
);
216 void wxImage::AddHandler( wxImageHandler
*handler
)
218 sm_handlers
.Append( handler
);
221 void wxImage::InsertHandler( wxImageHandler
*handler
)
223 sm_handlers
.Insert( handler
);
226 bool wxImage::RemoveHandler( const wxString
& name
)
228 wxImageHandler
*handler
= FindHandler(name
);
231 sm_handlers
.DeleteObject(handler
);
238 wxImageHandler
*wxImage::FindHandler( const wxString
& name
)
240 wxNode
*node
= sm_handlers
.First();
243 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
244 if (handler
->GetName() == name
) return handler
;
247 return (wxImageHandler
*)NULL
;
250 wxImageHandler
*wxImage::FindHandler( const wxString
& extension
, long bitmapType
)
252 wxNode
*node
= sm_handlers
.First();
255 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
256 if ( handler
->GetExtension() == extension
&&
257 (bitmapType
== -1 || handler
->GetType() == bitmapType
) )
261 return (wxImageHandler
*)NULL
;
264 wxImageHandler
*wxImage::FindHandler( long bitmapType
)
266 wxNode
*node
= sm_handlers
.First();
269 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
270 if (handler
->GetType() == bitmapType
) return handler
;
276 void wxImage::CleanUpHandlers()
278 wxNode
*node
= sm_handlers
.First();
281 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
282 wxNode
*next
= node
->Next();
289 //-----------------------------------------------------------------------------
291 //-----------------------------------------------------------------------------
293 #if !USE_SHARED_LIBRARIES
294 IMPLEMENT_DYNAMIC_CLASS(wxImageHandler
,wxObject
)
297 bool wxImageHandler::LoadFile( wxImage
*WXUNUSED(image
), const wxString
& WXUNUSED(name
) )
302 bool wxImageHandler::SaveFile( wxImage
*WXUNUSED(image
), const wxString
& WXUNUSED(name
) )
307 //-----------------------------------------------------------------------------
309 //-----------------------------------------------------------------------------
311 #if !USE_SHARED_LIBRARIES
312 IMPLEMENT_DYNAMIC_CLASS(wxPNGHandler
,wxImageHandler
)
315 bool wxPNGHandler::LoadFile( wxImage
*image
, const wxString
& name
)
320 unsigned char *ptr
, **lines
, *ptr2
;
321 int transp
,bit_depth
,color_type
,interlace_type
;
322 png_uint_32 width
, height
;
327 png_ptr
= png_create_read_struct( PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
);
328 if (!png_ptr
) return FALSE
;
330 info_ptr
= png_create_info_struct( png_ptr
);
333 png_destroy_read_struct( &png_ptr
, NULL
, NULL
);
337 if (setjmp(png_ptr
->jmpbuf
))
339 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
343 if (info_ptr
->color_type
== PNG_COLOR_TYPE_RGB_ALPHA
)
345 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
349 f
= fopen( name
, "rb" );
350 png_init_io( png_ptr
, f
);
352 png_read_info( png_ptr
, info_ptr
);
353 png_get_IHDR( png_ptr
, info_ptr
, &width
, &height
, &bit_depth
, &color_type
, &interlace_type
, NULL
, NULL
);
355 if (color_type
== PNG_COLOR_TYPE_PALETTE
) png_set_expand( png_ptr
);
357 png_set_strip_16( png_ptr
);
358 png_set_packing( png_ptr
);
359 if (png_get_valid( png_ptr
, info_ptr
, PNG_INFO_tRNS
)) png_set_expand( png_ptr
);
360 png_set_filler( png_ptr
, 0xff, PNG_FILLER_AFTER
);
362 image
->Create( width
, height
);
366 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
370 lines
= (unsigned char **)malloc( height
* sizeof(unsigned char *) );
374 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
378 for (unsigned int i
= 0; i
< height
; i
++)
380 if ((lines
[i
] = (unsigned char *)malloc(width
* (sizeof(unsigned char) * 4))) == NULL
)
383 for (unsigned int n
= 0; n
< i
; n
++) free( lines
[n
] );
385 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
390 png_read_image( png_ptr
, lines
);
391 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
392 ptr
= image
->GetData();
393 if ((color_type
== PNG_COLOR_TYPE_GRAY
) ||
394 (color_type
== PNG_COLOR_TYPE_GRAY_ALPHA
))
396 for (unsigned int y
= 0; y
< height
; y
++)
399 for (unsigned int x
= 0; x
< width
; x
++)
401 unsigned char r
= *ptr2
++;
402 unsigned char a
= *ptr2
++;
421 for (unsigned int y
= 0; y
< height
; y
++)
424 for (unsigned int x
= 0; x
< width
; x
++)
426 unsigned char r
= *ptr2
++;
427 unsigned char g
= *ptr2
++;
428 unsigned char b
= *ptr2
++;
429 unsigned char a
= *ptr2
++;
439 if ((r
== 255) && (g
== 0) && (b
== 255)) r
= 254;
447 for (unsigned int i
= 0; i
< height
; i
++) free( lines
[i
] );
450 image
->SetMaskColour( 255, 0, 255 );
452 image
->SetMask( FALSE
);
458 bool wxPNGHandler::SaveFile( wxImage
*image
, const wxString
& name
)
460 FILE *f
= fopen( name
, "wb" );
463 png_structp png_ptr
= png_create_write_struct( PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
);
470 png_infop info_ptr
= png_create_info_struct(png_ptr
);
471 if (info_ptr
== NULL
)
474 png_destroy_write_struct( &png_ptr
, (png_infopp
)NULL
);
478 if (setjmp(png_ptr
->jmpbuf
))
481 png_destroy_write_struct( &png_ptr
, (png_infopp
)NULL
);
485 png_init_io( png_ptr
, f
);
486 png_set_IHDR( png_ptr
, info_ptr
, image
->GetWidth(), image
->GetHeight(), 8,
487 PNG_COLOR_TYPE_RGB_ALPHA
, PNG_INTERLACE_NONE
,
488 PNG_COMPRESSION_TYPE_BASE
, PNG_FILTER_TYPE_BASE
);
495 png_set_sBIT( png_ptr
, info_ptr
, &sig_bit
);
496 png_write_info( png_ptr
, info_ptr
);
497 png_set_shift( png_ptr
, &sig_bit
);
498 png_set_packing( png_ptr
);
500 unsigned char *data
= (unsigned char *)malloc( image
->GetWidth()*4 );
504 png_destroy_write_struct( &png_ptr
, (png_infopp
)NULL
);
508 for (int y
= 0; y
< image
->GetHeight(); y
++)
510 unsigned char *ptr
= image
->GetData() + (y
* image
->GetWidth() * 3);
511 for (int x
= 0; x
< image
->GetWidth(); x
++)
513 data
[(x
<< 2) + 0] = *ptr
++;
514 data
[(x
<< 2) + 1] = *ptr
++;
515 data
[(x
<< 2) + 2] = *ptr
++;
516 if ((data
[(x
<< 2) + 0] == image
->GetMaskRed()) &&
517 (data
[(x
<< 2) + 1] == image
->GetMaskGreen()) &&
518 (data
[(x
<< 2) + 2] == image
->GetMaskBlue()))
519 data
[(x
<< 2) + 3] = 0;
521 data
[(x
<< 2) + 3] = 255;
523 png_bytep row_ptr
= data
;
524 png_write_rows( png_ptr
, &row_ptr
, 1 );
527 png_write_end( png_ptr
, info_ptr
);
528 png_destroy_write_struct( &png_ptr
, (png_infopp
)NULL
);
535 //-----------------------------------------------------------------------------
537 //-----------------------------------------------------------------------------
539 #if !USE_SHARED_LIBRARIES
540 IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler
,wxImageHandler
)
543 bool wxBMPHandler::LoadFile( wxImage
*image
, const wxString
& name
)
546 unsigned char *data
, *ptr
;
547 int done
, i
, bpp
, planes
, comp
, ncolors
, line
, column
,
548 linesize
, linepos
, rshift
= 0, gshift
= 0, bshift
= 0;
551 long int dbuf
[4], dword
, rmask
= 0, gmask
= 0, bmask
= 0, offset
,
556 unsigned char r
, g
, b
;
563 #define BI_BITFIELDS 3
567 file
= fopen(name
, "r");
573 * Reading the bmp header
576 fread(&bbuf
, 1, 2, file
);
578 fread(dbuf
, 4, 4, file
);
583 fread(dbuf
, 4, 2, file
);
584 int width
= (int)dbuf
[0];
585 int height
= (int)dbuf
[1];
588 fprintf(stderr
, "IMLIB ERROR: Image width > 32767 pixels for file\n");
594 fprintf(stderr
, "IMLIB ERROR: Image height > 32767 pixels for file\n");
598 fread(&word
, 2, 1, file
);
600 fread(&word
, 2, 1, file
);
602 if (bpp
!= 1 && bpp
!= 4 && bpp
!= 8 && bpp
&& 16 && bpp
!= 24 && bpp
!= 32)
604 fprintf(stderr
, "IMLIB ERROR: unknown bitdepth in file\n");
608 fread(dbuf
, 4, 4, file
);
610 if (comp
!= BI_RGB
&& comp
!= BI_RLE4
&& comp
!= BI_RLE8
&& comp
!= BI_BITFIELDS
)
612 fprintf(stderr
, "IMLIB ERROR: unknown encoding in Windows BMP file\n");
616 fread(dbuf
, 4, 2, file
);
617 ncolors
= (int)dbuf
[0];
620 /* some more sanity checks */
621 if (((comp
== BI_RLE4
) && (bpp
!= 4)) || ((comp
== BI_RLE8
) && (bpp
!= 8)) || ((comp
== BI_BITFIELDS
) && (bpp
!= 16 && bpp
!= 32)))
623 fprintf(stderr
, "IMLIB ERROR: encoding of BMP doesn't match bitdepth\n");
629 cmap
= (struct _cmap
*)malloc(sizeof(struct _cmap
) * ncolors
);
633 fprintf(stderr
, "IMLIB ERROR: Cannot allocate RAM for color map in BMP file\n");
641 image
->Create( width
, height
);
642 ptr
= image
->GetData();
645 fprintf(stderr
, "IMLIB ERROR: Cannot allocate RAM for RGB data in file\n");
653 * Reading the palette, if it exists.
655 if (bpp
< 16 && ncolors
!= 0)
657 for (i
= 0; i
< ncolors
; i
++)
659 fread(bbuf
, 1, 4, file
);
665 else if (bpp
== 16 || bpp
== 32)
667 if (comp
== BI_BITFIELDS
)
671 fread(dbuf
, 4, 3, file
);
675 /* find shift amount.. ugly, but i can't think of a better way */
676 for (bit
= 0; bit
< bpp
; bit
++)
678 if (bmask
& (1 << bit
))
680 if (gmask
& (1 << bit
))
682 if (rmask
& (1 << bit
))
707 * REading the image data
709 fseek(file
, offset
, SEEK_SET
);
712 /* set the whole image to the background color */
713 if (bpp
< 16 && (comp
== BI_RLE4
|| comp
== BI_RLE8
))
715 for (i
= 0; i
< width
* height
; i
++)
725 #define poffset (line * width * 3 + column * 3)
728 * BMPs are stored upside down... hmmmmmmmmmm....
731 linesize
= ((width
* bpp
+ 31) / 32) * 4;
732 for (line
= (height
- 1); line
>= 0; line
--)
735 for (column
= 0; column
< width
;)
747 for (bit
= 0; bit
< 8; bit
++)
749 index
= ((byte
& (0x80 >> bit
)) ? 1 : 0);
750 ptr
[poffset
] = cmap
[index
].r
;
751 ptr
[poffset
+ 1] = cmap
[index
].g
;
752 ptr
[poffset
+ 2] = cmap
[index
].b
;
760 fprintf(stderr
, "can't deal with 4bit encoded yet.\n");
769 for (nibble
= 0; nibble
< 2; nibble
++)
771 index
= ((byte
& (0xF0 >> nibble
* 4)) >> (!nibble
* 4));
774 ptr
[poffset
] = cmap
[index
].r
;
775 ptr
[poffset
+ 1] = cmap
[index
].g
;
776 ptr
[poffset
+ 2] = cmap
[index
].b
;
793 /* column = width; */
804 linepos
= column
* bpp
/ 8;
812 for (i
= 0; i
< absolute
; i
++)
816 ptr
[poffset
] = cmap
[byte
].r
;
817 ptr
[poffset
+ 1] = cmap
[byte
].g
;
818 ptr
[poffset
+ 2] = cmap
[byte
].b
;
827 for (i
= 0; i
< first
; i
++)
829 ptr
[poffset
] = cmap
[byte
].r
;
830 ptr
[poffset
+ 1] = cmap
[byte
].g
;
831 ptr
[poffset
+ 2] = cmap
[byte
].b
;
839 ptr
[poffset
] = cmap
[byte
].r
;
840 ptr
[poffset
+ 1] = cmap
[byte
].g
;
841 ptr
[poffset
+ 2] = cmap
[byte
].b
;
849 linepos
+= fread(&bbuf
, 1, 3, file
);
850 ptr
[poffset
] = (unsigned char)bbuf
[2];
851 ptr
[poffset
+ 1] = (unsigned char)bbuf
[1];
852 ptr
[poffset
+ 2] = (unsigned char)bbuf
[0];
859 linepos
+= fread(&word
, 2, 1, file
);
860 temp
= (word
& rmask
) >> rshift
;
862 temp
= (word
& gmask
) >> gshift
;
863 ptr
[poffset
+ 1] = temp
;
864 temp
= (word
& bmask
) >> gshift
;
865 ptr
[poffset
+ 2] = temp
;
872 linepos
+= fread(&dword
, 4, 1, file
);
873 temp
= (dword
& rmask
) >> rshift
;
875 temp
= (dword
& gmask
) >> gshift
;
876 ptr
[poffset
+ 1] = temp
;
877 temp
= (dword
& bmask
) >> bshift
;
878 ptr
[poffset
+ 2] = temp
;
882 while ((linepos
< linesize
) && (comp
!= 1) && (comp
!= 2))
884 int temp
= fread(&byte
, 1, 1, file
);
891 if (cmap
) free(cmap
);
893 image
->SetMask( FALSE
);