]> git.saurik.com Git - wxWidgets.git/blob - src/common/image.cpp
1. some fixes for the problems reported by BoundsChecker
[wxWidgets.git] / src / common / image.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: image.cpp
3 // Purpose: wxImage
4 // Author: Robert Roebling
5 // RCS-ID: $Id$
6 // Copyright: (c) Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "image.h"
12 #endif
13
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
16
17 #ifdef __BORLANDC__
18 #pragma hdrstop
19 #endif
20
21 #include "wx/image.h"
22 #include "wx/bitmap.h"
23 #include "wx/debug.h"
24 #include "wx/log.h"
25 #include "wx/app.h"
26 #include "wx/filefn.h"
27 #include "wx/wfstream.h"
28 #include "wx/intl.h"
29 #include "wx/module.h"
30
31 // For memcpy
32 #include <string.h>
33
34 #ifdef __SALFORDC__
35 #undef FAR
36 #endif
37
38 #ifdef __WXMSW__
39 #include "wx/msw/private.h"
40 #endif
41
42 //-----------------------------------------------------------------------------
43 // wxImage
44 //-----------------------------------------------------------------------------
45
46 class wxImageRefData: public wxObjectRefData
47 {
48 public:
49 wxImageRefData();
50 ~wxImageRefData();
51
52 int m_width;
53 int m_height;
54 unsigned char *m_data;
55 bool m_hasMask;
56 unsigned char m_maskRed,m_maskGreen,m_maskBlue;
57 bool m_ok;
58 };
59
60 wxImageRefData::wxImageRefData()
61 {
62 m_width = 0;
63 m_height = 0;
64 m_data = (unsigned char*) NULL;
65 m_ok = FALSE;
66 m_maskRed = 0;
67 m_maskGreen = 0;
68 m_maskBlue = 0;
69 m_hasMask = FALSE;
70 }
71
72 wxImageRefData::~wxImageRefData()
73 {
74 if (m_data)
75 free( m_data );
76 }
77
78 wxList wxImage::sm_handlers;
79
80 //-----------------------------------------------------------------------------
81
82 #define M_IMGDATA ((wxImageRefData *)m_refData)
83
84 IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject)
85
86 wxImage::wxImage()
87 {
88 }
89
90 wxImage::wxImage( int width, int height )
91 {
92 Create( width, height );
93 }
94
95 wxImage::wxImage( const wxString& name, long type )
96 {
97 LoadFile( name, type );
98 }
99
100 wxImage::wxImage( const wxString& name, const wxString& mimetype )
101 {
102 LoadFile( name, mimetype );
103 }
104
105 #if wxUSE_STREAMS
106 wxImage::wxImage( wxInputStream& stream, long type )
107 {
108 LoadFile( stream, type );
109 }
110
111 wxImage::wxImage( wxInputStream& stream, const wxString& mimetype )
112 {
113 LoadFile( stream, mimetype );
114 }
115 #endif // wxUSE_STREAMS
116
117 wxImage::wxImage( const wxImage& image )
118 {
119 Ref(image);
120 }
121
122 wxImage::wxImage( const wxImage* image )
123 {
124 if (image) Ref(*image);
125 }
126
127 void wxImage::Create( int width, int height )
128 {
129 m_refData = new wxImageRefData();
130
131 M_IMGDATA->m_data = (unsigned char *) malloc( width*height*3 );
132 if (M_IMGDATA->m_data)
133 {
134 for (int l = 0; l < width*height*3; l++) M_IMGDATA->m_data[l] = 0;
135
136 M_IMGDATA->m_width = width;
137 M_IMGDATA->m_height = height;
138 M_IMGDATA->m_ok = TRUE;
139 }
140 else
141 {
142 UnRef();
143 }
144 }
145
146 void wxImage::Destroy()
147 {
148 UnRef();
149 }
150
151 wxImage wxImage::Scale( int width, int height ) const
152 {
153 wxImage image;
154
155 wxCHECK_MSG( Ok(), image, wxT("invalid image") );
156
157 wxCHECK_MSG( (width > 0) && (height > 0), image, wxT("invalid image size") );
158
159 image.Create( width, height );
160
161 char unsigned *data = image.GetData();
162
163 wxCHECK_MSG( data, image, wxT("unable to create image") );
164
165 if (M_IMGDATA->m_hasMask)
166 image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
167
168 long old_height = M_IMGDATA->m_height;
169 long old_width = M_IMGDATA->m_width;
170
171 char unsigned *source_data = M_IMGDATA->m_data;
172 char unsigned *target_data = data;
173
174 for (long j = 0; j < height; j++)
175 {
176 long y_offset = (j * old_height / height) * old_width;
177
178 for (long i = 0; i < width; i++)
179 {
180 memcpy( target_data,
181 source_data + 3*(y_offset + ((i * old_width )/ width)),
182 3 );
183 target_data += 3;
184 }
185 }
186
187 return image;
188 }
189
190 wxImage wxImage::GetSubImage( const wxRect &rect ) const
191 {
192 wxImage image;
193
194 wxCHECK_MSG( Ok(), image, wxT("invalid image") );
195
196 wxCHECK_MSG( (rect.GetLeft()>=0) && (rect.GetTop()>=0) && (rect.GetRight()<=GetWidth()) && (rect.GetBottom()<=GetHeight()),
197 image, wxT("invalid subimage size") );
198
199 int subwidth=rect.GetWidth();
200 const int subheight=rect.GetHeight();
201
202 image.Create( subwidth, subheight );
203
204 char unsigned *subdata = image.GetData(), *data=GetData();
205
206 wxCHECK_MSG( subdata, image, wxT("unable to create image") );
207
208 if (M_IMGDATA->m_hasMask)
209 image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
210
211 const int subleft=3*rect.GetLeft();
212 const int width=3*GetWidth();
213 subwidth*=3;
214
215 data+=rect.GetTop()*width+subleft;
216
217 for (long j = 0; j < subheight; ++j)
218 {
219 memcpy( subdata, data, subwidth);
220 subdata+=subwidth;
221 data+=width;
222 }
223
224 return image;
225 }
226
227 void wxImage::Replace( unsigned char r1, unsigned char g1, unsigned char b1,
228 unsigned char r2, unsigned char g2, unsigned char b2 )
229 {
230 wxCHECK_RET( Ok(), wxT("invalid image") );
231
232 char unsigned *data = GetData();
233
234 const int w = GetWidth();
235 const int h = GetHeight();
236
237 for (int j = 0; j < h; j++)
238 for (int i = 0; i < w; i++)
239 {
240 if ((data[0] == r1) && (data[1] == g1) && (data[2] == b1))
241 {
242 data[0] = r2;
243 data[1] = g2;
244 data[2] = b2;
245 }
246 data += 3;
247 }
248 }
249
250 void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b )
251 {
252 wxCHECK_RET( Ok(), wxT("invalid image") );
253
254 int w = M_IMGDATA->m_width;
255 int h = M_IMGDATA->m_height;
256
257 wxCHECK_RET( (x>=0) && (y>=0) && (x<w) && (y<h), wxT("invalid image index") );
258
259 long pos = (y * w + x) * 3;
260
261 M_IMGDATA->m_data[ pos ] = r;
262 M_IMGDATA->m_data[ pos+1 ] = g;
263 M_IMGDATA->m_data[ pos+2 ] = b;
264 }
265
266 unsigned char wxImage::GetRed( int x, int y )
267 {
268 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
269
270 int w = M_IMGDATA->m_width;
271 int h = M_IMGDATA->m_height;
272
273 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
274
275 long pos = (y * w + x) * 3;
276
277 return M_IMGDATA->m_data[pos];
278 }
279
280 unsigned char wxImage::GetGreen( int x, int y )
281 {
282 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
283
284 int w = M_IMGDATA->m_width;
285 int h = M_IMGDATA->m_height;
286
287 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
288
289 long pos = (y * w + x) * 3;
290
291 return M_IMGDATA->m_data[pos+1];
292 }
293
294 unsigned char wxImage::GetBlue( int x, int y )
295 {
296 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
297
298 int w = M_IMGDATA->m_width;
299 int h = M_IMGDATA->m_height;
300
301 wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
302
303 long pos = (y * w + x) * 3;
304
305 return M_IMGDATA->m_data[pos+2];
306 }
307
308 bool wxImage::Ok() const
309 {
310 return (M_IMGDATA && M_IMGDATA->m_ok);
311 }
312
313 char unsigned *wxImage::GetData() const
314 {
315 wxCHECK_MSG( Ok(), (char unsigned *)NULL, wxT("invalid image") );
316
317 return M_IMGDATA->m_data;
318 }
319
320 void wxImage::SetData( char unsigned *data )
321 {
322 wxCHECK_RET( Ok(), wxT("invalid image") );
323
324 wxImageRefData *newRefData = new wxImageRefData();
325
326 newRefData->m_width = M_IMGDATA->m_width;
327 newRefData->m_height = M_IMGDATA->m_height;
328 newRefData->m_data = data;
329 newRefData->m_ok = TRUE;
330 newRefData->m_maskRed = M_IMGDATA->m_maskRed;
331 newRefData->m_maskGreen = M_IMGDATA->m_maskGreen;
332 newRefData->m_maskBlue = M_IMGDATA->m_maskBlue;
333 newRefData->m_hasMask = M_IMGDATA->m_hasMask;
334
335 UnRef();
336
337 m_refData = newRefData;
338 }
339
340 void wxImage::SetMaskColour( unsigned char r, unsigned char g, unsigned char b )
341 {
342 wxCHECK_RET( Ok(), wxT("invalid image") );
343
344 M_IMGDATA->m_maskRed = r;
345 M_IMGDATA->m_maskGreen = g;
346 M_IMGDATA->m_maskBlue = b;
347 M_IMGDATA->m_hasMask = TRUE;
348 }
349
350 unsigned char wxImage::GetMaskRed() const
351 {
352 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
353
354 return M_IMGDATA->m_maskRed;
355 }
356
357 unsigned char wxImage::GetMaskGreen() const
358 {
359 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
360
361 return M_IMGDATA->m_maskGreen;
362 }
363
364 unsigned char wxImage::GetMaskBlue() const
365 {
366 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
367
368 return M_IMGDATA->m_maskBlue;
369 }
370
371 void wxImage::SetMask( bool mask )
372 {
373 wxCHECK_RET( Ok(), wxT("invalid image") );
374
375 M_IMGDATA->m_hasMask = mask;
376 }
377
378 bool wxImage::HasMask() const
379 {
380 wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") );
381
382 return M_IMGDATA->m_hasMask;
383 }
384
385 int wxImage::GetWidth() const
386 {
387 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
388
389 return M_IMGDATA->m_width;
390 }
391
392 int wxImage::GetHeight() const
393 {
394 wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
395
396 return M_IMGDATA->m_height;
397 }
398
399 bool wxImage::LoadFile( const wxString& filename, long type )
400 {
401 #if wxUSE_STREAMS
402 if (wxFileExists(filename))
403 {
404 wxFileInputStream stream(filename);
405 wxBufferedInputStream bstream( stream );
406 return LoadFile(bstream, type);
407 }
408 else
409 {
410 wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() );
411
412 return FALSE;
413 }
414 #else // !wxUSE_STREAMS
415 return FALSE;
416 #endif // wxUSE_STREAMS
417 }
418
419 bool wxImage::LoadFile( const wxString& filename, const wxString& mimetype )
420 {
421 #if wxUSE_STREAMS
422 if (wxFileExists(filename))
423 {
424 wxFileInputStream stream(filename);
425 wxBufferedInputStream bstream( stream );
426 return LoadFile(bstream, mimetype);
427 }
428 else
429 {
430 wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() );
431
432 return FALSE;
433 }
434 #else // !wxUSE_STREAMS
435 return FALSE;
436 #endif // wxUSE_STREAMS
437 }
438
439 bool wxImage::SaveFile( const wxString& filename, int type )
440 {
441 #if wxUSE_STREAMS
442 wxFileOutputStream stream(filename);
443
444 if ( stream.LastError() == wxStream_NOERROR )
445 {
446 wxBufferedOutputStream bstream( stream );
447 return SaveFile(bstream, type);
448 }
449 else
450 #endif // wxUSE_STREAMS
451 return FALSE;
452 }
453
454 bool wxImage::SaveFile( const wxString& filename, const wxString& mimetype )
455 {
456 #if wxUSE_STREAMS
457 wxFileOutputStream stream(filename);
458
459 if ( stream.LastError() == wxStream_NOERROR )
460 {
461 wxBufferedOutputStream bstream( stream );
462 return SaveFile(bstream, mimetype);
463 }
464 else
465 #endif // wxUSE_STREAMS
466 return FALSE;
467 }
468
469 bool wxImage::CanRead( const wxString &name )
470 {
471 #if wxUSE_STREAMS
472 wxFileInputStream stream(name);
473 return CanRead(stream);
474 #else
475 return FALSE;
476 #endif
477 }
478
479 #if wxUSE_STREAMS
480
481 bool wxImage::CanRead( wxInputStream &stream )
482 {
483 wxList &list=GetHandlers();
484
485 for ( wxList::Node *node = list.GetFirst(); node; node = node->GetNext() )
486 {
487 wxImageHandler *handler=(wxImageHandler*)node->GetData();
488 if (handler->CanRead( stream ))
489 return TRUE;
490 }
491
492 return FALSE;
493 }
494
495 bool wxImage::LoadFile( wxInputStream& stream, long type )
496 {
497 UnRef();
498
499 m_refData = new wxImageRefData;
500
501 wxImageHandler *handler;
502
503 if (type==wxBITMAP_TYPE_ANY)
504 {
505 wxList &list=GetHandlers();
506
507 for ( wxList::Node *node = list.GetFirst(); node; node = node->GetNext() )
508 {
509 handler=(wxImageHandler*)node->GetData();
510 if (handler->CanRead( stream ))
511 return handler->LoadFile( this, stream );
512
513 }
514
515 wxLogWarning( _("No handler found for image type.") );
516 return FALSE;
517 }
518
519 handler = FindHandler(type);
520
521 if (handler == NULL)
522 {
523 wxLogWarning( _("No image handler for type %d defined."), type );
524
525 return FALSE;
526 }
527
528 return handler->LoadFile( this, stream );
529 }
530
531 bool wxImage::LoadFile( wxInputStream& stream, const wxString& mimetype )
532 {
533 UnRef();
534
535 m_refData = new wxImageRefData;
536
537 wxImageHandler *handler = FindHandlerMime(mimetype);
538
539 if (handler == NULL)
540 {
541 wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() );
542
543 return FALSE;
544 }
545
546 return handler->LoadFile( this, stream );
547 }
548
549 bool wxImage::SaveFile( wxOutputStream& stream, int type )
550 {
551 wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") );
552
553 wxImageHandler *handler = FindHandler(type);
554
555 if (handler == NULL)
556 {
557 wxLogWarning( _("No image handler for type %d defined."), type );
558
559 return FALSE;
560 }
561
562 return handler->SaveFile( this, stream );
563 }
564
565 bool wxImage::SaveFile( wxOutputStream& stream, const wxString& mimetype )
566 {
567 wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") );
568
569 wxImageHandler *handler = FindHandlerMime(mimetype);
570
571 if (handler == NULL)
572 {
573 wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() );
574
575 return FALSE;
576 }
577
578 return handler->SaveFile( this, stream );
579 }
580 #endif // wxUSE_STREAMS
581
582 void wxImage::AddHandler( wxImageHandler *handler )
583 {
584 // make sure that the memory will be freed at the program end
585 sm_handlers.DeleteContents(TRUE);
586
587 sm_handlers.Append( handler );
588 }
589
590 void wxImage::InsertHandler( wxImageHandler *handler )
591 {
592 // make sure that the memory will be freed at the program end
593 sm_handlers.DeleteContents(TRUE);
594
595 sm_handlers.Insert( handler );
596 }
597
598 bool wxImage::RemoveHandler( const wxString& name )
599 {
600 wxImageHandler *handler = FindHandler(name);
601 if (handler)
602 {
603 sm_handlers.DeleteObject(handler);
604 return TRUE;
605 }
606 else
607 return FALSE;
608 }
609
610 wxImageHandler *wxImage::FindHandler( const wxString& name )
611 {
612 wxNode *node = sm_handlers.First();
613 while (node)
614 {
615 wxImageHandler *handler = (wxImageHandler*)node->Data();
616 if (handler->GetName().Cmp(name) == 0) return handler;
617
618 node = node->Next();
619 }
620 return (wxImageHandler *)NULL;
621 }
622
623 wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType )
624 {
625 wxNode *node = sm_handlers.First();
626 while (node)
627 {
628 wxImageHandler *handler = (wxImageHandler*)node->Data();
629 if ( (handler->GetExtension().Cmp(extension) == 0) &&
630 (bitmapType == -1 || handler->GetType() == bitmapType) )
631 return handler;
632 node = node->Next();
633 }
634 return (wxImageHandler*)NULL;
635 }
636
637 wxImageHandler *wxImage::FindHandler( long bitmapType )
638 {
639 wxNode *node = sm_handlers.First();
640 while (node)
641 {
642 wxImageHandler *handler = (wxImageHandler *)node->Data();
643 if (handler->GetType() == bitmapType) return handler;
644 node = node->Next();
645 }
646 return NULL;
647 }
648
649 wxImageHandler *wxImage::FindHandlerMime( const wxString& mimetype )
650 {
651 wxNode *node = sm_handlers.First();
652 while (node)
653 {
654 wxImageHandler *handler = (wxImageHandler *)node->Data();
655 if (handler->GetMimeType().IsSameAs(mimetype, FALSE)) return handler;
656 node = node->Next();
657 }
658 return NULL;
659 }
660
661 void wxImage::InitStandardHandlers()
662 {
663 AddHandler( new wxBMPHandler );
664 }
665
666 void wxImage::CleanUpHandlers()
667 {
668 wxNode *node = sm_handlers.First();
669 while (node)
670 {
671 wxImageHandler *handler = (wxImageHandler *)node->Data();
672 wxNode *next = node->Next();
673 delete handler;
674 delete node;
675 node = next;
676 }
677 }
678
679 //-----------------------------------------------------------------------------
680 // wxImageHandler
681 //-----------------------------------------------------------------------------
682
683 IMPLEMENT_ABSTRACT_CLASS(wxImageHandler,wxObject)
684
685 #if wxUSE_STREAMS
686 bool wxImageHandler::LoadFile( wxImage *WXUNUSED(image), wxInputStream& WXUNUSED(stream), bool WXUNUSED(verbose), int WXUNUSED(index) )
687 {
688 return FALSE;
689 }
690
691 bool wxImageHandler::SaveFile( wxImage *WXUNUSED(image), wxOutputStream& WXUNUSED(stream), bool WXUNUSED(verbose) )
692 {
693 return FALSE;
694 }
695
696 int wxImageHandler::GetImageCount( wxInputStream& WXUNUSED(stream) )
697 {
698 return 1;
699 }
700
701 bool wxImageHandler::CanRead( const wxString& name )
702 {
703 if (wxFileExists(name))
704 {
705 wxFileInputStream stream(name);
706 return CanRead(stream);
707 }
708
709 else {
710 wxLogError( _("Can't check image format of file '%s': file does not exist."), name.c_str() );
711
712 return FALSE;
713 }
714 // return FALSE;
715 }
716
717 #endif // wxUSE_STREAMS
718
719 //-----------------------------------------------------------------------------
720 // MSW conversion routines
721 //-----------------------------------------------------------------------------
722
723 #ifdef __WXMSW__
724
725 wxBitmap wxImage::ConvertToBitmap() const
726 {
727 if ( !Ok() )
728 return wxNullBitmap;
729
730 // sizeLimit is the MS upper limit for the DIB size
731 #ifdef WIN32
732 int sizeLimit = 1024*768*3;
733 #else
734 int sizeLimit = 0x7fff ;
735 #endif
736
737 // width and height of the device-dependent bitmap
738 int width = GetWidth();
739 int bmpHeight = GetHeight();
740
741 // calc the number of bytes per scanline and padding
742 int bytePerLine = width*3;
743 int sizeDWORD = sizeof( DWORD );
744 int lineBoundary = bytePerLine % sizeDWORD;
745 int padding = 0;
746 if( lineBoundary > 0 )
747 {
748 padding = sizeDWORD - lineBoundary;
749 bytePerLine += padding;
750 }
751 // calc the number of DIBs and heights of DIBs
752 int numDIB = 1;
753 int hRemain = 0;
754 int height = sizeLimit/bytePerLine;
755 if( height >= bmpHeight )
756 height = bmpHeight;
757 else
758 {
759 numDIB = bmpHeight / height;
760 hRemain = bmpHeight % height;
761 if( hRemain >0 ) numDIB++;
762 }
763
764 // set bitmap parameters
765 wxBitmap bitmap;
766 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
767 bitmap.SetWidth( width );
768 bitmap.SetHeight( bmpHeight );
769 bitmap.SetDepth( wxDisplayDepth() );
770
771 // create a DIB header
772 int headersize = sizeof(BITMAPINFOHEADER);
773 BITMAPINFO *lpDIBh = (BITMAPINFO *) malloc( headersize );
774 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
775 // Fill in the DIB header
776 lpDIBh->bmiHeader.biSize = headersize;
777 lpDIBh->bmiHeader.biWidth = (DWORD)width;
778 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
779 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
780 // the general formula for biSizeImage:
781 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
782 lpDIBh->bmiHeader.biPlanes = 1;
783 lpDIBh->bmiHeader.biBitCount = 24;
784 lpDIBh->bmiHeader.biCompression = BI_RGB;
785 lpDIBh->bmiHeader.biClrUsed = 0;
786 // These seem not really needed for our purpose here.
787 lpDIBh->bmiHeader.biClrImportant = 0;
788 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
789 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
790 // memory for DIB data
791 unsigned char *lpBits;
792 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
793 if( !lpBits )
794 {
795 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
796 free( lpDIBh );
797 return bitmap;
798 }
799
800 // create and set the device-dependent bitmap
801 HDC hdc = ::GetDC(NULL);
802 HDC memdc = ::CreateCompatibleDC( hdc );
803 HBITMAP hbitmap;
804 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
805 ::SelectObject( memdc, hbitmap);
806
807 // copy image data into DIB data and then into DDB (in a loop)
808 unsigned char *data = GetData();
809 int i, j, n;
810 int origin = 0;
811 unsigned char *ptdata = data;
812 unsigned char *ptbits;
813
814 for( n=0; n<numDIB; n++ )
815 {
816 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
817 {
818 // redefine height and size of the (possibly) last smaller DIB
819 // memory is not reallocated
820 height = hRemain;
821 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
822 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
823 }
824 ptbits = lpBits;
825
826 for( j=0; j<height; j++ )
827 {
828 for( i=0; i<width; i++ )
829 {
830 *(ptbits++) = *(ptdata+2);
831 *(ptbits++) = *(ptdata+1);
832 *(ptbits++) = *(ptdata );
833 ptdata += 3;
834 }
835 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
836 }
837 ::StretchDIBits( memdc, 0, origin, width, height,\
838 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
839 origin += height;
840 // if numDIB = 1, lines below can also be used
841 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
842 // The above line is equivalent to the following two lines.
843 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
844 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
845 // or the following lines
846 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
847 // HDC memdc = ::CreateCompatibleDC( hdc );
848 // ::SelectObject( memdc, hbitmap);
849 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
850 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
851 // ::SelectObject( memdc, 0 );
852 // ::DeleteDC( memdc );
853 }
854 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
855
856 // similarly, created an mono-bitmap for the possible mask
857 if( HasMask() )
858 {
859 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
860 HGDIOBJ hbmpOld = ::SelectObject( memdc, hbitmap);
861 if( numDIB == 1 ) height = bmpHeight;
862 else height = sizeLimit/bytePerLine;
863 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
864 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
865 origin = 0;
866 unsigned char r = GetMaskRed();
867 unsigned char g = GetMaskGreen();
868 unsigned char b = GetMaskBlue();
869 unsigned char zero = 0, one = 255;
870 ptdata = data;
871 for( n=0; n<numDIB; n++ )
872 {
873 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
874 {
875 // redefine height and size of the (possibly) last smaller DIB
876 // memory is not reallocated
877 height = hRemain;
878 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
879 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
880 }
881 ptbits = lpBits;
882 for( int j=0; j<height; j++ )
883 {
884 for(i=0; i<width; i++ )
885 {
886 // was causing a code gen bug in cw : if( ( cr !=r) || (cg!=g) || (cb!=b) )
887 unsigned char cr = (*(ptdata++)) ;
888 unsigned char cg = (*(ptdata++)) ;
889 unsigned char cb = (*(ptdata++)) ;
890
891 if( ( cr !=r) || (cg!=g) || (cb!=b) )
892 {
893 *(ptbits++) = one;
894 *(ptbits++) = one;
895 *(ptbits++) = one;
896 }
897 else
898 {
899 *(ptbits++) = zero;
900 *(ptbits++) = zero;
901 *(ptbits++) = zero;
902 }
903 }
904 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
905 }
906 ::StretchDIBits( memdc, 0, origin, width, height,\
907 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
908 origin += height;
909 }
910 // create a wxMask object
911 wxMask *mask = new wxMask();
912 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
913 bitmap.SetMask( mask );
914 // It will be deleted when the wxBitmap object is deleted (as of 01/1999)
915 /* The following can also be used but is slow to run
916 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
917 wxMask *mask = new wxMask( bitmap, colour );
918 bitmap.SetMask( mask );
919 */
920
921 ::SelectObject( memdc, hbmpOld );
922 }
923
924 // free allocated resources
925 ::DeleteDC( memdc );
926 ::ReleaseDC(NULL, hdc);
927 free(lpDIBh);
928 free(lpBits);
929
930 #if WXWIN_COMPATIBILITY_2
931 // check the wxBitmap object
932 bitmap.GetBitmapData()->SetOk();
933 #endif // WXWIN_COMPATIBILITY_2
934
935 return bitmap;
936 }
937
938 wxImage::wxImage( const wxBitmap &bitmap )
939 {
940 // check the bitmap
941 if( !bitmap.Ok() )
942 {
943 wxFAIL_MSG( wxT("invalid bitmap") );
944 return;
945 }
946
947 // create an wxImage object
948 int width = bitmap.GetWidth();
949 int height = bitmap.GetHeight();
950 Create( width, height );
951 unsigned char *data = GetData();
952 if( !data )
953 {
954 wxFAIL_MSG( wxT("could not allocate data for image") );
955 return;
956 }
957
958 // calc the number of bytes per scanline and padding in the DIB
959 int bytePerLine = width*3;
960 int sizeDWORD = sizeof( DWORD );
961 int lineBoundary = bytePerLine % sizeDWORD;
962 int padding = 0;
963 if( lineBoundary > 0 )
964 {
965 padding = sizeDWORD - lineBoundary;
966 bytePerLine += padding;
967 }
968
969 // create a DIB header
970 int headersize = sizeof(BITMAPINFOHEADER);
971 BITMAPINFO *lpDIBh = (BITMAPINFO *) malloc( headersize );
972 if( !lpDIBh )
973 {
974 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
975 free( data );
976 return;
977 }
978 // Fill in the DIB header
979 lpDIBh->bmiHeader.biSize = headersize;
980 lpDIBh->bmiHeader.biWidth = width;
981 lpDIBh->bmiHeader.biHeight = -height;
982 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
983 lpDIBh->bmiHeader.biPlanes = 1;
984 lpDIBh->bmiHeader.biBitCount = 24;
985 lpDIBh->bmiHeader.biCompression = BI_RGB;
986 lpDIBh->bmiHeader.biClrUsed = 0;
987 // These seem not really needed for our purpose here.
988 lpDIBh->bmiHeader.biClrImportant = 0;
989 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
990 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
991 // memory for DIB data
992 unsigned char *lpBits;
993 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
994 if( !lpBits )
995 {
996 wxFAIL_MSG( wxT("could not allocate data for DIB") );
997 free( data );
998 free( lpDIBh );
999 return;
1000 }
1001
1002 // copy data from the device-dependent bitmap to the DIB
1003 HDC hdc = ::GetDC(NULL);
1004 HBITMAP hbitmap;
1005 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1006 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1007
1008 // copy DIB data into the wxImage object
1009 int i, j;
1010 unsigned char *ptdata = data;
1011 unsigned char *ptbits = lpBits;
1012 for( i=0; i<height; i++ )
1013 {
1014 for( j=0; j<width; j++ )
1015 {
1016 *(ptdata++) = *(ptbits+2);
1017 *(ptdata++) = *(ptbits+1);
1018 *(ptdata++) = *(ptbits );
1019 ptbits += 3;
1020 }
1021 ptbits += padding;
1022 }
1023
1024 // similarly, set data according to the possible mask bitmap
1025 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1026 {
1027 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1028 // memory DC created, color set, data copied, and memory DC deleted
1029 HDC memdc = ::CreateCompatibleDC( hdc );
1030 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1031 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1032 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1033 ::DeleteDC( memdc );
1034 // background color set to RGB(16,16,16) in consistent with wxGTK
1035 unsigned char r=16, g=16, b=16;
1036 ptdata = data;
1037 ptbits = lpBits;
1038 for( i=0; i<height; i++ )
1039 {
1040 for( j=0; j<width; j++ )
1041 {
1042 if( *ptbits != 0 )
1043 ptdata += 3;
1044 else
1045 {
1046 *(ptdata++) = r;
1047 *(ptdata++) = g;
1048 *(ptdata++) = b;
1049 }
1050 ptbits += 3;
1051 }
1052 ptbits += padding;
1053 }
1054 SetMaskColour( r, g, b );
1055 SetMask( TRUE );
1056 }
1057 else
1058 {
1059 SetMask( FALSE );
1060 }
1061 // free allocated resources
1062 ::ReleaseDC(NULL, hdc);
1063 free(lpDIBh);
1064 free(lpBits);
1065 }
1066
1067 #endif
1068
1069 #ifdef __WXMAC__
1070
1071 #include <PictUtils.h>
1072
1073 extern CTabHandle wxMacCreateColorTable( int numColors ) ;
1074 extern void wxMacDestroyColorTable( CTabHandle colors ) ;
1075 extern void wxMacSetColorTableEntry( CTabHandle newColors , int index , int red , int green , int blue ) ;
1076 extern GWorldPtr wxMacCreateGWorld( int height , int width , int depth ) ;
1077 extern void wxMacDestroyGWorld( GWorldPtr gw ) ;
1078
1079 wxBitmap wxImage::ConvertToBitmap() const
1080 {
1081 // width and height of the device-dependent bitmap
1082 int width = GetWidth();
1083 int height = GetHeight();
1084
1085 // Create picture
1086
1087 wxBitmap bitmap( width , height , wxDisplayDepth() ) ;
1088
1089 // Create mask
1090
1091 if (HasMask())
1092 {
1093 /*
1094 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1095
1096 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1097
1098 wxMask *mask = new wxMask();
1099 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1100
1101 bitmap.SetMask( mask );
1102 */
1103 }
1104
1105 // Render
1106
1107 int r_mask = GetMaskRed();
1108 int g_mask = GetMaskGreen();
1109 int b_mask = GetMaskBlue();
1110
1111 CGrafPtr origPort ;
1112 GDHandle origDevice ;
1113
1114 GetGWorld( &origPort , &origDevice ) ;
1115 SetGWorld( bitmap.GetHBITMAP() , NULL ) ;
1116
1117 register unsigned char* data = GetData();
1118
1119 int index = 0;
1120 for (int y = 0; y < height; y++)
1121 {
1122 for (int x = 0; x < width; x++)
1123 {
1124 unsigned char r = data[index++];
1125 unsigned char g = data[index++];
1126 unsigned char b = data[index++];
1127 RGBColor color ;
1128 color.red = ( r << 8 ) + r ;
1129 color.green = ( g << 8 ) + g ;
1130 color.blue = ( b << 8 ) + b ;
1131 SetCPixel( x , y , &color ) ;
1132 }
1133 } // for height
1134
1135 SetGWorld( origPort , origDevice ) ;
1136
1137 if ( HasMask() )
1138 {
1139 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1140 wxMask *mask = new wxMask( bitmap, colour );
1141 bitmap.SetMask( mask );
1142 }
1143 return bitmap;
1144
1145 }
1146
1147 wxImage::wxImage( const wxBitmap &bitmap )
1148 {
1149 // check the bitmap
1150 if( !bitmap.Ok() )
1151 {
1152 wxFAIL_MSG( "invalid bitmap" );
1153 return;
1154 }
1155
1156 // create an wxImage object
1157 int width = bitmap.GetWidth();
1158 int height = bitmap.GetHeight();
1159 Create( width, height );
1160 /*
1161 unsigned char *data = GetData();
1162 if( !data )
1163 {
1164 wxFAIL_MSG( "could not allocate data for image" );
1165 return;
1166 }
1167
1168 // calc the number of bytes per scanline and padding in the DIB
1169 int bytePerLine = width*3;
1170 int sizeDWORD = sizeof( DWORD );
1171 div_t lineBoundary = div( bytePerLine, sizeDWORD );
1172 int padding = 0;
1173 if( lineBoundary.rem > 0 )
1174 {
1175 padding = sizeDWORD - lineBoundary.rem;
1176 bytePerLine += padding;
1177 }
1178
1179 // create a DIB header
1180 int headersize = sizeof(BITMAPINFOHEADER);
1181 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
1182 if( !lpDIBh )
1183 {
1184 wxFAIL_MSG( "could not allocate data for DIB header" );
1185 free( data );
1186 return;
1187 }
1188 // Fill in the DIB header
1189 lpDIBh->bmiHeader.biSize = headersize;
1190 lpDIBh->bmiHeader.biWidth = width;
1191 lpDIBh->bmiHeader.biHeight = -height;
1192 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
1193 lpDIBh->bmiHeader.biPlanes = 1;
1194 lpDIBh->bmiHeader.biBitCount = 24;
1195 lpDIBh->bmiHeader.biCompression = BI_RGB;
1196 lpDIBh->bmiHeader.biClrUsed = 0;
1197 // These seem not really needed for our purpose here.
1198 lpDIBh->bmiHeader.biClrImportant = 0;
1199 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1200 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1201 // memory for DIB data
1202 unsigned char *lpBits;
1203 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
1204 if( !lpBits )
1205 {
1206 wxFAIL_MSG( "could not allocate data for DIB" );
1207 free( data );
1208 free( lpDIBh );
1209 return;
1210 }
1211
1212 // copy data from the device-dependent bitmap to the DIB
1213 HDC hdc = ::GetDC(NULL);
1214 HBITMAP hbitmap;
1215 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1216 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1217
1218 // copy DIB data into the wxImage object
1219 int i, j;
1220 unsigned char *ptdata = data;
1221 unsigned char *ptbits = lpBits;
1222 for( i=0; i<height; i++ )
1223 {
1224 for( j=0; j<width; j++ )
1225 {
1226 *(ptdata++) = *(ptbits+2);
1227 *(ptdata++) = *(ptbits+1);
1228 *(ptdata++) = *(ptbits );
1229 ptbits += 3;
1230 }
1231 ptbits += padding;
1232 }
1233
1234 // similarly, set data according to the possible mask bitmap
1235 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1236 {
1237 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1238 // memory DC created, color set, data copied, and memory DC deleted
1239 HDC memdc = ::CreateCompatibleDC( hdc );
1240 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1241 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1242 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1243 ::DeleteDC( memdc );
1244 // background color set to RGB(16,16,16) in consistent with wxGTK
1245 unsigned char r=16, g=16, b=16;
1246 ptdata = data;
1247 ptbits = lpBits;
1248 for( i=0; i<height; i++ )
1249 {
1250 for( j=0; j<width; j++ )
1251 {
1252 if( *ptbits != 0 )
1253 ptdata += 3;
1254 else
1255 {
1256 *(ptdata++) = r;
1257 *(ptdata++) = g;
1258 *(ptdata++) = b;
1259 }
1260 ptbits += 3;
1261 }
1262 ptbits += padding;
1263 }
1264 SetMaskColour( r, g, b );
1265 SetMask( TRUE );
1266 }
1267 else
1268 {
1269 SetMask( FALSE );
1270 }
1271 // free allocated resources
1272 ::ReleaseDC(NULL, hdc);
1273 free(lpDIBh);
1274 free(lpBits);
1275 */
1276 }
1277
1278 #endif
1279
1280 //-----------------------------------------------------------------------------
1281 // GTK conversion routines
1282 //-----------------------------------------------------------------------------
1283
1284 #ifdef __WXGTK__
1285
1286 #include <gtk/gtk.h>
1287 #include <gdk/gdk.h>
1288 #include <gdk/gdkx.h>
1289
1290 #if (GTK_MINOR_VERSION > 0)
1291 #include <gdk/gdkrgb.h>
1292 #endif
1293
1294 extern GtkWidget *wxRootWindow;
1295
1296 wxBitmap wxImage::ConvertToMonoBitmap( unsigned char red, unsigned char green, unsigned char blue )
1297 {
1298 wxBitmap bitmap;
1299
1300 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
1301
1302 int width = GetWidth();
1303 int height = GetHeight();
1304
1305 bitmap.SetHeight( height );
1306 bitmap.SetWidth( width );
1307
1308 bitmap.SetBitmap( gdk_pixmap_new( wxRootWindow->window, width, height, 1 ) );
1309
1310 bitmap.SetDepth( 1 );
1311
1312 // Create picture image
1313
1314 unsigned char *data_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1315
1316 GdkImage *data_image =
1317 gdk_image_new_bitmap( gdk_visual_get_system(), data_data, width, height );
1318
1319 // Create mask image
1320
1321 GdkImage *mask_image = (GdkImage*) NULL;
1322
1323 if (HasMask())
1324 {
1325 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1326
1327 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1328
1329 wxMask *mask = new wxMask();
1330 mask->m_bitmap = gdk_pixmap_new( wxRootWindow->window, width, height, 1 );
1331
1332 bitmap.SetMask( mask );
1333 }
1334
1335 int r_mask = GetMaskRed();
1336 int g_mask = GetMaskGreen();
1337 int b_mask = GetMaskBlue();
1338
1339 unsigned char* data = GetData();
1340
1341 int index = 0;
1342 for (int y = 0; y < height; y++)
1343 {
1344 for (int x = 0; x < width; x++)
1345 {
1346 int r = data[index];
1347 index++;
1348 int g = data[index];
1349 index++;
1350 int b = data[index];
1351 index++;
1352
1353 if (HasMask())
1354 {
1355 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1356 gdk_image_put_pixel( mask_image, x, y, 1 );
1357 else
1358 gdk_image_put_pixel( mask_image, x, y, 0 );
1359 }
1360
1361 if ((r == red) && (b == blue) && (g == green))
1362 gdk_image_put_pixel( data_image, x, y, 1 );
1363 else
1364 gdk_image_put_pixel( data_image, x, y, 0 );
1365
1366 } // for
1367 } // for
1368
1369 // Blit picture
1370
1371 GdkGC *data_gc = gdk_gc_new( bitmap.GetBitmap() );
1372
1373 gdk_draw_image( bitmap.GetBitmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
1374
1375 gdk_image_destroy( data_image );
1376 gdk_gc_unref( data_gc );
1377
1378 // Blit mask
1379
1380 if (HasMask())
1381 {
1382 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
1383
1384 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
1385
1386 gdk_image_destroy( mask_image );
1387 gdk_gc_unref( mask_gc );
1388 }
1389
1390 return bitmap;
1391 }
1392
1393
1394 wxBitmap wxImage::ConvertToBitmap() const
1395 {
1396 wxBitmap bitmap;
1397
1398 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
1399
1400 int width = GetWidth();
1401 int height = GetHeight();
1402
1403 bitmap.SetHeight( height );
1404 bitmap.SetWidth( width );
1405
1406 bitmap.SetPixmap( gdk_pixmap_new( wxRootWindow->window, width, height, -1 ) );
1407
1408 // Retrieve depth
1409
1410 GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
1411 if (visual == NULL) visual = gdk_visual_get_system();
1412 int bpp = visual->depth;
1413
1414 bitmap.SetDepth( bpp );
1415
1416 if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
1417 if (bpp < 8) bpp = 8;
1418
1419 #if (GTK_MINOR_VERSION > 0)
1420
1421 if (!HasMask() && (bpp > 8))
1422 {
1423 static bool s_hasInitialized = FALSE;
1424
1425 if (!s_hasInitialized)
1426 {
1427 gdk_rgb_init();
1428 s_hasInitialized = TRUE;
1429 }
1430
1431 GdkGC *gc = gdk_gc_new( bitmap.GetPixmap() );
1432
1433 gdk_draw_rgb_image( bitmap.GetPixmap(),
1434 gc,
1435 0, 0,
1436 width, height,
1437 GDK_RGB_DITHER_NONE,
1438 GetData(),
1439 width*3 );
1440
1441 gdk_gc_unref( gc );
1442
1443 return bitmap;
1444 }
1445
1446 #endif
1447
1448 // Create picture image
1449
1450 GdkImage *data_image =
1451 gdk_image_new( GDK_IMAGE_FASTEST, gdk_visual_get_system(), width, height );
1452
1453 // Create mask image
1454
1455 GdkImage *mask_image = (GdkImage*) NULL;
1456
1457 if (HasMask())
1458 {
1459 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1460
1461 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1462
1463 wxMask *mask = new wxMask();
1464 mask->m_bitmap = gdk_pixmap_new( wxRootWindow->window, width, height, 1 );
1465
1466 bitmap.SetMask( mask );
1467 }
1468
1469 // Render
1470
1471 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1472 byte_order b_o = RGB;
1473
1474 if (bpp >= 24)
1475 {
1476 GdkVisual *visual = gdk_visual_get_system();
1477 if ((visual->red_mask > visual->green_mask) && (visual->green_mask > visual->blue_mask)) b_o = RGB;
1478 else if ((visual->red_mask > visual->blue_mask) && (visual->blue_mask > visual->green_mask)) b_o = RGB;
1479 else if ((visual->blue_mask > visual->red_mask) && (visual->red_mask > visual->green_mask)) b_o = BRG;
1480 else if ((visual->blue_mask > visual->green_mask) && (visual->green_mask > visual->red_mask)) b_o = BGR;
1481 else if ((visual->green_mask > visual->red_mask) && (visual->red_mask > visual->blue_mask)) b_o = GRB;
1482 else if ((visual->green_mask > visual->blue_mask) && (visual->blue_mask > visual->red_mask)) b_o = GBR;
1483 }
1484
1485 int r_mask = GetMaskRed();
1486 int g_mask = GetMaskGreen();
1487 int b_mask = GetMaskBlue();
1488
1489 unsigned char* data = GetData();
1490
1491 int index = 0;
1492 for (int y = 0; y < height; y++)
1493 {
1494 for (int x = 0; x < width; x++)
1495 {
1496 int r = data[index];
1497 index++;
1498 int g = data[index];
1499 index++;
1500 int b = data[index];
1501 index++;
1502
1503 if (HasMask())
1504 {
1505 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1506 gdk_image_put_pixel( mask_image, x, y, 1 );
1507 else
1508 gdk_image_put_pixel( mask_image, x, y, 0 );
1509 }
1510
1511 switch (bpp)
1512 {
1513 case 8:
1514 {
1515 int pixel = -1;
1516 if (wxTheApp->m_colorCube)
1517 {
1518 pixel = wxTheApp->m_colorCube[ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
1519 }
1520 else
1521 {
1522 GdkColormap *cmap = gtk_widget_get_default_colormap();
1523 GdkColor *colors = cmap->colors;
1524 int max = 3 * (65536);
1525
1526 for (int i = 0; i < cmap->size; i++)
1527 {
1528 int rdiff = (r << 8) - colors[i].red;
1529 int gdiff = (g << 8) - colors[i].green;
1530 int bdiff = (b << 8) - colors[i].blue;
1531 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
1532 if (sum < max) { pixel = i; max = sum; }
1533 }
1534 }
1535
1536 gdk_image_put_pixel( data_image, x, y, pixel );
1537
1538 break;
1539 }
1540 case 15:
1541 {
1542 guint32 pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
1543 gdk_image_put_pixel( data_image, x, y, pixel );
1544 break;
1545 }
1546 case 16:
1547 {
1548 guint32 pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
1549 gdk_image_put_pixel( data_image, x, y, pixel );
1550 break;
1551 }
1552 case 32:
1553 case 24:
1554 {
1555 guint32 pixel = 0;
1556 switch (b_o)
1557 {
1558 case RGB: pixel = (r << 16) | (g << 8) | b; break;
1559 case RBG: pixel = (r << 16) | (b << 8) | g; break;
1560 case BRG: pixel = (b << 16) | (r << 8) | g; break;
1561 case BGR: pixel = (b << 16) | (g << 8) | r; break;
1562 case GRB: pixel = (g << 16) | (r << 8) | b; break;
1563 case GBR: pixel = (g << 16) | (b << 8) | r; break;
1564 }
1565 gdk_image_put_pixel( data_image, x, y, pixel );
1566 }
1567 default: break;
1568 }
1569 } // for
1570 } // for
1571
1572 // Blit picture
1573
1574 GdkGC *data_gc = gdk_gc_new( bitmap.GetPixmap() );
1575
1576 gdk_draw_image( bitmap.GetPixmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
1577
1578 gdk_image_destroy( data_image );
1579 gdk_gc_unref( data_gc );
1580
1581 // Blit mask
1582
1583 if (HasMask())
1584 {
1585 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
1586
1587 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
1588
1589 gdk_image_destroy( mask_image );
1590 gdk_gc_unref( mask_gc );
1591 }
1592
1593 return bitmap;
1594 }
1595
1596 wxImage::wxImage( const wxBitmap &bitmap )
1597 {
1598 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
1599
1600 GdkImage *gdk_image = (GdkImage*) NULL;
1601 if (bitmap.GetPixmap())
1602 {
1603 gdk_image = gdk_image_get( bitmap.GetPixmap(),
1604 0, 0,
1605 bitmap.GetWidth(), bitmap.GetHeight() );
1606 } else
1607 if (bitmap.GetBitmap())
1608 {
1609 gdk_image = gdk_image_get( bitmap.GetBitmap(),
1610 0, 0,
1611 bitmap.GetWidth(), bitmap.GetHeight() );
1612 } else
1613 {
1614 wxFAIL_MSG( wxT("Ill-formed bitmap") );
1615 }
1616
1617 wxCHECK_RET( gdk_image, wxT("couldn't create image") );
1618
1619 Create( bitmap.GetWidth(), bitmap.GetHeight() );
1620 char unsigned *data = GetData();
1621
1622 if (!data)
1623 {
1624 gdk_image_destroy( gdk_image );
1625 wxFAIL_MSG( wxT("couldn't create image") );
1626 return;
1627 }
1628
1629 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1630 if (bitmap.GetMask())
1631 {
1632 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
1633 0, 0,
1634 bitmap.GetWidth(), bitmap.GetHeight() );
1635
1636 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1637 }
1638
1639 int bpp = -1;
1640 int red_shift_right = 0;
1641 int green_shift_right = 0;
1642 int blue_shift_right = 0;
1643 int red_shift_left = 0;
1644 int green_shift_left = 0;
1645 int blue_shift_left = 0;
1646 bool use_shift = FALSE;
1647
1648 if (bitmap.GetPixmap())
1649 {
1650 GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
1651
1652 if (visual == NULL) visual = gdk_window_get_visual( wxRootWindow->window );
1653 bpp = visual->depth;
1654 if (bpp == 16) bpp = visual->red_prec + visual->green_prec + visual->blue_prec;
1655 red_shift_right = visual->red_shift;
1656 red_shift_left = 8-visual->red_prec;
1657 green_shift_right = visual->green_shift;
1658 green_shift_left = 8-visual->green_prec;
1659 blue_shift_right = visual->blue_shift;
1660 blue_shift_left = 8-visual->blue_prec;
1661
1662 use_shift = (visual->type == GDK_VISUAL_TRUE_COLOR) || (visual->type == GDK_VISUAL_DIRECT_COLOR);
1663 }
1664 if (bitmap.GetBitmap())
1665 {
1666 bpp = 1;
1667 }
1668
1669
1670 GdkColormap *cmap = gtk_widget_get_default_colormap();
1671
1672 long pos = 0;
1673 for (int j = 0; j < bitmap.GetHeight(); j++)
1674 {
1675 for (int i = 0; i < bitmap.GetWidth(); i++)
1676 {
1677 wxUint32 pixel = gdk_image_get_pixel( gdk_image, i, j );
1678 if (bpp == 1)
1679 {
1680 if (pixel == 0)
1681 {
1682 data[pos] = 0;
1683 data[pos+1] = 0;
1684 data[pos+2] = 0;
1685 }
1686 else
1687 {
1688 data[pos] = 255;
1689 data[pos+1] = 255;
1690 data[pos+2] = 255;
1691 }
1692 }
1693 else if (use_shift)
1694 {
1695 data[pos] = (pixel >> red_shift_right) << red_shift_left;
1696 data[pos+1] = (pixel >> green_shift_right) << green_shift_left;
1697 data[pos+2] = (pixel >> blue_shift_right) << blue_shift_left;
1698 }
1699 else if (cmap->colors)
1700 {
1701 data[pos] = cmap->colors[pixel].red >> 8;
1702 data[pos+1] = cmap->colors[pixel].green >> 8;
1703 data[pos+2] = cmap->colors[pixel].blue >> 8;
1704 }
1705 else
1706 {
1707 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
1708 }
1709
1710 if (gdk_image_mask)
1711 {
1712 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1713 if (mask_pixel == 0)
1714 {
1715 data[pos] = 16;
1716 data[pos+1] = 16;
1717 data[pos+2] = 16;
1718 }
1719 }
1720
1721 pos += 3;
1722 }
1723 }
1724
1725 gdk_image_destroy( gdk_image );
1726 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1727 }
1728
1729 #endif
1730
1731 //-----------------------------------------------------------------------------
1732 // Motif conversion routines
1733 //-----------------------------------------------------------------------------
1734
1735 #ifdef __WXMOTIF__
1736 #ifdef __VMS__
1737 #pragma message disable nosimpint
1738 #endif
1739 #include <Xm/Xm.h>
1740 #ifdef __VMS__
1741 #pragma message enable nosimpint
1742 #endif
1743 #include "wx/utils.h"
1744 #include <math.h>
1745
1746 /*
1747
1748 Date: Wed, 05 Jan 2000 11:45:40 +0100
1749 From: Frits Boel <boel@niob.knaw.nl>
1750 To: julian.smart@ukonline.co.uk
1751 Subject: Patch for Motif ConvertToBitmap
1752
1753 Hi Julian,
1754
1755 I've been working on a wxWin application for image processing. From the
1756 beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
1757 till I looked in the source code of image.cpp. I saw that converting a
1758 wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
1759 to the 256 colors of the palet. A very time-consuming piece of code!
1760
1761 Because I wanted a faster application, I've made a 'patch' for this. In
1762 short: every pixel of the image is compared to a sorted list with
1763 colors. If the color is found in the list, the palette entry is
1764 returned; if the color is not found, the color palette is searched and
1765 then the palette entry is returned and the color added to the sorted
1766 list.
1767
1768 Maybe there is another method for this, namely changing the palette
1769 itself (if the colors are known, as is the case with tiffs with a
1770 colormap). I did not look at this, maybe someone else did?
1771
1772 The code of the patch is attached, have a look on it, and maybe you will
1773 ship it with the next release of wxMotif?
1774
1775 Regards,
1776
1777 Frits Boel
1778 Software engineer at Hubrecht Laboratory, The Netherlands.
1779
1780 */
1781
1782 class wxSearchColor
1783 {
1784 public:
1785 wxSearchColor( void );
1786 wxSearchColor( int size, XColor *colors );
1787 ~wxSearchColor( void );
1788
1789 int SearchColor( int r, int g, int b );
1790 private:
1791 int AddColor( unsigned int value, int pos );
1792
1793 int size;
1794 XColor *colors;
1795 unsigned int *color;
1796 int *entry;
1797
1798 int bottom;
1799 int top;
1800 };
1801
1802 wxSearchColor::wxSearchColor( void )
1803 {
1804 size = 0;
1805 colors = (XColor*) NULL;
1806 color = (unsigned int *) NULL;
1807 entry = (int*) NULL;
1808
1809 bottom = 0;
1810 top = 0;
1811 }
1812
1813 wxSearchColor::wxSearchColor( int size_, XColor *colors_ )
1814 {
1815 int i;
1816 size = size_;
1817 colors = colors_;
1818 color = new unsigned int[size];
1819 entry = new int [size];
1820
1821 for (i = 0; i < size; i++ ) {
1822 entry[i] = -1;
1823 }
1824
1825 bottom = top = ( size >> 1 );
1826 }
1827
1828 wxSearchColor::~wxSearchColor( void )
1829 {
1830 if ( color ) delete color;
1831 if ( entry ) delete entry;
1832 }
1833
1834 int wxSearchColor::SearchColor( int r, int g, int b )
1835 {
1836 unsigned int value = ( ( ( r * 256 ) + g ) * 256 ) + b;
1837 int begin = bottom;
1838 int end = top;
1839 int middle;
1840
1841 while ( begin <= end ) {
1842
1843 middle = ( begin + end ) >> 1;
1844
1845 if ( value == color[middle] ) {
1846 return( entry[middle] );
1847 } else if ( value < color[middle] ) {
1848 end = middle - 1;
1849 } else {
1850 begin = middle + 1;
1851 }
1852
1853 }
1854
1855 return AddColor( value, middle );
1856 }
1857
1858 int wxSearchColor::AddColor( unsigned int value, int pos )
1859 {
1860 int i;
1861 int pixel = -1;
1862 int max = 3 * (65536);
1863 for ( i = 0; i < 256; i++ ) {
1864 int rdiff = ((value >> 8) & 0xFF00 ) - colors[i].red;
1865 int gdiff = ((value ) & 0xFF00 ) - colors[i].green;
1866 int bdiff = ((value << 8) & 0xFF00 ) - colors[i].blue;
1867 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
1868 if (sum < max) { pixel = i; max = sum; }
1869 }
1870
1871 if ( entry[pos] < 0 ) {
1872 color[pos] = value;
1873 entry[pos] = pixel;
1874 } else if ( value < color[pos] ) {
1875
1876 if ( bottom > 0 ) {
1877 for ( i = bottom; i < pos; i++ ) {
1878 color[i-1] = color[i];
1879 entry[i-1] = entry[i];
1880 }
1881 bottom--;
1882 color[pos-1] = value;
1883 entry[pos-1] = pixel;
1884 } else if ( top < size-1 ) {
1885 for ( i = top; i >= pos; i-- ) {
1886 color[i+1] = color[i];
1887 entry[i+1] = entry[i];
1888 }
1889 top++;
1890 color[pos] = value;
1891 entry[pos] = pixel;
1892 }
1893
1894 } else {
1895
1896 if ( top < size-1 ) {
1897 for ( i = top; i > pos; i-- ) {
1898 color[i+1] = color[i];
1899 entry[i+1] = entry[i];
1900 }
1901 top++;
1902 color[pos+1] = value;
1903 entry[pos+1] = pixel;
1904 } else if ( bottom > 0 ) {
1905 for ( i = bottom; i < pos; i++ ) {
1906 color[i-1] = color[i];
1907 entry[i-1] = entry[i];
1908 }
1909 bottom--;
1910 color[pos] = value;
1911 entry[pos] = pixel;
1912 }
1913
1914 }
1915
1916 return( pixel );
1917 }
1918
1919 wxBitmap wxImage::ConvertToBitmap() const
1920 {
1921 wxBitmap bitmap;
1922
1923 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
1924
1925 int width = GetWidth();
1926 int height = GetHeight();
1927
1928 bitmap.SetHeight( height );
1929 bitmap.SetWidth( width );
1930
1931 Display *dpy = (Display*) wxGetDisplay();
1932 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
1933 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
1934
1935 // Create image
1936
1937 XImage *data_image = XCreateImage( dpy, vis, bpp, ZPixmap, 0, 0, width, height, 32, 0 );
1938 data_image->data = (char*) malloc( data_image->bytes_per_line * data_image->height );
1939
1940 bitmap.Create( width, height, bpp );
1941
1942 /*
1943 // Create mask
1944
1945 GdkImage *mask_image = (GdkImage*) NULL;
1946
1947 if (HasMask())
1948 {
1949 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1950
1951 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1952
1953 wxMask *mask = new wxMask();
1954 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1955
1956 bitmap.SetMask( mask );
1957 }
1958 */
1959
1960 // Retrieve depth info
1961
1962 XVisualInfo vinfo_template;
1963 XVisualInfo *vi;
1964
1965 vinfo_template.visual = vis;
1966 vinfo_template.visualid = XVisualIDFromVisual( vis );
1967 vinfo_template.depth = bpp;
1968 int nitem = 0;
1969
1970 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
1971
1972 wxCHECK_MSG( vi, wxNullBitmap, wxT("no visual") );
1973
1974 XFree( vi );
1975
1976 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
1977 if (bpp < 8) bpp = 8;
1978
1979 // Render
1980
1981 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1982 byte_order b_o = RGB;
1983
1984 if (bpp >= 24)
1985 {
1986 if ((vi->red_mask > vi->green_mask) && (vi->green_mask > vi->blue_mask)) b_o = RGB;
1987 else if ((vi->red_mask > vi->blue_mask) && (vi->blue_mask > vi->green_mask)) b_o = RGB;
1988 else if ((vi->blue_mask > vi->red_mask) && (vi->red_mask > vi->green_mask)) b_o = BRG;
1989 else if ((vi->blue_mask > vi->green_mask) && (vi->green_mask > vi->red_mask)) b_o = BGR;
1990 else if ((vi->green_mask > vi->red_mask) && (vi->red_mask > vi->blue_mask)) b_o = GRB;
1991 else if ((vi->green_mask > vi->blue_mask) && (vi->blue_mask > vi->red_mask)) b_o = GBR;
1992 }
1993
1994 /*
1995 int r_mask = GetMaskRed();
1996 int g_mask = GetMaskGreen();
1997 int b_mask = GetMaskBlue();
1998 */
1999
2000 XColor colors[256];
2001 if (bpp == 8)
2002 {
2003 Colormap cmap = (Colormap) wxTheApp->GetMainColormap( dpy );
2004
2005 for (int i = 0; i < 256; i++) colors[i].pixel = i;
2006 XQueryColors( dpy, cmap, colors, 256 );
2007 }
2008
2009 wxSearchColor scolor( 256, colors );
2010 unsigned char* data = GetData();
2011
2012 int index = 0;
2013 for (int y = 0; y < height; y++)
2014 {
2015 for (int x = 0; x < width; x++)
2016 {
2017 int r = data[index];
2018 index++;
2019 int g = data[index];
2020 index++;
2021 int b = data[index];
2022 index++;
2023
2024 /*
2025 if (HasMask())
2026 {
2027 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
2028 gdk_image_put_pixel( mask_image, x, y, 1 );
2029 else
2030 gdk_image_put_pixel( mask_image, x, y, 0 );
2031 }
2032 */
2033
2034 switch (bpp)
2035 {
2036 case 8:
2037 {
2038 #if 0 // Old, slower code
2039 int pixel = -1;
2040 /*
2041 if (wxTheApp->m_colorCube)
2042 {
2043 pixel = wxTheApp->m_colorCube
2044 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
2045 }
2046 else
2047 {
2048 */
2049 int max = 3 * (65536);
2050 for (int i = 0; i < 256; i++)
2051 {
2052 int rdiff = (r << 8) - colors[i].red;
2053 int gdiff = (g << 8) - colors[i].green;
2054 int bdiff = (b << 8) - colors[i].blue;
2055 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
2056 if (sum < max) { pixel = i; max = sum; }
2057 }
2058 /*
2059 }
2060 */
2061 #endif
2062
2063 // And this is all to get the 'right' color...
2064 int pixel = scolor.SearchColor( r, g, b );
2065 XPutPixel( data_image, x, y, pixel );
2066 break;
2067 }
2068 case 15:
2069 {
2070 int pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
2071 XPutPixel( data_image, x, y, pixel );
2072 break;
2073 }
2074 case 16:
2075 {
2076 int pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
2077 XPutPixel( data_image, x, y, pixel );
2078 break;
2079 }
2080 case 32:
2081 case 24:
2082 {
2083 int pixel = 0;
2084 switch (b_o)
2085 {
2086 case RGB: pixel = (r << 16) | (g << 8) | b; break;
2087 case RBG: pixel = (r << 16) | (b << 8) | g; break;
2088 case BRG: pixel = (b << 16) | (r << 8) | g; break;
2089 case BGR: pixel = (b << 16) | (g << 8) | r; break;
2090 case GRB: pixel = (g << 16) | (r << 8) | b; break;
2091 case GBR: pixel = (g << 16) | (b << 8) | r; break;
2092 }
2093 XPutPixel( data_image, x, y, pixel );
2094 }
2095 default: break;
2096 }
2097 } // for
2098 } // for
2099
2100 // Blit picture
2101
2102 XGCValues gcvalues;
2103 gcvalues.foreground = BlackPixel( dpy, DefaultScreen( dpy ) );
2104 GC gc = XCreateGC( dpy, RootWindow ( dpy, DefaultScreen(dpy) ), GCForeground, &gcvalues );
2105 XPutImage( dpy, (Drawable)bitmap.GetPixmap(), gc, data_image, 0, 0, 0, 0, width, height );
2106
2107 XDestroyImage( data_image );
2108 XFreeGC( dpy, gc );
2109
2110 /*
2111 // Blit mask
2112
2113 if (HasMask())
2114 {
2115 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
2116
2117 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
2118
2119 gdk_image_destroy( mask_image );
2120 gdk_gc_unref( mask_gc );
2121 }
2122 */
2123
2124 return bitmap;
2125 }
2126
2127 wxImage::wxImage( const wxBitmap &bitmap )
2128 {
2129 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
2130
2131 Display *dpy = (Display*) wxGetDisplay();
2132 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
2133 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
2134
2135 XImage *ximage = XGetImage( dpy,
2136 (Drawable)bitmap.GetPixmap(),
2137 0, 0,
2138 bitmap.GetWidth(), bitmap.GetHeight(),
2139 AllPlanes, ZPixmap );
2140
2141 wxCHECK_RET( ximage, wxT("couldn't create image") );
2142
2143 Create( bitmap.GetWidth(), bitmap.GetHeight() );
2144 char unsigned *data = GetData();
2145
2146 if (!data)
2147 {
2148 XDestroyImage( ximage );
2149 wxFAIL_MSG( wxT("couldn't create image") );
2150 return;
2151 }
2152
2153 /*
2154 GdkImage *gdk_image_mask = (GdkImage*) NULL;
2155 if (bitmap.GetMask())
2156 {
2157 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
2158 0, 0,
2159 bitmap.GetWidth(), bitmap.GetHeight() );
2160
2161 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
2162 }
2163 */
2164
2165 // Retrieve depth info
2166
2167 XVisualInfo vinfo_template;
2168 XVisualInfo *vi;
2169
2170 vinfo_template.visual = vis;
2171 vinfo_template.visualid = XVisualIDFromVisual( vis );
2172 vinfo_template.depth = bpp;
2173 int nitem = 0;
2174
2175 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
2176
2177 wxCHECK_RET( vi, wxT("no visual") );
2178
2179 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
2180
2181 XFree( vi );
2182
2183 XColor colors[256];
2184 if (bpp == 8)
2185 {
2186 Colormap cmap = (Colormap)wxTheApp->GetMainColormap( dpy );
2187
2188 for (int i = 0; i < 256; i++) colors[i].pixel = i;
2189 XQueryColors( dpy, cmap, colors, 256 );
2190 }
2191
2192 long pos = 0;
2193 for (int j = 0; j < bitmap.GetHeight(); j++)
2194 {
2195 for (int i = 0; i < bitmap.GetWidth(); i++)
2196 {
2197 int pixel = XGetPixel( ximage, i, j );
2198 if (bpp <= 8)
2199 {
2200 data[pos] = colors[pixel].red >> 8;
2201 data[pos+1] = colors[pixel].green >> 8;
2202 data[pos+2] = colors[pixel].blue >> 8;
2203 } else if (bpp == 15)
2204 {
2205 data[pos] = (pixel >> 7) & 0xf8;
2206 data[pos+1] = (pixel >> 2) & 0xf8;
2207 data[pos+2] = (pixel << 3) & 0xf8;
2208 } else if (bpp == 16)
2209 {
2210 data[pos] = (pixel >> 8) & 0xf8;
2211 data[pos+1] = (pixel >> 3) & 0xfc;
2212 data[pos+2] = (pixel << 3) & 0xf8;
2213 } else
2214 {
2215 data[pos] = (pixel >> 16) & 0xff;
2216 data[pos+1] = (pixel >> 8) & 0xff;
2217 data[pos+2] = pixel & 0xff;
2218 }
2219
2220 /*
2221 if (gdk_image_mask)
2222 {
2223 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
2224 if (mask_pixel == 0)
2225 {
2226 data[pos] = 16;
2227 data[pos+1] = 16;
2228 data[pos+2] = 16;
2229 }
2230 }
2231 */
2232
2233 pos += 3;
2234 }
2235 }
2236
2237 XDestroyImage( ximage );
2238 /*
2239 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
2240 */
2241 }
2242 #endif
2243
2244 #ifdef __WXPM__
2245 // OS/2 Presentation manager conversion routings
2246
2247 wxBitmap wxImage::ConvertToBitmap() const
2248 {
2249 if ( !Ok() )
2250 return wxNullBitmap;
2251 wxBitmap bitmap; // remove
2252 // TODO:
2253 /*
2254 int sizeLimit = 1024*768*3;
2255
2256 // width and height of the device-dependent bitmap
2257 int width = GetWidth();
2258 int bmpHeight = GetHeight();
2259
2260 // calc the number of bytes per scanline and padding
2261 int bytePerLine = width*3;
2262 int sizeDWORD = sizeof( DWORD );
2263 int lineBoundary = bytePerLine % sizeDWORD;
2264 int padding = 0;
2265 if( lineBoundary > 0 )
2266 {
2267 padding = sizeDWORD - lineBoundary;
2268 bytePerLine += padding;
2269 }
2270 // calc the number of DIBs and heights of DIBs
2271 int numDIB = 1;
2272 int hRemain = 0;
2273 int height = sizeLimit/bytePerLine;
2274 if( height >= bmpHeight )
2275 height = bmpHeight;
2276 else
2277 {
2278 numDIB = bmpHeight / height;
2279 hRemain = bmpHeight % height;
2280 if( hRemain >0 ) numDIB++;
2281 }
2282
2283 // set bitmap parameters
2284 wxBitmap bitmap;
2285 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
2286 bitmap.SetWidth( width );
2287 bitmap.SetHeight( bmpHeight );
2288 bitmap.SetDepth( wxDisplayDepth() );
2289
2290 // create a DIB header
2291 int headersize = sizeof(BITMAPINFOHEADER);
2292 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2293 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
2294 // Fill in the DIB header
2295 lpDIBh->bmiHeader.biSize = headersize;
2296 lpDIBh->bmiHeader.biWidth = (DWORD)width;
2297 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2298 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2299 // the general formula for biSizeImage:
2300 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
2301 lpDIBh->bmiHeader.biPlanes = 1;
2302 lpDIBh->bmiHeader.biBitCount = 24;
2303 lpDIBh->bmiHeader.biCompression = BI_RGB;
2304 lpDIBh->bmiHeader.biClrUsed = 0;
2305 // These seem not really needed for our purpose here.
2306 lpDIBh->bmiHeader.biClrImportant = 0;
2307 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2308 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2309 // memory for DIB data
2310 unsigned char *lpBits;
2311 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
2312 if( !lpBits )
2313 {
2314 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
2315 free( lpDIBh );
2316 return bitmap;
2317 }
2318
2319 // create and set the device-dependent bitmap
2320 HDC hdc = ::GetDC(NULL);
2321 HDC memdc = ::CreateCompatibleDC( hdc );
2322 HBITMAP hbitmap;
2323 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
2324 ::SelectObject( memdc, hbitmap);
2325
2326 // copy image data into DIB data and then into DDB (in a loop)
2327 unsigned char *data = GetData();
2328 int i, j, n;
2329 int origin = 0;
2330 unsigned char *ptdata = data;
2331 unsigned char *ptbits;
2332
2333 for( n=0; n<numDIB; n++ )
2334 {
2335 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
2336 {
2337 // redefine height and size of the (possibly) last smaller DIB
2338 // memory is not reallocated
2339 height = hRemain;
2340 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2341 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2342 }
2343 ptbits = lpBits;
2344
2345 for( j=0; j<height; j++ )
2346 {
2347 for( i=0; i<width; i++ )
2348 {
2349 *(ptbits++) = *(ptdata+2);
2350 *(ptbits++) = *(ptdata+1);
2351 *(ptbits++) = *(ptdata );
2352 ptdata += 3;
2353 }
2354 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
2355 }
2356 ::StretchDIBits( memdc, 0, origin, width, height,\
2357 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2358 origin += height;
2359 // if numDIB = 1, lines below can also be used
2360 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
2361 // The above line is equivalent to the following two lines.
2362 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2363 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
2364 // or the following lines
2365 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2366 // HDC memdc = ::CreateCompatibleDC( hdc );
2367 // ::SelectObject( memdc, hbitmap);
2368 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
2369 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
2370 // ::SelectObject( memdc, 0 );
2371 // ::DeleteDC( memdc );
2372 }
2373 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
2374
2375 // similarly, created an mono-bitmap for the possible mask
2376 if( HasMask() )
2377 {
2378 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
2379 ::SelectObject( memdc, hbitmap);
2380 if( numDIB == 1 ) height = bmpHeight;
2381 else height = sizeLimit/bytePerLine;
2382 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2383 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2384 origin = 0;
2385 unsigned char r = GetMaskRed();
2386 unsigned char g = GetMaskGreen();
2387 unsigned char b = GetMaskBlue();
2388 unsigned char zero = 0, one = 255;
2389 ptdata = data;
2390 for( n=0; n<numDIB; n++ )
2391 {
2392 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
2393 {
2394 // redefine height and size of the (possibly) last smaller DIB
2395 // memory is not reallocated
2396 height = hRemain;
2397 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2398 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2399 }
2400 ptbits = lpBits;
2401 for( int j=0; j<height; j++ )
2402 {
2403 for(i=0; i<width; i++ )
2404 {
2405 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
2406 {
2407 *(ptbits++) = one;
2408 *(ptbits++) = one;
2409 *(ptbits++) = one;
2410 }
2411 else
2412 {
2413 *(ptbits++) = zero;
2414 *(ptbits++) = zero;
2415 *(ptbits++) = zero;
2416 }
2417 }
2418 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
2419 }
2420 ::StretchDIBits( memdc, 0, origin, width, height,\
2421 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2422 origin += height;
2423 }
2424 // create a wxMask object
2425 wxMask *mask = new wxMask();
2426 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
2427 bitmap.SetMask( mask );
2428 }
2429
2430 // free allocated resources
2431 ::SelectObject( memdc, 0 );
2432 ::DeleteDC( memdc );
2433 ::ReleaseDC(NULL, hdc);
2434 free(lpDIBh);
2435 free(lpBits);
2436
2437 // check the wxBitmap object
2438 if( bitmap.GetHBITMAP() )
2439 bitmap.SetOk( TRUE );
2440 else
2441 bitmap.SetOk( FALSE );
2442 */
2443 return bitmap;
2444 }
2445
2446 wxImage::wxImage( const wxBitmap &bitmap )
2447 {
2448 // check the bitmap
2449 if( !bitmap.Ok() )
2450 {
2451 wxFAIL_MSG( wxT("invalid bitmap") );
2452 return;
2453 }
2454
2455 // create an wxImage object
2456 int width = bitmap.GetWidth();
2457 int height = bitmap.GetHeight();
2458 Create( width, height );
2459 unsigned char *data = GetData();
2460 if( !data )
2461 {
2462 wxFAIL_MSG( wxT("could not allocate data for image") );
2463 return;
2464 }
2465
2466 // calc the number of bytes per scanline and padding in the DIB
2467 int bytePerLine = width*3;
2468 int sizeDWORD = sizeof( DWORD );
2469 int lineBoundary = bytePerLine % sizeDWORD;
2470 int padding = 0;
2471 if( lineBoundary > 0 )
2472 {
2473 padding = sizeDWORD - lineBoundary;
2474 bytePerLine += padding;
2475 }
2476 // TODO:
2477 /*
2478 // create a DIB header
2479 int headersize = sizeof(BITMAPINFOHEADER);
2480 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2481 if( !lpDIBh )
2482 {
2483 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
2484 free( data );
2485 return;
2486 }
2487 // Fill in the DIB header
2488 lpDIBh->bmiHeader.biSize = headersize;
2489 lpDIBh->bmiHeader.biWidth = width;
2490 lpDIBh->bmiHeader.biHeight = -height;
2491 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
2492 lpDIBh->bmiHeader.biPlanes = 1;
2493 lpDIBh->bmiHeader.biBitCount = 24;
2494 lpDIBh->bmiHeader.biCompression = BI_RGB;
2495 lpDIBh->bmiHeader.biClrUsed = 0;
2496 // These seem not really needed for our purpose here.
2497 lpDIBh->bmiHeader.biClrImportant = 0;
2498 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2499 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2500 // memory for DIB data
2501 unsigned char *lpBits;
2502 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
2503 if( !lpBits )
2504 {
2505 wxFAIL_MSG( wxT("could not allocate data for DIB") );
2506 free( data );
2507 free( lpDIBh );
2508 return;
2509 }
2510
2511 // copy data from the device-dependent bitmap to the DIB
2512 HDC hdc = ::GetDC(NULL);
2513 HBITMAP hbitmap;
2514 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
2515 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2516
2517 // copy DIB data into the wxImage object
2518 int i, j;
2519 unsigned char *ptdata = data;
2520 unsigned char *ptbits = lpBits;
2521 for( i=0; i<height; i++ )
2522 {
2523 for( j=0; j<width; j++ )
2524 {
2525 *(ptdata++) = *(ptbits+2);
2526 *(ptdata++) = *(ptbits+1);
2527 *(ptdata++) = *(ptbits );
2528 ptbits += 3;
2529 }
2530 ptbits += padding;
2531 }
2532
2533 // similarly, set data according to the possible mask bitmap
2534 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
2535 {
2536 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
2537 // memory DC created, color set, data copied, and memory DC deleted
2538 HDC memdc = ::CreateCompatibleDC( hdc );
2539 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
2540 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
2541 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2542 ::DeleteDC( memdc );
2543 // background color set to RGB(16,16,16) in consistent with wxGTK
2544 unsigned char r=16, g=16, b=16;
2545 ptdata = data;
2546 ptbits = lpBits;
2547 for( i=0; i<height; i++ )
2548 {
2549 for( j=0; j<width; j++ )
2550 {
2551 if( *ptbits != 0 )
2552 ptdata += 3;
2553 else
2554 {
2555 *(ptdata++) = r;
2556 *(ptdata++) = g;
2557 *(ptdata++) = b;
2558 }
2559 ptbits += 3;
2560 }
2561 ptbits += padding;
2562 }
2563 SetMaskColour( r, g, b );
2564 SetMask( TRUE );
2565 }
2566 else
2567 {
2568 SetMask( FALSE );
2569 }
2570 // free allocated resources
2571 ::ReleaseDC(NULL, hdc);
2572 free(lpDIBh);
2573 free(lpBits);
2574 */
2575 }
2576
2577 #endif
2578
2579 // A module to allow wxImage initialization/cleanup
2580 // without calling these functions from app.cpp or from
2581 // the user's application.
2582
2583 class wxImageModule: public wxModule
2584 {
2585 DECLARE_DYNAMIC_CLASS(wxImageModule)
2586 public:
2587 wxImageModule() {}
2588 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE; };
2589 void OnExit() { wxImage::CleanUpHandlers(); };
2590 };
2591
2592 IMPLEMENT_DYNAMIC_CLASS(wxImageModule, wxModule)
2593
2594
2595 //-----------------------------------------------------------------------------
2596
2597 // GRG, Dic/99
2598 // Counts and returns the number of different colours. Optionally stops
2599 // when it exceeds 'stopafter' different colours. This is useful, for
2600 // example, to see if the image can be saved as 8-bit (256 colour or
2601 // less, in this case it would be invoked as CountColours(256)). Default
2602 // value for stopafter is -1 (don't care).
2603 //
2604 unsigned long wxImage::CountColours( unsigned long stopafter )
2605 {
2606 wxHashTable h;
2607 wxNode *node;
2608 wxHNode *hnode;
2609 unsigned char r, g, b, *p;
2610 unsigned long size, nentries, key;
2611
2612 p = GetData();
2613 size = GetWidth() * GetHeight();
2614 nentries = 0;
2615
2616 for (unsigned long j = 0; (j < size) && (nentries <= stopafter) ; j++)
2617 {
2618 r = *(p++);
2619 g = *(p++);
2620 b = *(p++);
2621 key = (r << 16) | (g << 8) | b;
2622
2623 hnode = (wxHNode *) h.Get(key);
2624
2625 if (!hnode)
2626 {
2627 h.Put(key, (wxObject *)(new wxHNode));
2628 nentries++;
2629 }
2630 }
2631
2632 // delete all HNodes
2633 h.BeginFind();
2634 while ((node = h.Next()) != NULL)
2635 delete (wxHNode *)node->GetData();
2636
2637 return nentries;
2638 }
2639
2640
2641 // GRG, Dic/99
2642 // Computes the histogram of the image and fills a hash table, indexed
2643 // with integer keys built as 0xRRGGBB, containing wxHNode objects. Each
2644 // wxHNode contains an 'index' (useful to build a palette with the image
2645 // colours) and a 'value', which is the number of pixels in the image with
2646 // that colour.
2647 //
2648 unsigned long wxImage::ComputeHistogram( wxHashTable &h )
2649 {
2650 unsigned char r, g, b, *p;
2651 unsigned long size, nentries, key;
2652 wxHNode *hnode;
2653
2654 p = GetData();
2655 size = GetWidth() * GetHeight();
2656 nentries = 0;
2657
2658 for (unsigned long j = 0; j < size; j++)
2659 {
2660 r = *(p++);
2661 g = *(p++);
2662 b = *(p++);
2663 key = (r << 16) | (g << 8) | b;
2664
2665 hnode = (wxHNode *) h.Get(key);
2666
2667 if (hnode)
2668 hnode->value++;
2669 else
2670 {
2671 hnode = new wxHNode();
2672 hnode->index = nentries++;
2673 hnode->value = 1;
2674
2675 h.Put(key, (wxObject *)hnode);
2676 }
2677 }
2678
2679 return nentries;
2680 }
2681
2682