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 bool wxImage::Ok() const
158 return (M_IMGDATA
&& M_IMGDATA
->m_ok
);
161 char unsigned *wxImage::GetData() const
163 wxCHECK_MSG( Ok(), (char unsigned *)NULL
, "invalid image" );
165 return M_IMGDATA
->m_data
;
168 void wxImage::SetData( char unsigned *WXUNUSED(data
) )
170 wxCHECK_RET( Ok(), "invalid image" );
173 void wxImage::SetMaskColour( unsigned char r
, unsigned char g
, unsigned char b
)
175 wxCHECK_RET( Ok(), "invalid image" );
177 M_IMGDATA
->m_maskRed
= r
;
178 M_IMGDATA
->m_maskGreen
= g
;
179 M_IMGDATA
->m_maskBlue
= b
;
180 M_IMGDATA
->m_hasMask
= TRUE
;
183 unsigned char wxImage::GetMaskRed() const
185 wxCHECK_MSG( Ok(), 0, "invalid image" );
187 return M_IMGDATA
->m_maskRed
;
190 unsigned char wxImage::GetMaskGreen() const
192 wxCHECK_MSG( Ok(), 0, "invalid image" );
194 return M_IMGDATA
->m_maskGreen
;
197 unsigned char wxImage::GetMaskBlue() const
199 wxCHECK_MSG( Ok(), 0, "invalid image" );
201 return M_IMGDATA
->m_maskBlue
;
204 void wxImage::SetMask( bool mask
)
206 wxCHECK_RET( Ok(), "invalid image" );
208 M_IMGDATA
->m_hasMask
= mask
;
211 bool wxImage::HasMask() const
213 wxCHECK_MSG( Ok(), FALSE
, "invalid image" );
215 return M_IMGDATA
->m_hasMask
;
218 int wxImage::GetWidth() const
220 wxCHECK_MSG( Ok(), 0, "invalid image" );
222 return M_IMGDATA
->m_width
;
225 int wxImage::GetHeight() const
227 wxCHECK_MSG( Ok(), 0, "invalid image" );
229 return M_IMGDATA
->m_height
;
232 bool wxImage::LoadFile( const wxString
& filename
, long type
)
236 if (!wxFileExists(filename
))
238 wxLogWarning( "Image file does not exist." );
243 m_refData
= new wxImageRefData
;
245 wxImageHandler
*handler
= FindHandler(type
);
249 wxLogWarning( "No image handler for type %d defined.", type
);
254 return handler
->LoadFile( this, filename
);
257 bool wxImage::SaveFile( const wxString
& filename
, int type
)
259 wxCHECK_MSG( Ok(), FALSE
, "invalid image" );
261 wxImageHandler
*handler
= FindHandler(type
);
265 wxLogWarning( "No image handler for type %d defined.", type
);
270 return handler
->SaveFile( this, filename
);
273 void wxImage::AddHandler( wxImageHandler
*handler
)
275 sm_handlers
.Append( handler
);
278 void wxImage::InsertHandler( wxImageHandler
*handler
)
280 sm_handlers
.Insert( handler
);
283 bool wxImage::RemoveHandler( const wxString
& name
)
285 wxImageHandler
*handler
= FindHandler(name
);
288 sm_handlers
.DeleteObject(handler
);
295 wxImageHandler
*wxImage::FindHandler( const wxString
& name
)
297 wxNode
*node
= sm_handlers
.First();
300 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
301 if (handler
->GetName() == name
) return handler
;
304 return (wxImageHandler
*)NULL
;
307 wxImageHandler
*wxImage::FindHandler( const wxString
& extension
, long bitmapType
)
309 wxNode
*node
= sm_handlers
.First();
312 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
313 if ( handler
->GetExtension() == extension
&&
314 (bitmapType
== -1 || handler
->GetType() == bitmapType
) )
318 return (wxImageHandler
*)NULL
;
321 wxImageHandler
*wxImage::FindHandler( long bitmapType
)
323 wxNode
*node
= sm_handlers
.First();
326 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
327 if (handler
->GetType() == bitmapType
) return handler
;
333 void wxImage::InitStandardHandlers()
335 AddHandler( new wxBMPHandler
);
336 AddHandler( new wxPNGHandler
);
339 void wxImage::CleanUpHandlers()
341 wxNode
*node
= sm_handlers
.First();
344 wxImageHandler
*handler
= (wxImageHandler
*)node
->Data();
345 wxNode
*next
= node
->Next();
352 //-----------------------------------------------------------------------------
354 //-----------------------------------------------------------------------------
356 #if !USE_SHARED_LIBRARIES
357 IMPLEMENT_DYNAMIC_CLASS(wxImageHandler
,wxObject
)
360 bool wxImageHandler::LoadFile( wxImage
*WXUNUSED(image
), const wxString
& WXUNUSED(name
) )
365 bool wxImageHandler::SaveFile( wxImage
*WXUNUSED(image
), const wxString
& WXUNUSED(name
) )
370 //-----------------------------------------------------------------------------
372 //-----------------------------------------------------------------------------
374 #if !USE_SHARED_LIBRARIES
375 IMPLEMENT_DYNAMIC_CLASS(wxPNGHandler
,wxImageHandler
)
378 bool wxPNGHandler::LoadFile( wxImage
*image
, const wxString
& name
)
383 unsigned char *ptr
, **lines
, *ptr2
;
384 int transp
,bit_depth
,color_type
,interlace_type
;
385 png_uint_32 width
, height
;
391 png_ptr
= png_create_read_struct( PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
);
392 if (!png_ptr
) return FALSE
;
394 info_ptr
= png_create_info_struct( png_ptr
);
397 png_destroy_read_struct( &png_ptr
, NULL
, NULL
);
401 if (setjmp(png_ptr
->jmpbuf
))
403 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
407 if (info_ptr
->color_type
== PNG_COLOR_TYPE_RGB_ALPHA
)
409 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
413 f
= fopen( name
, "rb" );
414 png_init_io( png_ptr
, f
);
416 png_read_info( png_ptr
, info_ptr
);
417 png_get_IHDR( png_ptr
, info_ptr
, &width
, &height
, &bit_depth
, &color_type
, &interlace_type
, NULL
, NULL
);
419 if (color_type
== PNG_COLOR_TYPE_PALETTE
) png_set_expand( png_ptr
);
421 png_set_strip_16( png_ptr
);
422 png_set_packing( png_ptr
);
423 if (png_get_valid( png_ptr
, info_ptr
, PNG_INFO_tRNS
)) png_set_expand( png_ptr
);
424 png_set_filler( png_ptr
, 0xff, PNG_FILLER_AFTER
);
426 image
->Create( width
, height
);
430 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
434 lines
= (unsigned char **)malloc( height
* sizeof(unsigned char *) );
438 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
442 for (i
= 0; i
< height
; i
++)
444 if ((lines
[i
] = (unsigned char *)malloc(width
* (sizeof(unsigned char) * 4))) == NULL
)
447 for (unsigned int n
= 0; n
< i
; n
++) free( lines
[n
] );
449 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
454 png_read_image( png_ptr
, lines
);
455 png_destroy_read_struct( &png_ptr
, &info_ptr
, NULL
);
456 ptr
= image
->GetData();
457 if ((color_type
== PNG_COLOR_TYPE_GRAY
) ||
458 (color_type
== PNG_COLOR_TYPE_GRAY_ALPHA
))
460 for (unsigned int y
= 0; y
< height
; y
++)
463 for (unsigned int x
= 0; x
< width
; x
++)
465 unsigned char r
= *ptr2
++;
466 unsigned char a
= *ptr2
++;
485 for (unsigned int y
= 0; y
< height
; y
++)
488 for (unsigned int x
= 0; x
< width
; x
++)
490 unsigned char r
= *ptr2
++;
491 unsigned char g
= *ptr2
++;
492 unsigned char b
= *ptr2
++;
493 unsigned char a
= *ptr2
++;
503 if ((r
== 255) && (g
== 0) && (b
== 255)) r
= 254;
511 for (i
= 0; i
< height
; i
++) free( lines
[i
] );
514 image
->SetMaskColour( 255, 0, 255 );
516 image
->SetMask( FALSE
);
522 bool wxPNGHandler::SaveFile( wxImage
*image
, const wxString
& name
)
524 FILE *f
= fopen( name
, "wb" );
527 png_structp png_ptr
= png_create_write_struct( PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
);
534 png_infop info_ptr
= png_create_info_struct(png_ptr
);
535 if (info_ptr
== NULL
)
538 png_destroy_write_struct( &png_ptr
, (png_infopp
)NULL
);
542 if (setjmp(png_ptr
->jmpbuf
))
545 png_destroy_write_struct( &png_ptr
, (png_infopp
)NULL
);
549 png_init_io( png_ptr
, f
);
550 png_set_IHDR( png_ptr
, info_ptr
, image
->GetWidth(), image
->GetHeight(), 8,
551 PNG_COLOR_TYPE_RGB_ALPHA
, PNG_INTERLACE_NONE
,
552 PNG_COMPRESSION_TYPE_BASE
, PNG_FILTER_TYPE_BASE
);
559 png_set_sBIT( png_ptr
, info_ptr
, &sig_bit
);
560 png_write_info( png_ptr
, info_ptr
);
561 png_set_shift( png_ptr
, &sig_bit
);
562 png_set_packing( png_ptr
);
564 unsigned char *data
= (unsigned char *)malloc( image
->GetWidth()*4 );
568 png_destroy_write_struct( &png_ptr
, (png_infopp
)NULL
);
572 for (int y
= 0; y
< image
->GetHeight(); y
++)
574 unsigned char *ptr
= image
->GetData() + (y
* image
->GetWidth() * 3);
575 for (int x
= 0; x
< image
->GetWidth(); x
++)
577 data
[(x
<< 2) + 0] = *ptr
++;
578 data
[(x
<< 2) + 1] = *ptr
++;
579 data
[(x
<< 2) + 2] = *ptr
++;
580 if ((data
[(x
<< 2) + 0] == image
->GetMaskRed()) &&
581 (data
[(x
<< 2) + 1] == image
->GetMaskGreen()) &&
582 (data
[(x
<< 2) + 2] == image
->GetMaskBlue()))
583 data
[(x
<< 2) + 3] = 0;
585 data
[(x
<< 2) + 3] = 255;
587 png_bytep row_ptr
= data
;
588 png_write_rows( png_ptr
, &row_ptr
, 1 );
591 png_write_end( png_ptr
, info_ptr
);
592 png_destroy_write_struct( &png_ptr
, (png_infopp
)NULL
);
599 //-----------------------------------------------------------------------------
601 //-----------------------------------------------------------------------------
603 #if !USE_SHARED_LIBRARIES
604 IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler
,wxImageHandler
)
607 bool wxBMPHandler::LoadFile( wxImage
*image
, const wxString
& name
)
610 unsigned char *data
, *ptr
;
611 int done
, i
, bpp
, planes
, comp
, ncolors
, line
, column
,
612 linesize
, linepos
, rshift
= 0, gshift
= 0, bshift
= 0;
615 long int dbuf
[4], dword
, rmask
= 0, gmask
= 0, bmask
= 0, offset
,
620 unsigned char r
, g
, b
;
627 #define BI_BITFIELDS 3
632 file
= fopen(name
, "r");
638 * Reading the bmp header
641 fread(&bbuf
, 1, 2, file
);
643 fread(dbuf
, 4, 4, file
);
648 fread(dbuf
, 4, 2, file
);
649 int width
= (int)dbuf
[0];
650 int height
= (int)dbuf
[1];
653 fprintf(stderr
, "IMLIB ERROR: Image width > 32767 pixels for file\n");
659 fprintf(stderr
, "IMLIB ERROR: Image height > 32767 pixels for file\n");
663 fread(&word
, 2, 1, file
);
665 fread(&word
, 2, 1, file
);
667 if (bpp
!= 1 && bpp
!= 4 && bpp
!= 8 && bpp
&& 16 && bpp
!= 24 && bpp
!= 32)
669 fprintf(stderr
, "IMLIB ERROR: unknown bitdepth in file\n");
673 fread(dbuf
, 4, 4, file
);
675 if (comp
!= BI_RGB
&& comp
!= BI_RLE4
&& comp
!= BI_RLE8
&& comp
!= BI_BITFIELDS
)
677 fprintf(stderr
, "IMLIB ERROR: unknown encoding in Windows BMP file\n");
681 fread(dbuf
, 4, 2, file
);
682 ncolors
= (int)dbuf
[0];
685 /* some more sanity checks */
686 if (((comp
== BI_RLE4
) && (bpp
!= 4)) || ((comp
== BI_RLE8
) && (bpp
!= 8)) || ((comp
== BI_BITFIELDS
) && (bpp
!= 16 && bpp
!= 32)))
688 fprintf(stderr
, "IMLIB ERROR: encoding of BMP doesn't match bitdepth\n");
694 cmap
= (struct _cmap
*)malloc(sizeof(struct _cmap
) * ncolors
);
698 fprintf(stderr
, "IMLIB ERROR: Cannot allocate RAM for color map in BMP file\n");
706 image
->Create( width
, height
);
707 ptr
= image
->GetData();
710 fprintf(stderr
, "IMLIB ERROR: Cannot allocate RAM for RGB data in file\n");
718 * Reading the palette, if it exists.
720 if (bpp
< 16 && ncolors
!= 0)
722 for (i
= 0; i
< ncolors
; i
++)
724 fread(bbuf
, 1, 4, file
);
730 else if (bpp
== 16 || bpp
== 32)
732 if (comp
== BI_BITFIELDS
)
736 fread(dbuf
, 4, 3, file
);
740 /* find shift amount.. ugly, but i can't think of a better way */
741 for (bit
= 0; bit
< bpp
; bit
++)
743 if (bmask
& (1 << bit
))
745 if (gmask
& (1 << bit
))
747 if (rmask
& (1 << bit
))
772 * REading the image data
774 fseek(file
, offset
, SEEK_SET
);
777 /* set the whole image to the background color */
778 if (bpp
< 16 && (comp
== BI_RLE4
|| comp
== BI_RLE8
))
780 for (i
= 0; i
< width
* height
; i
++)
790 #define poffset (line * width * 3 + column * 3)
793 * BMPs are stored upside down... hmmmmmmmmmm....
796 linesize
= ((width
* bpp
+ 31) / 32) * 4;
797 for (line
= (height
- 1); line
>= 0; line
--)
800 for (column
= 0; column
< width
;)
812 for (bit
= 0; bit
< 8; bit
++)
814 index
= ((byte
& (0x80 >> bit
)) ? 1 : 0);
815 ptr
[poffset
] = cmap
[index
].r
;
816 ptr
[poffset
+ 1] = cmap
[index
].g
;
817 ptr
[poffset
+ 2] = cmap
[index
].b
;
825 fprintf(stderr
, "can't deal with 4bit encoded yet.\n");
834 for (nibble
= 0; nibble
< 2; nibble
++)
836 index
= ((byte
& (0xF0 >> nibble
* 4)) >> (!nibble
* 4));
839 ptr
[poffset
] = cmap
[index
].r
;
840 ptr
[poffset
+ 1] = cmap
[index
].g
;
841 ptr
[poffset
+ 2] = cmap
[index
].b
;
858 /* column = width; */
869 linepos
= column
* bpp
/ 8;
877 for (i
= 0; i
< absolute
; i
++)
881 ptr
[poffset
] = cmap
[byte
].r
;
882 ptr
[poffset
+ 1] = cmap
[byte
].g
;
883 ptr
[poffset
+ 2] = cmap
[byte
].b
;
892 for (i
= 0; i
< first
; i
++)
894 ptr
[poffset
] = cmap
[byte
].r
;
895 ptr
[poffset
+ 1] = cmap
[byte
].g
;
896 ptr
[poffset
+ 2] = cmap
[byte
].b
;
904 ptr
[poffset
] = cmap
[byte
].r
;
905 ptr
[poffset
+ 1] = cmap
[byte
].g
;
906 ptr
[poffset
+ 2] = cmap
[byte
].b
;
914 linepos
+= fread(&bbuf
, 1, 3, file
);
915 ptr
[poffset
] = (unsigned char)bbuf
[2];
916 ptr
[poffset
+ 1] = (unsigned char)bbuf
[1];
917 ptr
[poffset
+ 2] = (unsigned char)bbuf
[0];
924 linepos
+= fread(&word
, 2, 1, file
);
925 temp
= (word
& rmask
) >> rshift
;
927 temp
= (word
& gmask
) >> gshift
;
928 ptr
[poffset
+ 1] = temp
;
929 temp
= (word
& bmask
) >> gshift
;
930 ptr
[poffset
+ 2] = temp
;
937 linepos
+= fread(&dword
, 4, 1, file
);
938 temp
= (dword
& rmask
) >> rshift
;
940 temp
= (dword
& gmask
) >> gshift
;
941 ptr
[poffset
+ 1] = temp
;
942 temp
= (dword
& bmask
) >> bshift
;
943 ptr
[poffset
+ 2] = temp
;
947 while ((linepos
< linesize
) && (comp
!= 1) && (comp
!= 2))
949 int temp
= fread(&byte
, 1, 1, file
);
956 if (cmap
) free(cmap
);
958 image
->SetMask( FALSE
);