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"
26 //-----------------------------------------------------------------------------
28 //-----------------------------------------------------------------------------
30 class wxImageRefData
: public wxObjectRefData
35 ~wxImageRefData(void);
39 unsigned char *m_data
;
41 unsigned char m_maskRed
,m_maskGreen
,m_maskBlue
;
45 wxImageRefData::wxImageRefData(void)
49 m_data
= (unsigned char*) NULL
;
57 wxImageRefData::~wxImageRefData(void)
59 if (m_data
) free( m_data
);
62 wxList
wxImage::sm_handlers
;
64 //-----------------------------------------------------------------------------
66 #define M_IMGDATA ((wxImageRefData *)m_refData)
68 #if !USE_SHARED_LIBRARIES
69 IMPLEMENT_DYNAMIC_CLASS(wxImage
, wxObject
)
76 wxImage::wxImage( int width
, int height
)
78 Create( width
, height
);
81 wxImage::wxImage( const wxString
& name
, long type
)
83 LoadFile( name
, type
);
86 wxImage::wxImage( const wxImage
& image
)
91 wxImage::wxImage( const wxImage
* image
)
93 if (image
) Ref(*image
);
96 void wxImage::Create( int width
, int height
)
98 m_refData
= new wxImageRefData();
100 M_IMGDATA
->m_data
= (unsigned char *) malloc( width
*height
*3 );
101 if (M_IMGDATA
->m_data
)
103 for (int l
= 0; l
< width
*height
*3; l
++) M_IMGDATA
->m_data
[l
] = 0;
105 M_IMGDATA
->m_width
= width
;
106 M_IMGDATA
->m_height
= height
;
107 M_IMGDATA
->m_ok
= TRUE
;
115 void wxImage::Destroy()
120 bool wxImage::Ok() const
122 return (M_IMGDATA
&& M_IMGDATA
->m_ok
);
125 char unsigned *wxImage::GetData() const
127 if (!Ok()) return (char unsigned *)NULL
;
129 return M_IMGDATA
->m_data
;
132 void wxImage::SetData( char unsigned *WXUNUSED(data
) )
136 void wxImage::SetMaskColour( unsigned char r
, unsigned char g
, unsigned char b
)
140 M_IMGDATA
->m_maskRed
= r
;
141 M_IMGDATA
->m_maskGreen
= g
;
142 M_IMGDATA
->m_maskBlue
= b
;
143 M_IMGDATA
->m_hasMask
= TRUE
;
146 unsigned char wxImage::GetMaskRed() const
150 return M_IMGDATA
->m_maskRed
;
153 unsigned char wxImage::GetMaskGreen() const
157 return M_IMGDATA
->m_maskGreen
;
160 unsigned char wxImage::GetMaskBlue() const
164 return M_IMGDATA
->m_maskBlue
;
167 void wxImage::SetMask( bool mask
)
171 M_IMGDATA
->m_hasMask
= mask
;
174 bool wxImage::HasMask() const
176 if (!Ok()) return FALSE
;
178 return M_IMGDATA
->m_hasMask
;
181 int wxImage::GetWidth() const
183 return (M_IMGDATA
? M_IMGDATA
->m_width
: 0);
186 int wxImage::GetHeight() const
188 return (M_IMGDATA
? M_IMGDATA
->m_height
: 0);
191 bool wxImage::LoadFile( const wxString
& filename
, long type
)
195 m_refData
= new wxImageRefData
;
197 wxImageHandler
*handler
= FindHandler(type
);
201 wxLogWarning( "No image handler for type %d defined.", type
);
206 return handler
->LoadFile( this, filename
);
209 bool wxImage::SaveFile( const wxString
& filename
, int type
)
211 wxImageHandler
*handler
= FindHandler(type
);
215 wxLogWarning( "No image handler for type %d defined.", type
);
220 return handler
->SaveFile( this, filename
);
223 void wxImage::AddHandler( wxImageHandler
*handler
)
225 sm_handlers
.Append( handler
);
228 void wxImage::InsertHandler( wxImageHandler
*handler
)
230 sm_handlers
.Insert( handler
);
233 bool wxImage::RemoveHandler( const wxString
& name
)
235 wxImageHandler
*handler
= FindHandler(name
);
238 sm_handlers
.DeleteObject(handler
);
245 wxImageHandler
*wxImage::FindHandler( const wxString
& name
)
247 wxNode
*node
= sm_handlers
.First();
250 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
251 if (handler
->GetName() == name
) return handler
;
254 return (wxImageHandler
*)NULL
;
257 wxImageHandler
*wxImage::FindHandler( const wxString
& extension
, long bitmapType
)
259 wxNode
*node
= sm_handlers
.First();
262 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
263 if ( handler
->GetExtension() == extension
&&
264 (bitmapType
== -1 || handler
->GetType() == bitmapType
) )
268 return (wxImageHandler
*)NULL
;
271 wxImageHandler
*wxImage::FindHandler( long bitmapType
)
273 wxNode
*node
= sm_handlers
.First();
276 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
277 if (handler
->GetType() == bitmapType
) return handler
;
283 void wxImage::CleanUpHandlers()
285 wxNode
*node
= sm_handlers
.First();
288 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
289 wxNode
*next
= node
->Next();
296 //-----------------------------------------------------------------------------
298 //-----------------------------------------------------------------------------
300 #if !USE_SHARED_LIBRARIES
301 IMPLEMENT_DYNAMIC_CLASS(wxImageHandler
,wxObject
)
304 bool wxImageHandler::LoadFile( wxImage
*WXUNUSED(image
), const wxString
& WXUNUSED(name
) )
309 bool wxImageHandler::SaveFile( wxImage
*WXUNUSED(image
), const wxString
& WXUNUSED(name
) )
314 //-----------------------------------------------------------------------------
316 //-----------------------------------------------------------------------------
318 #if !USE_SHARED_LIBRARIES
319 IMPLEMENT_DYNAMIC_CLASS(wxPNGHandler
,wxImageHandler
)
322 bool wxPNGHandler::LoadFile( wxImage
*image
, const wxString
& name
)
327 unsigned char *ptr
, **lines
, *ptr2
;
328 int transp
,bit_depth
,color_type
,interlace_type
;
329 png_uint_32 width
, height
;
335 png_ptr
= png_create_read_struct( PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
);
336 if (!png_ptr
) return FALSE
;
338 info_ptr
= png_create_info_struct( png_ptr
);
341 png_destroy_read_struct( &png_ptr
, NULL
, NULL
);
345 if (setjmp(png_ptr
->jmpbuf
))
347 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
351 if (info_ptr
->color_type
== PNG_COLOR_TYPE_RGB_ALPHA
)
353 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
357 f
= fopen( name
, "rb" );
358 png_init_io( png_ptr
, f
);
360 png_read_info( png_ptr
, info_ptr
);
361 png_get_IHDR( png_ptr
, info_ptr
, &width
, &height
, &bit_depth
, &color_type
, &interlace_type
, NULL
, NULL
);
363 if (color_type
== PNG_COLOR_TYPE_PALETTE
) png_set_expand( png_ptr
);
365 png_set_strip_16( png_ptr
);
366 png_set_packing( png_ptr
);
367 if (png_get_valid( png_ptr
, info_ptr
, PNG_INFO_tRNS
)) png_set_expand( png_ptr
);
368 png_set_filler( png_ptr
, 0xff, PNG_FILLER_AFTER
);
370 image
->Create( width
, height
);
374 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
378 lines
= (unsigned char **)malloc( height
* sizeof(unsigned char *) );
382 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
386 for (i
= 0; i
< height
; i
++)
388 if ((lines
[i
] = (unsigned char *)malloc(width
* (sizeof(unsigned char) * 4))) == NULL
)
391 for (unsigned int n
= 0; n
< i
; n
++) free( lines
[n
] );
393 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
398 png_read_image( png_ptr
, lines
);
399 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
400 ptr
= image
->GetData();
401 if ((color_type
== PNG_COLOR_TYPE_GRAY
) ||
402 (color_type
== PNG_COLOR_TYPE_GRAY_ALPHA
))
404 for (unsigned int y
= 0; y
< height
; y
++)
407 for (unsigned int x
= 0; x
< width
; x
++)
409 unsigned char r
= *ptr2
++;
410 unsigned char a
= *ptr2
++;
429 for (unsigned int y
= 0; y
< height
; y
++)
432 for (unsigned int x
= 0; x
< width
; x
++)
434 unsigned char r
= *ptr2
++;
435 unsigned char g
= *ptr2
++;
436 unsigned char b
= *ptr2
++;
437 unsigned char a
= *ptr2
++;
447 if ((r
== 255) && (g
== 0) && (b
== 255)) r
= 254;
455 for (i
= 0; i
< height
; i
++) free( lines
[i
] );
458 image
->SetMaskColour( 255, 0, 255 );
460 image
->SetMask( FALSE
);
466 bool wxPNGHandler::SaveFile( wxImage
*image
, const wxString
& name
)
468 FILE *f
= fopen( name
, "wb" );
471 png_structp png_ptr
= png_create_write_struct( PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
);
478 png_infop info_ptr
= png_create_info_struct(png_ptr
);
479 if (info_ptr
== NULL
)
482 png_destroy_write_struct( &png_ptr
, (png_infopp
)NULL
);
486 if (setjmp(png_ptr
->jmpbuf
))
489 png_destroy_write_struct( &png_ptr
, (png_infopp
)NULL
);
493 png_init_io( png_ptr
, f
);
494 png_set_IHDR( png_ptr
, info_ptr
, image
->GetWidth(), image
->GetHeight(), 8,
495 PNG_COLOR_TYPE_RGB_ALPHA
, PNG_INTERLACE_NONE
,
496 PNG_COMPRESSION_TYPE_BASE
, PNG_FILTER_TYPE_BASE
);
503 png_set_sBIT( png_ptr
, info_ptr
, &sig_bit
);
504 png_write_info( png_ptr
, info_ptr
);
505 png_set_shift( png_ptr
, &sig_bit
);
506 png_set_packing( png_ptr
);
508 unsigned char *data
= (unsigned char *)malloc( image
->GetWidth()*4 );
512 png_destroy_write_struct( &png_ptr
, (png_infopp
)NULL
);
516 for (int y
= 0; y
< image
->GetHeight(); y
++)
518 unsigned char *ptr
= image
->GetData() + (y
* image
->GetWidth() * 3);
519 for (int x
= 0; x
< image
->GetWidth(); x
++)
521 data
[(x
<< 2) + 0] = *ptr
++;
522 data
[(x
<< 2) + 1] = *ptr
++;
523 data
[(x
<< 2) + 2] = *ptr
++;
524 if ((data
[(x
<< 2) + 0] == image
->GetMaskRed()) &&
525 (data
[(x
<< 2) + 1] == image
->GetMaskGreen()) &&
526 (data
[(x
<< 2) + 2] == image
->GetMaskBlue()))
527 data
[(x
<< 2) + 3] = 0;
529 data
[(x
<< 2) + 3] = 255;
531 png_bytep row_ptr
= data
;
532 png_write_rows( png_ptr
, &row_ptr
, 1 );
535 png_write_end( png_ptr
, info_ptr
);
536 png_destroy_write_struct( &png_ptr
, (png_infopp
)NULL
);
543 //-----------------------------------------------------------------------------
545 //-----------------------------------------------------------------------------
547 #if !USE_SHARED_LIBRARIES
548 IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler
,wxImageHandler
)
551 bool wxBMPHandler::LoadFile( wxImage
*image
, const wxString
& name
)
554 unsigned char *data
, *ptr
;
555 int done
, i
, bpp
, planes
, comp
, ncolors
, line
, column
,
556 linesize
, linepos
, rshift
= 0, gshift
= 0, bshift
= 0;
559 long int dbuf
[4], dword
, rmask
= 0, gmask
= 0, bmask
= 0, offset
,
564 unsigned char r
, g
, b
;
571 #define BI_BITFIELDS 3
576 file
= fopen(name
, "r");
582 * Reading the bmp header
585 fread(&bbuf
, 1, 2, file
);
587 fread(dbuf
, 4, 4, file
);
592 fread(dbuf
, 4, 2, file
);
593 int width
= (int)dbuf
[0];
594 int height
= (int)dbuf
[1];
597 fprintf(stderr
, "IMLIB ERROR: Image width > 32767 pixels for file\n");
603 fprintf(stderr
, "IMLIB ERROR: Image height > 32767 pixels for file\n");
607 fread(&word
, 2, 1, file
);
609 fread(&word
, 2, 1, file
);
611 if (bpp
!= 1 && bpp
!= 4 && bpp
!= 8 && bpp
&& 16 && bpp
!= 24 && bpp
!= 32)
613 fprintf(stderr
, "IMLIB ERROR: unknown bitdepth in file\n");
617 fread(dbuf
, 4, 4, file
);
619 if (comp
!= BI_RGB
&& comp
!= BI_RLE4
&& comp
!= BI_RLE8
&& comp
!= BI_BITFIELDS
)
621 fprintf(stderr
, "IMLIB ERROR: unknown encoding in Windows BMP file\n");
625 fread(dbuf
, 4, 2, file
);
626 ncolors
= (int)dbuf
[0];
629 /* some more sanity checks */
630 if (((comp
== BI_RLE4
) && (bpp
!= 4)) || ((comp
== BI_RLE8
) && (bpp
!= 8)) || ((comp
== BI_BITFIELDS
) && (bpp
!= 16 && bpp
!= 32)))
632 fprintf(stderr
, "IMLIB ERROR: encoding of BMP doesn't match bitdepth\n");
638 cmap
= (struct _cmap
*)malloc(sizeof(struct _cmap
) * ncolors
);
642 fprintf(stderr
, "IMLIB ERROR: Cannot allocate RAM for color map in BMP file\n");
650 image
->Create( width
, height
);
651 ptr
= image
->GetData();
654 fprintf(stderr
, "IMLIB ERROR: Cannot allocate RAM for RGB data in file\n");
662 * Reading the palette, if it exists.
664 if (bpp
< 16 && ncolors
!= 0)
666 for (i
= 0; i
< ncolors
; i
++)
668 fread(bbuf
, 1, 4, file
);
674 else if (bpp
== 16 || bpp
== 32)
676 if (comp
== BI_BITFIELDS
)
680 fread(dbuf
, 4, 3, file
);
684 /* find shift amount.. ugly, but i can't think of a better way */
685 for (bit
= 0; bit
< bpp
; bit
++)
687 if (bmask
& (1 << bit
))
689 if (gmask
& (1 << bit
))
691 if (rmask
& (1 << bit
))
716 * REading the image data
718 fseek(file
, offset
, SEEK_SET
);
721 /* set the whole image to the background color */
722 if (bpp
< 16 && (comp
== BI_RLE4
|| comp
== BI_RLE8
))
724 for (i
= 0; i
< width
* height
; i
++)
734 #define poffset (line * width * 3 + column * 3)
737 * BMPs are stored upside down... hmmmmmmmmmm....
740 linesize
= ((width
* bpp
+ 31) / 32) * 4;
741 for (line
= (height
- 1); line
>= 0; line
--)
744 for (column
= 0; column
< width
;)
756 for (bit
= 0; bit
< 8; bit
++)
758 index
= ((byte
& (0x80 >> bit
)) ? 1 : 0);
759 ptr
[poffset
] = cmap
[index
].r
;
760 ptr
[poffset
+ 1] = cmap
[index
].g
;
761 ptr
[poffset
+ 2] = cmap
[index
].b
;
769 fprintf(stderr
, "can't deal with 4bit encoded yet.\n");
778 for (nibble
= 0; nibble
< 2; nibble
++)
780 index
= ((byte
& (0xF0 >> nibble
* 4)) >> (!nibble
* 4));
783 ptr
[poffset
] = cmap
[index
].r
;
784 ptr
[poffset
+ 1] = cmap
[index
].g
;
785 ptr
[poffset
+ 2] = cmap
[index
].b
;
802 /* column = width; */
813 linepos
= column
* bpp
/ 8;
821 for (i
= 0; i
< absolute
; i
++)
825 ptr
[poffset
] = cmap
[byte
].r
;
826 ptr
[poffset
+ 1] = cmap
[byte
].g
;
827 ptr
[poffset
+ 2] = cmap
[byte
].b
;
836 for (i
= 0; i
< first
; i
++)
838 ptr
[poffset
] = cmap
[byte
].r
;
839 ptr
[poffset
+ 1] = cmap
[byte
].g
;
840 ptr
[poffset
+ 2] = cmap
[byte
].b
;
848 ptr
[poffset
] = cmap
[byte
].r
;
849 ptr
[poffset
+ 1] = cmap
[byte
].g
;
850 ptr
[poffset
+ 2] = cmap
[byte
].b
;
858 linepos
+= fread(&bbuf
, 1, 3, file
);
859 ptr
[poffset
] = (unsigned char)bbuf
[2];
860 ptr
[poffset
+ 1] = (unsigned char)bbuf
[1];
861 ptr
[poffset
+ 2] = (unsigned char)bbuf
[0];
868 linepos
+= fread(&word
, 2, 1, file
);
869 temp
= (word
& rmask
) >> rshift
;
871 temp
= (word
& gmask
) >> gshift
;
872 ptr
[poffset
+ 1] = temp
;
873 temp
= (word
& bmask
) >> gshift
;
874 ptr
[poffset
+ 2] = temp
;
881 linepos
+= fread(&dword
, 4, 1, file
);
882 temp
= (dword
& rmask
) >> rshift
;
884 temp
= (dword
& gmask
) >> gshift
;
885 ptr
[poffset
+ 1] = temp
;
886 temp
= (dword
& bmask
) >> bshift
;
887 ptr
[poffset
+ 2] = temp
;
891 while ((linepos
< linesize
) && (comp
!= 1) && (comp
!= 2))
893 int temp
= fread(&byte
, 1, 1, file
);
900 if (cmap
) free(cmap
);
902 image
->SetMask( FALSE
);