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 wxImage
wxImage::Scale( int width
, int height
)
125 wxCHECK_MSG( Ok(), image
, "invlaid image" );
127 wxCHECK_MSG( (width
> 0) && (height
> 0), image
, "invalid image size" );
129 image
.Create( width
, height
);
131 char unsigned *data
= image
.GetData();
133 wxCHECK_MSG( data
, image
, "unable to create image" );
135 if (M_IMGDATA
->m_hasMask
)
136 image
.SetMaskColour( M_IMGDATA
->m_maskRed
, M_IMGDATA
->m_maskGreen
, M_IMGDATA
->m_maskBlue
);
138 double xscale
= (double)width
/ (double)M_IMGDATA
->m_width
;
139 double yscale
= (double)height
/ (double)M_IMGDATA
->m_height
;
141 for (int j
= 0; j
< height
; j
++)
143 for (int i
= 0; i
< width
; i
++)
145 int new_pos
= 3*(j
*width
+ i
);
146 int old_pos
= 3*((long)(j
/yscale
)*M_IMGDATA
->m_width
+ (long)(i
/xscale
));
147 data
[ new_pos
] = M_IMGDATA
->m_data
[ old_pos
];
148 data
[ new_pos
+1 ] = M_IMGDATA
->m_data
[ old_pos
+1 ];
149 data
[ new_pos
+2 ] = M_IMGDATA
->m_data
[ old_pos
+2 ];
156 void wxImage::SetRGB( int x
, int y
, unsigned char r
, unsigned char g
, unsigned char b
)
158 wxCHECK_RET( Ok(), "invalid image" );
160 int w
= M_IMGDATA
->m_width
;
161 int h
= M_IMGDATA
->m_height
;
163 wxCHECK_RET( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), "invalid image index" );
165 long pos
= (y
* w
+ x
) * 3;
167 M_IMGDATA
->m_data
[ pos
] = r
;
168 M_IMGDATA
->m_data
[ pos
+1 ] = g
;
169 M_IMGDATA
->m_data
[ pos
+2 ] = b
;
172 unsigned char wxImage::GetRed( int x
, int y
)
174 wxCHECK_MSG( Ok(), 0, "invalid image" );
176 int w
= M_IMGDATA
->m_width
;
177 int h
= M_IMGDATA
->m_height
;
179 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, "invalid image index" );
181 long pos
= (y
* w
+ x
) * 3;
183 return M_IMGDATA
->m_data
[pos
];
186 unsigned char wxImage::GetGreen( int x
, int y
)
188 wxCHECK_MSG( Ok(), 0, "invalid image" );
190 int w
= M_IMGDATA
->m_width
;
191 int h
= M_IMGDATA
->m_height
;
193 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, "invalid image index" );
195 long pos
= (y
* w
+ x
) * 3;
197 return M_IMGDATA
->m_data
[pos
+1];
200 unsigned char wxImage::GetBlue( int x
, int y
)
202 wxCHECK_MSG( Ok(), 0, "invalid image" );
204 int w
= M_IMGDATA
->m_width
;
205 int h
= M_IMGDATA
->m_height
;
207 wxCHECK_MSG( (x
>=0) && (y
>=0) && (x
<w
) && (y
<h
), 0, "invalid image index" );
209 long pos
= (y
* w
+ x
) * 3;
211 return M_IMGDATA
->m_data
[pos
+2];
214 bool wxImage::Ok() const
216 return (M_IMGDATA
&& M_IMGDATA
->m_ok
);
219 char unsigned *wxImage::GetData() const
221 wxCHECK_MSG( Ok(), (char unsigned *)NULL
, "invalid image" );
223 return M_IMGDATA
->m_data
;
226 void wxImage::SetData( char unsigned *WXUNUSED(data
) )
228 wxCHECK_RET( Ok(), "invalid image" );
231 void wxImage::SetMaskColour( unsigned char r
, unsigned char g
, unsigned char b
)
233 wxCHECK_RET( Ok(), "invalid image" );
235 M_IMGDATA
->m_maskRed
= r
;
236 M_IMGDATA
->m_maskGreen
= g
;
237 M_IMGDATA
->m_maskBlue
= b
;
238 M_IMGDATA
->m_hasMask
= TRUE
;
241 unsigned char wxImage::GetMaskRed() const
243 wxCHECK_MSG( Ok(), 0, "invalid image" );
245 return M_IMGDATA
->m_maskRed
;
248 unsigned char wxImage::GetMaskGreen() const
250 wxCHECK_MSG( Ok(), 0, "invalid image" );
252 return M_IMGDATA
->m_maskGreen
;
255 unsigned char wxImage::GetMaskBlue() const
257 wxCHECK_MSG( Ok(), 0, "invalid image" );
259 return M_IMGDATA
->m_maskBlue
;
262 void wxImage::SetMask( bool mask
)
264 wxCHECK_RET( Ok(), "invalid image" );
266 M_IMGDATA
->m_hasMask
= mask
;
269 bool wxImage::HasMask() const
271 wxCHECK_MSG( Ok(), FALSE
, "invalid image" );
273 return M_IMGDATA
->m_hasMask
;
276 int wxImage::GetWidth() const
278 wxCHECK_MSG( Ok(), 0, "invalid image" );
280 return M_IMGDATA
->m_width
;
283 int wxImage::GetHeight() const
285 wxCHECK_MSG( Ok(), 0, "invalid image" );
287 return M_IMGDATA
->m_height
;
290 bool wxImage::LoadFile( const wxString
& filename
, long type
)
294 if (!wxFileExists(filename
))
296 wxLogWarning( "Image file does not exist." );
301 m_refData
= new wxImageRefData
;
303 wxImageHandler
*handler
= FindHandler(type
);
307 wxLogWarning( "No image handler for type %d defined.", type
);
312 return handler
->LoadFile( this, filename
);
315 bool wxImage::SaveFile( const wxString
& filename
, int type
)
317 wxCHECK_MSG( Ok(), FALSE
, "invalid image" );
319 wxImageHandler
*handler
= FindHandler(type
);
323 wxLogWarning( "No image handler for type %d defined.", type
);
328 return handler
->SaveFile( this, filename
);
331 void wxImage::AddHandler( wxImageHandler
*handler
)
333 sm_handlers
.Append( handler
);
336 void wxImage::InsertHandler( wxImageHandler
*handler
)
338 sm_handlers
.Insert( handler
);
341 bool wxImage::RemoveHandler( const wxString
& name
)
343 wxImageHandler
*handler
= FindHandler(name
);
346 sm_handlers
.DeleteObject(handler
);
353 wxImageHandler
*wxImage::FindHandler( const wxString
& name
)
355 wxNode
*node
= sm_handlers
.First();
358 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
359 if (handler
->GetName() == name
) return handler
;
362 return (wxImageHandler
*)NULL
;
365 wxImageHandler
*wxImage::FindHandler( const wxString
& extension
, long bitmapType
)
367 wxNode
*node
= sm_handlers
.First();
370 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
371 if ( handler
->GetExtension() == extension
&&
372 (bitmapType
== -1 || handler
->GetType() == bitmapType
) )
376 return (wxImageHandler
*)NULL
;
379 wxImageHandler
*wxImage::FindHandler( long bitmapType
)
381 wxNode
*node
= sm_handlers
.First();
384 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
385 if (handler
->GetType() == bitmapType
) return handler
;
391 void wxImage::InitStandardHandlers()
393 AddHandler( new wxBMPHandler
);
394 AddHandler( new wxPNGHandler
);
397 void wxImage::CleanUpHandlers()
399 wxNode
*node
= sm_handlers
.First();
402 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
403 wxNode
*next
= node
->Next();
410 //-----------------------------------------------------------------------------
412 //-----------------------------------------------------------------------------
414 #if !USE_SHARED_LIBRARIES
415 IMPLEMENT_DYNAMIC_CLASS(wxImageHandler
,wxObject
)
418 bool wxImageHandler::LoadFile( wxImage
*WXUNUSED(image
), const wxString
& WXUNUSED(name
) )
423 bool wxImageHandler::SaveFile( wxImage
*WXUNUSED(image
), const wxString
& WXUNUSED(name
) )
428 //-----------------------------------------------------------------------------
430 //-----------------------------------------------------------------------------
432 #if !USE_SHARED_LIBRARIES
433 IMPLEMENT_DYNAMIC_CLASS(wxPNGHandler
,wxImageHandler
)
436 bool wxPNGHandler::LoadFile( wxImage
*image
, const wxString
& name
)
441 unsigned char *ptr
, **lines
, *ptr2
;
442 int transp
,bit_depth
,color_type
,interlace_type
;
443 png_uint_32 width
, height
;
449 png_ptr
= png_create_read_struct( PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
);
450 if (!png_ptr
) return FALSE
;
452 info_ptr
= png_create_info_struct( png_ptr
);
455 png_destroy_read_struct( &png_ptr
, NULL
, NULL
);
459 if (setjmp(png_ptr
->jmpbuf
))
461 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
465 if (info_ptr
->color_type
== PNG_COLOR_TYPE_RGB_ALPHA
)
467 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
471 f
= fopen( name
, "rb" );
472 png_init_io( png_ptr
, f
);
474 png_read_info( png_ptr
, info_ptr
);
475 png_get_IHDR( png_ptr
, info_ptr
, &width
, &height
, &bit_depth
, &color_type
, &interlace_type
, NULL
, NULL
);
477 if (color_type
== PNG_COLOR_TYPE_PALETTE
) png_set_expand( png_ptr
);
479 png_set_strip_16( png_ptr
);
480 png_set_packing( png_ptr
);
481 if (png_get_valid( png_ptr
, info_ptr
, PNG_INFO_tRNS
)) png_set_expand( png_ptr
);
482 png_set_filler( png_ptr
, 0xff, PNG_FILLER_AFTER
);
484 image
->Create( width
, height
);
488 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
492 lines
= (unsigned char **)malloc( height
* sizeof(unsigned char *) );
496 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
500 for (i
= 0; i
< height
; i
++)
502 if ((lines
[i
] = (unsigned char *)malloc(width
* (sizeof(unsigned char) * 4))) == NULL
)
505 for (unsigned int n
= 0; n
< i
; n
++) free( lines
[n
] );
507 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
512 png_read_image( png_ptr
, lines
);
513 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
514 ptr
= image
->GetData();
515 if ((color_type
== PNG_COLOR_TYPE_GRAY
) ||
516 (color_type
== PNG_COLOR_TYPE_GRAY_ALPHA
))
518 for (unsigned int y
= 0; y
< height
; y
++)
521 for (unsigned int x
= 0; x
< width
; x
++)
523 unsigned char r
= *ptr2
++;
524 unsigned char a
= *ptr2
++;
543 for (unsigned int y
= 0; y
< height
; y
++)
546 for (unsigned int x
= 0; x
< width
; x
++)
548 unsigned char r
= *ptr2
++;
549 unsigned char g
= *ptr2
++;
550 unsigned char b
= *ptr2
++;
551 unsigned char a
= *ptr2
++;
561 if ((r
== 255) && (g
== 0) && (b
== 255)) r
= 254;
569 for (i
= 0; i
< height
; i
++) free( lines
[i
] );
572 image
->SetMaskColour( 255, 0, 255 );
574 image
->SetMask( FALSE
);
580 bool wxPNGHandler::SaveFile( wxImage
*image
, const wxString
& name
)
582 FILE *f
= fopen( name
, "wb" );
585 png_structp png_ptr
= png_create_write_struct( PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
);
592 png_infop info_ptr
= png_create_info_struct(png_ptr
);
593 if (info_ptr
== NULL
)
596 png_destroy_write_struct( &png_ptr
, (png_infopp
)NULL
);
600 if (setjmp(png_ptr
->jmpbuf
))
603 png_destroy_write_struct( &png_ptr
, (png_infopp
)NULL
);
607 png_init_io( png_ptr
, f
);
608 png_set_IHDR( png_ptr
, info_ptr
, image
->GetWidth(), image
->GetHeight(), 8,
609 PNG_COLOR_TYPE_RGB_ALPHA
, PNG_INTERLACE_NONE
,
610 PNG_COMPRESSION_TYPE_BASE
, PNG_FILTER_TYPE_BASE
);
617 png_set_sBIT( png_ptr
, info_ptr
, &sig_bit
);
618 png_write_info( png_ptr
, info_ptr
);
619 png_set_shift( png_ptr
, &sig_bit
);
620 png_set_packing( png_ptr
);
622 unsigned char *data
= (unsigned char *)malloc( image
->GetWidth()*4 );
626 png_destroy_write_struct( &png_ptr
, (png_infopp
)NULL
);
630 for (int y
= 0; y
< image
->GetHeight(); y
++)
632 unsigned char *ptr
= image
->GetData() + (y
* image
->GetWidth() * 3);
633 for (int x
= 0; x
< image
->GetWidth(); x
++)
635 data
[(x
<< 2) + 0] = *ptr
++;
636 data
[(x
<< 2) + 1] = *ptr
++;
637 data
[(x
<< 2) + 2] = *ptr
++;
638 if ((data
[(x
<< 2) + 0] == image
->GetMaskRed()) &&
639 (data
[(x
<< 2) + 1] == image
->GetMaskGreen()) &&
640 (data
[(x
<< 2) + 2] == image
->GetMaskBlue()))
641 data
[(x
<< 2) + 3] = 0;
643 data
[(x
<< 2) + 3] = 255;
645 png_bytep row_ptr
= data
;
646 png_write_rows( png_ptr
, &row_ptr
, 1 );
649 png_write_end( png_ptr
, info_ptr
);
650 png_destroy_write_struct( &png_ptr
, (png_infopp
)NULL
);
657 //-----------------------------------------------------------------------------
659 //-----------------------------------------------------------------------------
661 #if !USE_SHARED_LIBRARIES
662 IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler
,wxImageHandler
)
665 bool wxBMPHandler::LoadFile( wxImage
*image
, const wxString
& name
)
668 unsigned char *data
, *ptr
;
669 int done
, i
, bpp
, planes
, comp
, ncolors
, line
, column
,
670 linesize
, linepos
, rshift
= 0, gshift
= 0, bshift
= 0;
673 long int dbuf
[4], dword
, rmask
= 0, gmask
= 0, bmask
= 0, offset
,
678 unsigned char r
, g
, b
;
685 #define BI_BITFIELDS 3
690 file
= fopen(name
, "r");
696 * Reading the bmp header
699 fread(&bbuf
, 1, 2, file
);
701 fread(dbuf
, 4, 4, file
);
706 fread(dbuf
, 4, 2, file
);
707 int width
= (int)dbuf
[0];
708 int height
= (int)dbuf
[1];
711 fprintf(stderr
, "IMLIB ERROR: Image width > 32767 pixels for file\n");
717 fprintf(stderr
, "IMLIB ERROR: Image height > 32767 pixels for file\n");
721 fread(&word
, 2, 1, file
);
723 fread(&word
, 2, 1, file
);
725 if (bpp
!= 1 && bpp
!= 4 && bpp
!= 8 && bpp
&& 16 && bpp
!= 24 && bpp
!= 32)
727 fprintf(stderr
, "IMLIB ERROR: unknown bitdepth in file\n");
731 fread(dbuf
, 4, 4, file
);
733 if (comp
!= BI_RGB
&& comp
!= BI_RLE4
&& comp
!= BI_RLE8
&& comp
!= BI_BITFIELDS
)
735 fprintf(stderr
, "IMLIB ERROR: unknown encoding in Windows BMP file\n");
739 fread(dbuf
, 4, 2, file
);
740 ncolors
= (int)dbuf
[0];
743 /* some more sanity checks */
744 if (((comp
== BI_RLE4
) && (bpp
!= 4)) || ((comp
== BI_RLE8
) && (bpp
!= 8)) || ((comp
== BI_BITFIELDS
) && (bpp
!= 16 && bpp
!= 32)))
746 fprintf(stderr
, "IMLIB ERROR: encoding of BMP doesn't match bitdepth\n");
752 cmap
= (struct _cmap
*)malloc(sizeof(struct _cmap
) * ncolors
);
756 fprintf(stderr
, "IMLIB ERROR: Cannot allocate RAM for color map in BMP file\n");
764 image
->Create( width
, height
);
765 ptr
= image
->GetData();
768 fprintf(stderr
, "IMLIB ERROR: Cannot allocate RAM for RGB data in file\n");
776 * Reading the palette, if it exists.
778 if (bpp
< 16 && ncolors
!= 0)
780 for (i
= 0; i
< ncolors
; i
++)
782 fread(bbuf
, 1, 4, file
);
788 else if (bpp
== 16 || bpp
== 32)
790 if (comp
== BI_BITFIELDS
)
794 fread(dbuf
, 4, 3, file
);
798 /* find shift amount.. ugly, but i can't think of a better way */
799 for (bit
= 0; bit
< bpp
; bit
++)
801 if (bmask
& (1 << bit
))
803 if (gmask
& (1 << bit
))
805 if (rmask
& (1 << bit
))
830 * REading the image data
832 fseek(file
, offset
, SEEK_SET
);
835 /* set the whole image to the background color */
836 if (bpp
< 16 && (comp
== BI_RLE4
|| comp
== BI_RLE8
))
838 for (i
= 0; i
< width
* height
; i
++)
848 #define poffset (line * width * 3 + column * 3)
851 * BMPs are stored upside down... hmmmmmmmmmm....
854 linesize
= ((width
* bpp
+ 31) / 32) * 4;
855 for (line
= (height
- 1); line
>= 0; line
--)
858 for (column
= 0; column
< width
;)
870 for (bit
= 0; bit
< 8; bit
++)
872 index
= ((byte
& (0x80 >> bit
)) ? 1 : 0);
873 ptr
[poffset
] = cmap
[index
].r
;
874 ptr
[poffset
+ 1] = cmap
[index
].g
;
875 ptr
[poffset
+ 2] = cmap
[index
].b
;
883 fprintf(stderr
, "can't deal with 4bit encoded yet.\n");
892 for (nibble
= 0; nibble
< 2; nibble
++)
894 index
= ((byte
& (0xF0 >> nibble
* 4)) >> (!nibble
* 4));
897 ptr
[poffset
] = cmap
[index
].r
;
898 ptr
[poffset
+ 1] = cmap
[index
].g
;
899 ptr
[poffset
+ 2] = cmap
[index
].b
;
916 /* column = width; */
927 linepos
= column
* bpp
/ 8;
935 for (i
= 0; i
< absolute
; i
++)
939 ptr
[poffset
] = cmap
[byte
].r
;
940 ptr
[poffset
+ 1] = cmap
[byte
].g
;
941 ptr
[poffset
+ 2] = cmap
[byte
].b
;
950 for (i
= 0; i
< first
; i
++)
952 ptr
[poffset
] = cmap
[byte
].r
;
953 ptr
[poffset
+ 1] = cmap
[byte
].g
;
954 ptr
[poffset
+ 2] = cmap
[byte
].b
;
962 ptr
[poffset
] = cmap
[byte
].r
;
963 ptr
[poffset
+ 1] = cmap
[byte
].g
;
964 ptr
[poffset
+ 2] = cmap
[byte
].b
;
972 linepos
+= fread(&bbuf
, 1, 3, file
);
973 ptr
[poffset
] = (unsigned char)bbuf
[2];
974 ptr
[poffset
+ 1] = (unsigned char)bbuf
[1];
975 ptr
[poffset
+ 2] = (unsigned char)bbuf
[0];
982 linepos
+= fread(&word
, 2, 1, file
);
983 temp
= (word
& rmask
) >> rshift
;
985 temp
= (word
& gmask
) >> gshift
;
986 ptr
[poffset
+ 1] = temp
;
987 temp
= (word
& bmask
) >> gshift
;
988 ptr
[poffset
+ 2] = temp
;
995 linepos
+= fread(&dword
, 4, 1, file
);
996 temp
= (dword
& rmask
) >> rshift
;
998 temp
= (dword
& gmask
) >> gshift
;
999 ptr
[poffset
+ 1] = temp
;
1000 temp
= (dword
& bmask
) >> bshift
;
1001 ptr
[poffset
+ 2] = temp
;
1005 while ((linepos
< linesize
) && (comp
!= 1) && (comp
!= 2))
1007 int temp
= fread(&byte
, 1, 1, file
);
1014 if (cmap
) free(cmap
);
1016 image
->SetMask( FALSE
);