]> git.saurik.com Git - wxWidgets.git/blob - src/common/image.cpp
Copied isql.h and isqlext.h to /include/wx/unix and make
[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 ::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
922 // free allocated resources
923 ::SelectObject( memdc, 0 );
924 ::DeleteDC( memdc );
925 ::ReleaseDC(NULL, hdc);
926 free(lpDIBh);
927 free(lpBits);
928
929 #if WXWIN_COMPATIBILITY_2
930 // check the wxBitmap object
931 bitmap.GetBitmapData()->SetOk();
932 #endif // WXWIN_COMPATIBILITY_2
933
934 return bitmap;
935 }
936
937 wxImage::wxImage( const wxBitmap &bitmap )
938 {
939 // check the bitmap
940 if( !bitmap.Ok() )
941 {
942 wxFAIL_MSG( wxT("invalid bitmap") );
943 return;
944 }
945
946 // create an wxImage object
947 int width = bitmap.GetWidth();
948 int height = bitmap.GetHeight();
949 Create( width, height );
950 unsigned char *data = GetData();
951 if( !data )
952 {
953 wxFAIL_MSG( wxT("could not allocate data for image") );
954 return;
955 }
956
957 // calc the number of bytes per scanline and padding in the DIB
958 int bytePerLine = width*3;
959 int sizeDWORD = sizeof( DWORD );
960 int lineBoundary = bytePerLine % sizeDWORD;
961 int padding = 0;
962 if( lineBoundary > 0 )
963 {
964 padding = sizeDWORD - lineBoundary;
965 bytePerLine += padding;
966 }
967
968 // create a DIB header
969 int headersize = sizeof(BITMAPINFOHEADER);
970 BITMAPINFO *lpDIBh = (BITMAPINFO *) malloc( headersize );
971 if( !lpDIBh )
972 {
973 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
974 free( data );
975 return;
976 }
977 // Fill in the DIB header
978 lpDIBh->bmiHeader.biSize = headersize;
979 lpDIBh->bmiHeader.biWidth = width;
980 lpDIBh->bmiHeader.biHeight = -height;
981 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
982 lpDIBh->bmiHeader.biPlanes = 1;
983 lpDIBh->bmiHeader.biBitCount = 24;
984 lpDIBh->bmiHeader.biCompression = BI_RGB;
985 lpDIBh->bmiHeader.biClrUsed = 0;
986 // These seem not really needed for our purpose here.
987 lpDIBh->bmiHeader.biClrImportant = 0;
988 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
989 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
990 // memory for DIB data
991 unsigned char *lpBits;
992 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
993 if( !lpBits )
994 {
995 wxFAIL_MSG( wxT("could not allocate data for DIB") );
996 free( data );
997 free( lpDIBh );
998 return;
999 }
1000
1001 // copy data from the device-dependent bitmap to the DIB
1002 HDC hdc = ::GetDC(NULL);
1003 HBITMAP hbitmap;
1004 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1005 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1006
1007 // copy DIB data into the wxImage object
1008 int i, j;
1009 unsigned char *ptdata = data;
1010 unsigned char *ptbits = lpBits;
1011 for( i=0; i<height; i++ )
1012 {
1013 for( j=0; j<width; j++ )
1014 {
1015 *(ptdata++) = *(ptbits+2);
1016 *(ptdata++) = *(ptbits+1);
1017 *(ptdata++) = *(ptbits );
1018 ptbits += 3;
1019 }
1020 ptbits += padding;
1021 }
1022
1023 // similarly, set data according to the possible mask bitmap
1024 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1025 {
1026 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1027 // memory DC created, color set, data copied, and memory DC deleted
1028 HDC memdc = ::CreateCompatibleDC( hdc );
1029 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1030 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1031 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1032 ::DeleteDC( memdc );
1033 // background color set to RGB(16,16,16) in consistent with wxGTK
1034 unsigned char r=16, g=16, b=16;
1035 ptdata = data;
1036 ptbits = lpBits;
1037 for( i=0; i<height; i++ )
1038 {
1039 for( j=0; j<width; j++ )
1040 {
1041 if( *ptbits != 0 )
1042 ptdata += 3;
1043 else
1044 {
1045 *(ptdata++) = r;
1046 *(ptdata++) = g;
1047 *(ptdata++) = b;
1048 }
1049 ptbits += 3;
1050 }
1051 ptbits += padding;
1052 }
1053 SetMaskColour( r, g, b );
1054 SetMask( TRUE );
1055 }
1056 else
1057 {
1058 SetMask( FALSE );
1059 }
1060 // free allocated resources
1061 ::ReleaseDC(NULL, hdc);
1062 free(lpDIBh);
1063 free(lpBits);
1064 }
1065
1066 #endif
1067
1068 #ifdef __WXMAC__
1069
1070 #include <PictUtils.h>
1071
1072 extern CTabHandle wxMacCreateColorTable( int numColors ) ;
1073 extern void wxMacDestroyColorTable( CTabHandle colors ) ;
1074 extern void wxMacSetColorTableEntry( CTabHandle newColors , int index , int red , int green , int blue ) ;
1075 extern GWorldPtr wxMacCreateGWorld( int height , int width , int depth ) ;
1076 extern void wxMacDestroyGWorld( GWorldPtr gw ) ;
1077
1078 wxBitmap wxImage::ConvertToBitmap() const
1079 {
1080 // width and height of the device-dependent bitmap
1081 int width = GetWidth();
1082 int height = GetHeight();
1083
1084 // Create picture
1085
1086 wxBitmap bitmap( width , height , wxDisplayDepth() ) ;
1087
1088 // Create mask
1089
1090 if (HasMask())
1091 {
1092 /*
1093 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1094
1095 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1096
1097 wxMask *mask = new wxMask();
1098 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1099
1100 bitmap.SetMask( mask );
1101 */
1102 }
1103
1104 // Render
1105
1106 int r_mask = GetMaskRed();
1107 int g_mask = GetMaskGreen();
1108 int b_mask = GetMaskBlue();
1109
1110 CGrafPtr origPort ;
1111 GDHandle origDevice ;
1112
1113 GetGWorld( &origPort , &origDevice ) ;
1114 SetGWorld( bitmap.GetHBITMAP() , NULL ) ;
1115
1116 register unsigned char* data = GetData();
1117
1118 int index = 0;
1119 for (int y = 0; y < height; y++)
1120 {
1121 for (int x = 0; x < width; x++)
1122 {
1123 unsigned char r = data[index++];
1124 unsigned char g = data[index++];
1125 unsigned char b = data[index++];
1126 RGBColor color ;
1127 color.red = ( r << 8 ) + r ;
1128 color.green = ( g << 8 ) + g ;
1129 color.blue = ( b << 8 ) + b ;
1130 SetCPixel( x , y , &color ) ;
1131 }
1132 } // for height
1133
1134 SetGWorld( origPort , origDevice ) ;
1135
1136 if ( HasMask() )
1137 {
1138 wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
1139 wxMask *mask = new wxMask( bitmap, colour );
1140 bitmap.SetMask( mask );
1141 }
1142 return bitmap;
1143
1144 }
1145
1146 wxImage::wxImage( const wxBitmap &bitmap )
1147 {
1148 // check the bitmap
1149 if( !bitmap.Ok() )
1150 {
1151 wxFAIL_MSG( "invalid bitmap" );
1152 return;
1153 }
1154
1155 // create an wxImage object
1156 int width = bitmap.GetWidth();
1157 int height = bitmap.GetHeight();
1158 Create( width, height );
1159 /*
1160 unsigned char *data = GetData();
1161 if( !data )
1162 {
1163 wxFAIL_MSG( "could not allocate data for image" );
1164 return;
1165 }
1166
1167 // calc the number of bytes per scanline and padding in the DIB
1168 int bytePerLine = width*3;
1169 int sizeDWORD = sizeof( DWORD );
1170 div_t lineBoundary = div( bytePerLine, sizeDWORD );
1171 int padding = 0;
1172 if( lineBoundary.rem > 0 )
1173 {
1174 padding = sizeDWORD - lineBoundary.rem;
1175 bytePerLine += padding;
1176 }
1177
1178 // create a DIB header
1179 int headersize = sizeof(BITMAPINFOHEADER);
1180 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
1181 if( !lpDIBh )
1182 {
1183 wxFAIL_MSG( "could not allocate data for DIB header" );
1184 free( data );
1185 return;
1186 }
1187 // Fill in the DIB header
1188 lpDIBh->bmiHeader.biSize = headersize;
1189 lpDIBh->bmiHeader.biWidth = width;
1190 lpDIBh->bmiHeader.biHeight = -height;
1191 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
1192 lpDIBh->bmiHeader.biPlanes = 1;
1193 lpDIBh->bmiHeader.biBitCount = 24;
1194 lpDIBh->bmiHeader.biCompression = BI_RGB;
1195 lpDIBh->bmiHeader.biClrUsed = 0;
1196 // These seem not really needed for our purpose here.
1197 lpDIBh->bmiHeader.biClrImportant = 0;
1198 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
1199 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
1200 // memory for DIB data
1201 unsigned char *lpBits;
1202 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
1203 if( !lpBits )
1204 {
1205 wxFAIL_MSG( "could not allocate data for DIB" );
1206 free( data );
1207 free( lpDIBh );
1208 return;
1209 }
1210
1211 // copy data from the device-dependent bitmap to the DIB
1212 HDC hdc = ::GetDC(NULL);
1213 HBITMAP hbitmap;
1214 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
1215 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1216
1217 // copy DIB data into the wxImage object
1218 int i, j;
1219 unsigned char *ptdata = data;
1220 unsigned char *ptbits = lpBits;
1221 for( i=0; i<height; i++ )
1222 {
1223 for( j=0; j<width; j++ )
1224 {
1225 *(ptdata++) = *(ptbits+2);
1226 *(ptdata++) = *(ptbits+1);
1227 *(ptdata++) = *(ptbits );
1228 ptbits += 3;
1229 }
1230 ptbits += padding;
1231 }
1232
1233 // similarly, set data according to the possible mask bitmap
1234 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
1235 {
1236 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
1237 // memory DC created, color set, data copied, and memory DC deleted
1238 HDC memdc = ::CreateCompatibleDC( hdc );
1239 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
1240 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
1241 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
1242 ::DeleteDC( memdc );
1243 // background color set to RGB(16,16,16) in consistent with wxGTK
1244 unsigned char r=16, g=16, b=16;
1245 ptdata = data;
1246 ptbits = lpBits;
1247 for( i=0; i<height; i++ )
1248 {
1249 for( j=0; j<width; j++ )
1250 {
1251 if( *ptbits != 0 )
1252 ptdata += 3;
1253 else
1254 {
1255 *(ptdata++) = r;
1256 *(ptdata++) = g;
1257 *(ptdata++) = b;
1258 }
1259 ptbits += 3;
1260 }
1261 ptbits += padding;
1262 }
1263 SetMaskColour( r, g, b );
1264 SetMask( TRUE );
1265 }
1266 else
1267 {
1268 SetMask( FALSE );
1269 }
1270 // free allocated resources
1271 ::ReleaseDC(NULL, hdc);
1272 free(lpDIBh);
1273 free(lpBits);
1274 */
1275 }
1276
1277 #endif
1278
1279 //-----------------------------------------------------------------------------
1280 // GTK conversion routines
1281 //-----------------------------------------------------------------------------
1282
1283 #ifdef __WXGTK__
1284
1285 #include <gtk/gtk.h>
1286 #include <gdk/gdk.h>
1287 #include <gdk/gdkx.h>
1288
1289 #if (GTK_MINOR_VERSION > 0)
1290 #include <gdk/gdkrgb.h>
1291 #endif
1292
1293 extern GtkWidget *wxRootWindow;
1294
1295 wxBitmap wxImage::ConvertToMonoBitmap( unsigned char red, unsigned char green, unsigned char blue )
1296 {
1297 wxBitmap bitmap;
1298
1299 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
1300
1301 int width = GetWidth();
1302 int height = GetHeight();
1303
1304 bitmap.SetHeight( height );
1305 bitmap.SetWidth( width );
1306
1307 bitmap.SetBitmap( gdk_pixmap_new( wxRootWindow->window, width, height, 1 ) );
1308
1309 bitmap.SetDepth( 1 );
1310
1311 // Create picture image
1312
1313 unsigned char *data_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1314
1315 GdkImage *data_image =
1316 gdk_image_new_bitmap( gdk_visual_get_system(), data_data, width, height );
1317
1318 // Create mask image
1319
1320 GdkImage *mask_image = (GdkImage*) NULL;
1321
1322 if (HasMask())
1323 {
1324 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1325
1326 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1327
1328 wxMask *mask = new wxMask();
1329 mask->m_bitmap = gdk_pixmap_new( wxRootWindow->window, width, height, 1 );
1330
1331 bitmap.SetMask( mask );
1332 }
1333
1334 int r_mask = GetMaskRed();
1335 int g_mask = GetMaskGreen();
1336 int b_mask = GetMaskBlue();
1337
1338 unsigned char* data = GetData();
1339
1340 int index = 0;
1341 for (int y = 0; y < height; y++)
1342 {
1343 for (int x = 0; x < width; x++)
1344 {
1345 int r = data[index];
1346 index++;
1347 int g = data[index];
1348 index++;
1349 int b = data[index];
1350 index++;
1351
1352 if (HasMask())
1353 {
1354 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1355 gdk_image_put_pixel( mask_image, x, y, 1 );
1356 else
1357 gdk_image_put_pixel( mask_image, x, y, 0 );
1358 }
1359
1360 if ((r == red) && (b == blue) && (g == green))
1361 gdk_image_put_pixel( data_image, x, y, 1 );
1362 else
1363 gdk_image_put_pixel( data_image, x, y, 0 );
1364
1365 } // for
1366 } // for
1367
1368 // Blit picture
1369
1370 GdkGC *data_gc = gdk_gc_new( bitmap.GetBitmap() );
1371
1372 gdk_draw_image( bitmap.GetBitmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
1373
1374 gdk_image_destroy( data_image );
1375 gdk_gc_unref( data_gc );
1376
1377 // Blit mask
1378
1379 if (HasMask())
1380 {
1381 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
1382
1383 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
1384
1385 gdk_image_destroy( mask_image );
1386 gdk_gc_unref( mask_gc );
1387 }
1388
1389 return bitmap;
1390 }
1391
1392
1393 wxBitmap wxImage::ConvertToBitmap() const
1394 {
1395 wxBitmap bitmap;
1396
1397 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
1398
1399 int width = GetWidth();
1400 int height = GetHeight();
1401
1402 bitmap.SetHeight( height );
1403 bitmap.SetWidth( width );
1404
1405 bitmap.SetPixmap( gdk_pixmap_new( wxRootWindow->window, width, height, -1 ) );
1406
1407 // Retrieve depth
1408
1409 GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
1410 if (visual == NULL) visual = gdk_visual_get_system();
1411 int bpp = visual->depth;
1412
1413 bitmap.SetDepth( bpp );
1414
1415 if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
1416 if (bpp < 8) bpp = 8;
1417
1418 #if (GTK_MINOR_VERSION > 0)
1419
1420 if (!HasMask() && (bpp > 8))
1421 {
1422 static bool s_hasInitialized = FALSE;
1423
1424 if (!s_hasInitialized)
1425 {
1426 gdk_rgb_init();
1427 s_hasInitialized = TRUE;
1428 }
1429
1430 GdkGC *gc = gdk_gc_new( bitmap.GetPixmap() );
1431
1432 gdk_draw_rgb_image( bitmap.GetPixmap(),
1433 gc,
1434 0, 0,
1435 width, height,
1436 GDK_RGB_DITHER_NONE,
1437 GetData(),
1438 width*3 );
1439
1440 gdk_gc_unref( gc );
1441
1442 return bitmap;
1443 }
1444
1445 #endif
1446
1447 // Create picture image
1448
1449 GdkImage *data_image =
1450 gdk_image_new( GDK_IMAGE_FASTEST, gdk_visual_get_system(), width, height );
1451
1452 // Create mask image
1453
1454 GdkImage *mask_image = (GdkImage*) NULL;
1455
1456 if (HasMask())
1457 {
1458 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1459
1460 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1461
1462 wxMask *mask = new wxMask();
1463 mask->m_bitmap = gdk_pixmap_new( wxRootWindow->window, width, height, 1 );
1464
1465 bitmap.SetMask( mask );
1466 }
1467
1468 // Render
1469
1470 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1471 byte_order b_o = RGB;
1472
1473 if (bpp >= 24)
1474 {
1475 GdkVisual *visual = gdk_visual_get_system();
1476 if ((visual->red_mask > visual->green_mask) && (visual->green_mask > visual->blue_mask)) b_o = RGB;
1477 else if ((visual->red_mask > visual->blue_mask) && (visual->blue_mask > visual->green_mask)) b_o = RGB;
1478 else if ((visual->blue_mask > visual->red_mask) && (visual->red_mask > visual->green_mask)) b_o = BRG;
1479 else if ((visual->blue_mask > visual->green_mask) && (visual->green_mask > visual->red_mask)) b_o = BGR;
1480 else if ((visual->green_mask > visual->red_mask) && (visual->red_mask > visual->blue_mask)) b_o = GRB;
1481 else if ((visual->green_mask > visual->blue_mask) && (visual->blue_mask > visual->red_mask)) b_o = GBR;
1482 }
1483
1484 int r_mask = GetMaskRed();
1485 int g_mask = GetMaskGreen();
1486 int b_mask = GetMaskBlue();
1487
1488 unsigned char* data = GetData();
1489
1490 int index = 0;
1491 for (int y = 0; y < height; y++)
1492 {
1493 for (int x = 0; x < width; x++)
1494 {
1495 int r = data[index];
1496 index++;
1497 int g = data[index];
1498 index++;
1499 int b = data[index];
1500 index++;
1501
1502 if (HasMask())
1503 {
1504 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1505 gdk_image_put_pixel( mask_image, x, y, 1 );
1506 else
1507 gdk_image_put_pixel( mask_image, x, y, 0 );
1508 }
1509
1510 switch (bpp)
1511 {
1512 case 8:
1513 {
1514 int pixel = -1;
1515 if (wxTheApp->m_colorCube)
1516 {
1517 pixel = wxTheApp->m_colorCube[ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
1518 }
1519 else
1520 {
1521 GdkColormap *cmap = gtk_widget_get_default_colormap();
1522 GdkColor *colors = cmap->colors;
1523 int max = 3 * (65536);
1524
1525 for (int i = 0; i < cmap->size; i++)
1526 {
1527 int rdiff = (r << 8) - colors[i].red;
1528 int gdiff = (g << 8) - colors[i].green;
1529 int bdiff = (b << 8) - colors[i].blue;
1530 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
1531 if (sum < max) { pixel = i; max = sum; }
1532 }
1533 }
1534
1535 gdk_image_put_pixel( data_image, x, y, pixel );
1536
1537 break;
1538 }
1539 case 15:
1540 {
1541 guint32 pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
1542 gdk_image_put_pixel( data_image, x, y, pixel );
1543 break;
1544 }
1545 case 16:
1546 {
1547 guint32 pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
1548 gdk_image_put_pixel( data_image, x, y, pixel );
1549 break;
1550 }
1551 case 32:
1552 case 24:
1553 {
1554 guint32 pixel = 0;
1555 switch (b_o)
1556 {
1557 case RGB: pixel = (r << 16) | (g << 8) | b; break;
1558 case RBG: pixel = (r << 16) | (b << 8) | g; break;
1559 case BRG: pixel = (b << 16) | (r << 8) | g; break;
1560 case BGR: pixel = (b << 16) | (g << 8) | r; break;
1561 case GRB: pixel = (g << 16) | (r << 8) | b; break;
1562 case GBR: pixel = (g << 16) | (b << 8) | r; break;
1563 }
1564 gdk_image_put_pixel( data_image, x, y, pixel );
1565 }
1566 default: break;
1567 }
1568 } // for
1569 } // for
1570
1571 // Blit picture
1572
1573 GdkGC *data_gc = gdk_gc_new( bitmap.GetPixmap() );
1574
1575 gdk_draw_image( bitmap.GetPixmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
1576
1577 gdk_image_destroy( data_image );
1578 gdk_gc_unref( data_gc );
1579
1580 // Blit mask
1581
1582 if (HasMask())
1583 {
1584 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
1585
1586 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
1587
1588 gdk_image_destroy( mask_image );
1589 gdk_gc_unref( mask_gc );
1590 }
1591
1592 return bitmap;
1593 }
1594
1595 wxImage::wxImage( const wxBitmap &bitmap )
1596 {
1597 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
1598
1599 GdkImage *gdk_image = (GdkImage*) NULL;
1600 if (bitmap.GetPixmap())
1601 {
1602 gdk_image = gdk_image_get( bitmap.GetPixmap(),
1603 0, 0,
1604 bitmap.GetWidth(), bitmap.GetHeight() );
1605 } else
1606 if (bitmap.GetBitmap())
1607 {
1608 gdk_image = gdk_image_get( bitmap.GetBitmap(),
1609 0, 0,
1610 bitmap.GetWidth(), bitmap.GetHeight() );
1611 } else
1612 {
1613 wxFAIL_MSG( wxT("Ill-formed bitmap") );
1614 }
1615
1616 wxCHECK_RET( gdk_image, wxT("couldn't create image") );
1617
1618 Create( bitmap.GetWidth(), bitmap.GetHeight() );
1619 char unsigned *data = GetData();
1620
1621 if (!data)
1622 {
1623 gdk_image_destroy( gdk_image );
1624 wxFAIL_MSG( wxT("couldn't create image") );
1625 return;
1626 }
1627
1628 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1629 if (bitmap.GetMask())
1630 {
1631 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
1632 0, 0,
1633 bitmap.GetWidth(), bitmap.GetHeight() );
1634
1635 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1636 }
1637
1638 int bpp = -1;
1639 int red_shift_right = 0;
1640 int green_shift_right = 0;
1641 int blue_shift_right = 0;
1642 int red_shift_left = 0;
1643 int green_shift_left = 0;
1644 int blue_shift_left = 0;
1645 bool use_shift = FALSE;
1646
1647 if (bitmap.GetPixmap())
1648 {
1649 GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
1650
1651 if (visual == NULL) visual = gdk_window_get_visual( wxRootWindow->window );
1652 bpp = visual->depth;
1653 if (bpp == 16) bpp = visual->red_prec + visual->green_prec + visual->blue_prec;
1654 red_shift_right = visual->red_shift;
1655 red_shift_left = 8-visual->red_prec;
1656 green_shift_right = visual->green_shift;
1657 green_shift_left = 8-visual->green_prec;
1658 blue_shift_right = visual->blue_shift;
1659 blue_shift_left = 8-visual->blue_prec;
1660
1661 use_shift = (visual->type == GDK_VISUAL_TRUE_COLOR) || (visual->type == GDK_VISUAL_DIRECT_COLOR);
1662 }
1663 if (bitmap.GetBitmap())
1664 {
1665 bpp = 1;
1666 }
1667
1668
1669 GdkColormap *cmap = gtk_widget_get_default_colormap();
1670
1671 long pos = 0;
1672 for (int j = 0; j < bitmap.GetHeight(); j++)
1673 {
1674 for (int i = 0; i < bitmap.GetWidth(); i++)
1675 {
1676 wxUint32 pixel = gdk_image_get_pixel( gdk_image, i, j );
1677 if (bpp == 1)
1678 {
1679 if (pixel == 0)
1680 {
1681 data[pos] = 0;
1682 data[pos+1] = 0;
1683 data[pos+2] = 0;
1684 }
1685 else
1686 {
1687 data[pos] = 255;
1688 data[pos+1] = 255;
1689 data[pos+2] = 255;
1690 }
1691 }
1692 else if (use_shift)
1693 {
1694 data[pos] = (pixel >> red_shift_right) << red_shift_left;
1695 data[pos+1] = (pixel >> green_shift_right) << green_shift_left;
1696 data[pos+2] = (pixel >> blue_shift_right) << blue_shift_left;
1697 }
1698 else if (cmap->colors)
1699 {
1700 data[pos] = cmap->colors[pixel].red >> 8;
1701 data[pos+1] = cmap->colors[pixel].green >> 8;
1702 data[pos+2] = cmap->colors[pixel].blue >> 8;
1703 }
1704 else
1705 {
1706 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
1707 }
1708
1709 if (gdk_image_mask)
1710 {
1711 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1712 if (mask_pixel == 0)
1713 {
1714 data[pos] = 16;
1715 data[pos+1] = 16;
1716 data[pos+2] = 16;
1717 }
1718 }
1719
1720 pos += 3;
1721 }
1722 }
1723
1724 gdk_image_destroy( gdk_image );
1725 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1726 }
1727
1728 #endif
1729
1730 //-----------------------------------------------------------------------------
1731 // Motif conversion routines
1732 //-----------------------------------------------------------------------------
1733
1734 #ifdef __WXMOTIF__
1735 #ifdef __VMS__
1736 #pragma message disable nosimpint
1737 #endif
1738 #include <Xm/Xm.h>
1739 #ifdef __VMS__
1740 #pragma message enable nosimpint
1741 #endif
1742 #include "wx/utils.h"
1743 #include <math.h>
1744
1745 /*
1746
1747 Date: Wed, 05 Jan 2000 11:45:40 +0100
1748 From: Frits Boel <boel@niob.knaw.nl>
1749 To: julian.smart@ukonline.co.uk
1750 Subject: Patch for Motif ConvertToBitmap
1751
1752 Hi Julian,
1753
1754 I've been working on a wxWin application for image processing. From the
1755 beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
1756 till I looked in the source code of image.cpp. I saw that converting a
1757 wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
1758 to the 256 colors of the palet. A very time-consuming piece of code!
1759
1760 Because I wanted a faster application, I've made a 'patch' for this. In
1761 short: every pixel of the image is compared to a sorted list with
1762 colors. If the color is found in the list, the palette entry is
1763 returned; if the color is not found, the color palette is searched and
1764 then the palette entry is returned and the color added to the sorted
1765 list.
1766
1767 Maybe there is another method for this, namely changing the palette
1768 itself (if the colors are known, as is the case with tiffs with a
1769 colormap). I did not look at this, maybe someone else did?
1770
1771 The code of the patch is attached, have a look on it, and maybe you will
1772 ship it with the next release of wxMotif?
1773
1774 Regards,
1775
1776 Frits Boel
1777 Software engineer at Hubrecht Laboratory, The Netherlands.
1778
1779 */
1780
1781 class wxSearchColor
1782 {
1783 public:
1784 wxSearchColor( void );
1785 wxSearchColor( int size, XColor *colors );
1786 ~wxSearchColor( void );
1787
1788 int SearchColor( int r, int g, int b );
1789 private:
1790 int AddColor( unsigned int value, int pos );
1791
1792 int size;
1793 XColor *colors;
1794 unsigned int *color;
1795 int *entry;
1796
1797 int bottom;
1798 int top;
1799 };
1800
1801 wxSearchColor::wxSearchColor( void )
1802 {
1803 size = 0;
1804 colors = (XColor*) NULL;
1805 color = (unsigned int *) NULL;
1806 entry = (int*) NULL;
1807
1808 bottom = 0;
1809 top = 0;
1810 }
1811
1812 wxSearchColor::wxSearchColor( int size_, XColor *colors_ )
1813 {
1814 int i;
1815 size = size_;
1816 colors = colors_;
1817 color = new unsigned int[size];
1818 entry = new int [size];
1819
1820 for (i = 0; i < size; i++ ) {
1821 entry[i] = -1;
1822 }
1823
1824 bottom = top = ( size >> 1 );
1825 }
1826
1827 wxSearchColor::~wxSearchColor( void )
1828 {
1829 if ( color ) delete color;
1830 if ( entry ) delete entry;
1831 }
1832
1833 int wxSearchColor::SearchColor( int r, int g, int b )
1834 {
1835 unsigned int value = ( ( ( r * 256 ) + g ) * 256 ) + b;
1836 int begin = bottom;
1837 int end = top;
1838 int middle;
1839
1840 while ( begin <= end ) {
1841
1842 middle = ( begin + end ) >> 1;
1843
1844 if ( value == color[middle] ) {
1845 return( entry[middle] );
1846 } else if ( value < color[middle] ) {
1847 end = middle - 1;
1848 } else {
1849 begin = middle + 1;
1850 }
1851
1852 }
1853
1854 return AddColor( value, middle );
1855 }
1856
1857 int wxSearchColor::AddColor( unsigned int value, int pos )
1858 {
1859 int i;
1860 int pixel = -1;
1861 int max = 3 * (65536);
1862 for ( i = 0; i < 256; i++ ) {
1863 int rdiff = ((value >> 8) & 0xFF00 ) - colors[i].red;
1864 int gdiff = ((value ) & 0xFF00 ) - colors[i].green;
1865 int bdiff = ((value << 8) & 0xFF00 ) - colors[i].blue;
1866 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
1867 if (sum < max) { pixel = i; max = sum; }
1868 }
1869
1870 if ( entry[pos] < 0 ) {
1871 color[pos] = value;
1872 entry[pos] = pixel;
1873 } else if ( value < color[pos] ) {
1874
1875 if ( bottom > 0 ) {
1876 for ( i = bottom; i < pos; i++ ) {
1877 color[i-1] = color[i];
1878 entry[i-1] = entry[i];
1879 }
1880 bottom--;
1881 color[pos-1] = value;
1882 entry[pos-1] = pixel;
1883 } else if ( top < size-1 ) {
1884 for ( i = top; i >= pos; i-- ) {
1885 color[i+1] = color[i];
1886 entry[i+1] = entry[i];
1887 }
1888 top++;
1889 color[pos] = value;
1890 entry[pos] = pixel;
1891 }
1892
1893 } else {
1894
1895 if ( top < size-1 ) {
1896 for ( i = top; i > pos; i-- ) {
1897 color[i+1] = color[i];
1898 entry[i+1] = entry[i];
1899 }
1900 top++;
1901 color[pos+1] = value;
1902 entry[pos+1] = pixel;
1903 } else if ( bottom > 0 ) {
1904 for ( i = bottom; i < pos; i++ ) {
1905 color[i-1] = color[i];
1906 entry[i-1] = entry[i];
1907 }
1908 bottom--;
1909 color[pos] = value;
1910 entry[pos] = pixel;
1911 }
1912
1913 }
1914
1915 return( pixel );
1916 }
1917
1918 wxBitmap wxImage::ConvertToBitmap() const
1919 {
1920 wxBitmap bitmap;
1921
1922 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
1923
1924 int width = GetWidth();
1925 int height = GetHeight();
1926
1927 bitmap.SetHeight( height );
1928 bitmap.SetWidth( width );
1929
1930 Display *dpy = (Display*) wxGetDisplay();
1931 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
1932 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
1933
1934 // Create image
1935
1936 XImage *data_image = XCreateImage( dpy, vis, bpp, ZPixmap, 0, 0, width, height, 32, 0 );
1937 data_image->data = (char*) malloc( data_image->bytes_per_line * data_image->height );
1938
1939 bitmap.Create( width, height, bpp );
1940
1941 /*
1942 // Create mask
1943
1944 GdkImage *mask_image = (GdkImage*) NULL;
1945
1946 if (HasMask())
1947 {
1948 unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
1949
1950 mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height );
1951
1952 wxMask *mask = new wxMask();
1953 mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 );
1954
1955 bitmap.SetMask( mask );
1956 }
1957 */
1958
1959 // Retrieve depth info
1960
1961 XVisualInfo vinfo_template;
1962 XVisualInfo *vi;
1963
1964 vinfo_template.visual = vis;
1965 vinfo_template.visualid = XVisualIDFromVisual( vis );
1966 vinfo_template.depth = bpp;
1967 int nitem = 0;
1968
1969 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
1970
1971 wxCHECK_MSG( vi, wxNullBitmap, wxT("no visual") );
1972
1973 XFree( vi );
1974
1975 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
1976 if (bpp < 8) bpp = 8;
1977
1978 // Render
1979
1980 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1981 byte_order b_o = RGB;
1982
1983 if (bpp >= 24)
1984 {
1985 if ((vi->red_mask > vi->green_mask) && (vi->green_mask > vi->blue_mask)) b_o = RGB;
1986 else if ((vi->red_mask > vi->blue_mask) && (vi->blue_mask > vi->green_mask)) b_o = RGB;
1987 else if ((vi->blue_mask > vi->red_mask) && (vi->red_mask > vi->green_mask)) b_o = BRG;
1988 else if ((vi->blue_mask > vi->green_mask) && (vi->green_mask > vi->red_mask)) b_o = BGR;
1989 else if ((vi->green_mask > vi->red_mask) && (vi->red_mask > vi->blue_mask)) b_o = GRB;
1990 else if ((vi->green_mask > vi->blue_mask) && (vi->blue_mask > vi->red_mask)) b_o = GBR;
1991 }
1992
1993 /*
1994 int r_mask = GetMaskRed();
1995 int g_mask = GetMaskGreen();
1996 int b_mask = GetMaskBlue();
1997 */
1998
1999 XColor colors[256];
2000 if (bpp == 8)
2001 {
2002 Colormap cmap = (Colormap) wxTheApp->GetMainColormap( dpy );
2003
2004 for (int i = 0; i < 256; i++) colors[i].pixel = i;
2005 XQueryColors( dpy, cmap, colors, 256 );
2006 }
2007
2008 wxSearchColor scolor( 256, colors );
2009 unsigned char* data = GetData();
2010
2011 int index = 0;
2012 for (int y = 0; y < height; y++)
2013 {
2014 for (int x = 0; x < width; x++)
2015 {
2016 int r = data[index];
2017 index++;
2018 int g = data[index];
2019 index++;
2020 int b = data[index];
2021 index++;
2022
2023 /*
2024 if (HasMask())
2025 {
2026 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
2027 gdk_image_put_pixel( mask_image, x, y, 1 );
2028 else
2029 gdk_image_put_pixel( mask_image, x, y, 0 );
2030 }
2031 */
2032
2033 switch (bpp)
2034 {
2035 case 8:
2036 {
2037 #if 0 // Old, slower code
2038 int pixel = -1;
2039 /*
2040 if (wxTheApp->m_colorCube)
2041 {
2042 pixel = wxTheApp->m_colorCube
2043 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
2044 }
2045 else
2046 {
2047 */
2048 int max = 3 * (65536);
2049 for (int i = 0; i < 256; i++)
2050 {
2051 int rdiff = (r << 8) - colors[i].red;
2052 int gdiff = (g << 8) - colors[i].green;
2053 int bdiff = (b << 8) - colors[i].blue;
2054 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
2055 if (sum < max) { pixel = i; max = sum; }
2056 }
2057 /*
2058 }
2059 */
2060 #endif
2061
2062 // And this is all to get the 'right' color...
2063 int pixel = scolor.SearchColor( r, g, b );
2064 XPutPixel( data_image, x, y, pixel );
2065 break;
2066 }
2067 case 15:
2068 {
2069 int pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
2070 XPutPixel( data_image, x, y, pixel );
2071 break;
2072 }
2073 case 16:
2074 {
2075 int pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
2076 XPutPixel( data_image, x, y, pixel );
2077 break;
2078 }
2079 case 32:
2080 case 24:
2081 {
2082 int pixel = 0;
2083 switch (b_o)
2084 {
2085 case RGB: pixel = (r << 16) | (g << 8) | b; break;
2086 case RBG: pixel = (r << 16) | (b << 8) | g; break;
2087 case BRG: pixel = (b << 16) | (r << 8) | g; break;
2088 case BGR: pixel = (b << 16) | (g << 8) | r; break;
2089 case GRB: pixel = (g << 16) | (r << 8) | b; break;
2090 case GBR: pixel = (g << 16) | (b << 8) | r; break;
2091 }
2092 XPutPixel( data_image, x, y, pixel );
2093 }
2094 default: break;
2095 }
2096 } // for
2097 } // for
2098
2099 // Blit picture
2100
2101 XGCValues gcvalues;
2102 gcvalues.foreground = BlackPixel( dpy, DefaultScreen( dpy ) );
2103 GC gc = XCreateGC( dpy, RootWindow ( dpy, DefaultScreen(dpy) ), GCForeground, &gcvalues );
2104 XPutImage( dpy, (Drawable)bitmap.GetPixmap(), gc, data_image, 0, 0, 0, 0, width, height );
2105
2106 XDestroyImage( data_image );
2107 XFreeGC( dpy, gc );
2108
2109 /*
2110 // Blit mask
2111
2112 if (HasMask())
2113 {
2114 GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() );
2115
2116 gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
2117
2118 gdk_image_destroy( mask_image );
2119 gdk_gc_unref( mask_gc );
2120 }
2121 */
2122
2123 return bitmap;
2124 }
2125
2126 wxImage::wxImage( const wxBitmap &bitmap )
2127 {
2128 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
2129
2130 Display *dpy = (Display*) wxGetDisplay();
2131 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
2132 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
2133
2134 XImage *ximage = XGetImage( dpy,
2135 (Drawable)bitmap.GetPixmap(),
2136 0, 0,
2137 bitmap.GetWidth(), bitmap.GetHeight(),
2138 AllPlanes, ZPixmap );
2139
2140 wxCHECK_RET( ximage, wxT("couldn't create image") );
2141
2142 Create( bitmap.GetWidth(), bitmap.GetHeight() );
2143 char unsigned *data = GetData();
2144
2145 if (!data)
2146 {
2147 XDestroyImage( ximage );
2148 wxFAIL_MSG( wxT("couldn't create image") );
2149 return;
2150 }
2151
2152 /*
2153 GdkImage *gdk_image_mask = (GdkImage*) NULL;
2154 if (bitmap.GetMask())
2155 {
2156 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
2157 0, 0,
2158 bitmap.GetWidth(), bitmap.GetHeight() );
2159
2160 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
2161 }
2162 */
2163
2164 // Retrieve depth info
2165
2166 XVisualInfo vinfo_template;
2167 XVisualInfo *vi;
2168
2169 vinfo_template.visual = vis;
2170 vinfo_template.visualid = XVisualIDFromVisual( vis );
2171 vinfo_template.depth = bpp;
2172 int nitem = 0;
2173
2174 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
2175
2176 wxCHECK_RET( vi, wxT("no visual") );
2177
2178 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
2179
2180 XFree( vi );
2181
2182 XColor colors[256];
2183 if (bpp == 8)
2184 {
2185 Colormap cmap = (Colormap)wxTheApp->GetMainColormap( dpy );
2186
2187 for (int i = 0; i < 256; i++) colors[i].pixel = i;
2188 XQueryColors( dpy, cmap, colors, 256 );
2189 }
2190
2191 long pos = 0;
2192 for (int j = 0; j < bitmap.GetHeight(); j++)
2193 {
2194 for (int i = 0; i < bitmap.GetWidth(); i++)
2195 {
2196 int pixel = XGetPixel( ximage, i, j );
2197 if (bpp <= 8)
2198 {
2199 data[pos] = colors[pixel].red >> 8;
2200 data[pos+1] = colors[pixel].green >> 8;
2201 data[pos+2] = colors[pixel].blue >> 8;
2202 } else if (bpp == 15)
2203 {
2204 data[pos] = (pixel >> 7) & 0xf8;
2205 data[pos+1] = (pixel >> 2) & 0xf8;
2206 data[pos+2] = (pixel << 3) & 0xf8;
2207 } else if (bpp == 16)
2208 {
2209 data[pos] = (pixel >> 8) & 0xf8;
2210 data[pos+1] = (pixel >> 3) & 0xfc;
2211 data[pos+2] = (pixel << 3) & 0xf8;
2212 } else
2213 {
2214 data[pos] = (pixel >> 16) & 0xff;
2215 data[pos+1] = (pixel >> 8) & 0xff;
2216 data[pos+2] = pixel & 0xff;
2217 }
2218
2219 /*
2220 if (gdk_image_mask)
2221 {
2222 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
2223 if (mask_pixel == 0)
2224 {
2225 data[pos] = 16;
2226 data[pos+1] = 16;
2227 data[pos+2] = 16;
2228 }
2229 }
2230 */
2231
2232 pos += 3;
2233 }
2234 }
2235
2236 XDestroyImage( ximage );
2237 /*
2238 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
2239 */
2240 }
2241 #endif
2242
2243 #ifdef __WXPM__
2244 // OS/2 Presentation manager conversion routings
2245
2246 wxBitmap wxImage::ConvertToBitmap() const
2247 {
2248 if ( !Ok() )
2249 return wxNullBitmap;
2250 wxBitmap bitmap; // remove
2251 // TODO:
2252 /*
2253 int sizeLimit = 1024*768*3;
2254
2255 // width and height of the device-dependent bitmap
2256 int width = GetWidth();
2257 int bmpHeight = GetHeight();
2258
2259 // calc the number of bytes per scanline and padding
2260 int bytePerLine = width*3;
2261 int sizeDWORD = sizeof( DWORD );
2262 int lineBoundary = bytePerLine % sizeDWORD;
2263 int padding = 0;
2264 if( lineBoundary > 0 )
2265 {
2266 padding = sizeDWORD - lineBoundary;
2267 bytePerLine += padding;
2268 }
2269 // calc the number of DIBs and heights of DIBs
2270 int numDIB = 1;
2271 int hRemain = 0;
2272 int height = sizeLimit/bytePerLine;
2273 if( height >= bmpHeight )
2274 height = bmpHeight;
2275 else
2276 {
2277 numDIB = bmpHeight / height;
2278 hRemain = bmpHeight % height;
2279 if( hRemain >0 ) numDIB++;
2280 }
2281
2282 // set bitmap parameters
2283 wxBitmap bitmap;
2284 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
2285 bitmap.SetWidth( width );
2286 bitmap.SetHeight( bmpHeight );
2287 bitmap.SetDepth( wxDisplayDepth() );
2288
2289 // create a DIB header
2290 int headersize = sizeof(BITMAPINFOHEADER);
2291 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2292 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
2293 // Fill in the DIB header
2294 lpDIBh->bmiHeader.biSize = headersize;
2295 lpDIBh->bmiHeader.biWidth = (DWORD)width;
2296 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2297 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2298 // the general formula for biSizeImage:
2299 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
2300 lpDIBh->bmiHeader.biPlanes = 1;
2301 lpDIBh->bmiHeader.biBitCount = 24;
2302 lpDIBh->bmiHeader.biCompression = BI_RGB;
2303 lpDIBh->bmiHeader.biClrUsed = 0;
2304 // These seem not really needed for our purpose here.
2305 lpDIBh->bmiHeader.biClrImportant = 0;
2306 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2307 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2308 // memory for DIB data
2309 unsigned char *lpBits;
2310 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
2311 if( !lpBits )
2312 {
2313 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
2314 free( lpDIBh );
2315 return bitmap;
2316 }
2317
2318 // create and set the device-dependent bitmap
2319 HDC hdc = ::GetDC(NULL);
2320 HDC memdc = ::CreateCompatibleDC( hdc );
2321 HBITMAP hbitmap;
2322 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
2323 ::SelectObject( memdc, hbitmap);
2324
2325 // copy image data into DIB data and then into DDB (in a loop)
2326 unsigned char *data = GetData();
2327 int i, j, n;
2328 int origin = 0;
2329 unsigned char *ptdata = data;
2330 unsigned char *ptbits;
2331
2332 for( n=0; n<numDIB; n++ )
2333 {
2334 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
2335 {
2336 // redefine height and size of the (possibly) last smaller DIB
2337 // memory is not reallocated
2338 height = hRemain;
2339 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2340 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2341 }
2342 ptbits = lpBits;
2343
2344 for( j=0; j<height; j++ )
2345 {
2346 for( i=0; i<width; i++ )
2347 {
2348 *(ptbits++) = *(ptdata+2);
2349 *(ptbits++) = *(ptdata+1);
2350 *(ptbits++) = *(ptdata );
2351 ptdata += 3;
2352 }
2353 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
2354 }
2355 ::StretchDIBits( memdc, 0, origin, width, height,\
2356 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2357 origin += height;
2358 // if numDIB = 1, lines below can also be used
2359 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
2360 // The above line is equivalent to the following two lines.
2361 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2362 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
2363 // or the following lines
2364 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2365 // HDC memdc = ::CreateCompatibleDC( hdc );
2366 // ::SelectObject( memdc, hbitmap);
2367 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
2368 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
2369 // ::SelectObject( memdc, 0 );
2370 // ::DeleteDC( memdc );
2371 }
2372 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
2373
2374 // similarly, created an mono-bitmap for the possible mask
2375 if( HasMask() )
2376 {
2377 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
2378 ::SelectObject( memdc, hbitmap);
2379 if( numDIB == 1 ) height = bmpHeight;
2380 else height = sizeLimit/bytePerLine;
2381 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2382 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2383 origin = 0;
2384 unsigned char r = GetMaskRed();
2385 unsigned char g = GetMaskGreen();
2386 unsigned char b = GetMaskBlue();
2387 unsigned char zero = 0, one = 255;
2388 ptdata = data;
2389 for( n=0; n<numDIB; n++ )
2390 {
2391 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
2392 {
2393 // redefine height and size of the (possibly) last smaller DIB
2394 // memory is not reallocated
2395 height = hRemain;
2396 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2397 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2398 }
2399 ptbits = lpBits;
2400 for( int j=0; j<height; j++ )
2401 {
2402 for(i=0; i<width; i++ )
2403 {
2404 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
2405 {
2406 *(ptbits++) = one;
2407 *(ptbits++) = one;
2408 *(ptbits++) = one;
2409 }
2410 else
2411 {
2412 *(ptbits++) = zero;
2413 *(ptbits++) = zero;
2414 *(ptbits++) = zero;
2415 }
2416 }
2417 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
2418 }
2419 ::StretchDIBits( memdc, 0, origin, width, height,\
2420 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2421 origin += height;
2422 }
2423 // create a wxMask object
2424 wxMask *mask = new wxMask();
2425 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
2426 bitmap.SetMask( mask );
2427 }
2428
2429 // free allocated resources
2430 ::SelectObject( memdc, 0 );
2431 ::DeleteDC( memdc );
2432 ::ReleaseDC(NULL, hdc);
2433 free(lpDIBh);
2434 free(lpBits);
2435
2436 // check the wxBitmap object
2437 if( bitmap.GetHBITMAP() )
2438 bitmap.SetOk( TRUE );
2439 else
2440 bitmap.SetOk( FALSE );
2441 */
2442 return bitmap;
2443 }
2444
2445 wxImage::wxImage( const wxBitmap &bitmap )
2446 {
2447 // check the bitmap
2448 if( !bitmap.Ok() )
2449 {
2450 wxFAIL_MSG( wxT("invalid bitmap") );
2451 return;
2452 }
2453
2454 // create an wxImage object
2455 int width = bitmap.GetWidth();
2456 int height = bitmap.GetHeight();
2457 Create( width, height );
2458 unsigned char *data = GetData();
2459 if( !data )
2460 {
2461 wxFAIL_MSG( wxT("could not allocate data for image") );
2462 return;
2463 }
2464
2465 // calc the number of bytes per scanline and padding in the DIB
2466 int bytePerLine = width*3;
2467 int sizeDWORD = sizeof( DWORD );
2468 int lineBoundary = bytePerLine % sizeDWORD;
2469 int padding = 0;
2470 if( lineBoundary > 0 )
2471 {
2472 padding = sizeDWORD - lineBoundary;
2473 bytePerLine += padding;
2474 }
2475 // TODO:
2476 /*
2477 // create a DIB header
2478 int headersize = sizeof(BITMAPINFOHEADER);
2479 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2480 if( !lpDIBh )
2481 {
2482 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
2483 free( data );
2484 return;
2485 }
2486 // Fill in the DIB header
2487 lpDIBh->bmiHeader.biSize = headersize;
2488 lpDIBh->bmiHeader.biWidth = width;
2489 lpDIBh->bmiHeader.biHeight = -height;
2490 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
2491 lpDIBh->bmiHeader.biPlanes = 1;
2492 lpDIBh->bmiHeader.biBitCount = 24;
2493 lpDIBh->bmiHeader.biCompression = BI_RGB;
2494 lpDIBh->bmiHeader.biClrUsed = 0;
2495 // These seem not really needed for our purpose here.
2496 lpDIBh->bmiHeader.biClrImportant = 0;
2497 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2498 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2499 // memory for DIB data
2500 unsigned char *lpBits;
2501 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
2502 if( !lpBits )
2503 {
2504 wxFAIL_MSG( wxT("could not allocate data for DIB") );
2505 free( data );
2506 free( lpDIBh );
2507 return;
2508 }
2509
2510 // copy data from the device-dependent bitmap to the DIB
2511 HDC hdc = ::GetDC(NULL);
2512 HBITMAP hbitmap;
2513 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
2514 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2515
2516 // copy DIB data into the wxImage object
2517 int i, j;
2518 unsigned char *ptdata = data;
2519 unsigned char *ptbits = lpBits;
2520 for( i=0; i<height; i++ )
2521 {
2522 for( j=0; j<width; j++ )
2523 {
2524 *(ptdata++) = *(ptbits+2);
2525 *(ptdata++) = *(ptbits+1);
2526 *(ptdata++) = *(ptbits );
2527 ptbits += 3;
2528 }
2529 ptbits += padding;
2530 }
2531
2532 // similarly, set data according to the possible mask bitmap
2533 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
2534 {
2535 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
2536 // memory DC created, color set, data copied, and memory DC deleted
2537 HDC memdc = ::CreateCompatibleDC( hdc );
2538 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
2539 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
2540 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2541 ::DeleteDC( memdc );
2542 // background color set to RGB(16,16,16) in consistent with wxGTK
2543 unsigned char r=16, g=16, b=16;
2544 ptdata = data;
2545 ptbits = lpBits;
2546 for( i=0; i<height; i++ )
2547 {
2548 for( j=0; j<width; j++ )
2549 {
2550 if( *ptbits != 0 )
2551 ptdata += 3;
2552 else
2553 {
2554 *(ptdata++) = r;
2555 *(ptdata++) = g;
2556 *(ptdata++) = b;
2557 }
2558 ptbits += 3;
2559 }
2560 ptbits += padding;
2561 }
2562 SetMaskColour( r, g, b );
2563 SetMask( TRUE );
2564 }
2565 else
2566 {
2567 SetMask( FALSE );
2568 }
2569 // free allocated resources
2570 ::ReleaseDC(NULL, hdc);
2571 free(lpDIBh);
2572 free(lpBits);
2573 */
2574 }
2575
2576 #endif
2577
2578 // A module to allow wxImage initialization/cleanup
2579 // without calling these functions from app.cpp or from
2580 // the user's application.
2581
2582 class wxImageModule: public wxModule
2583 {
2584 DECLARE_DYNAMIC_CLASS(wxImageModule)
2585 public:
2586 wxImageModule() {}
2587 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE; };
2588 void OnExit() { wxImage::CleanUpHandlers(); };
2589 };
2590
2591 IMPLEMENT_DYNAMIC_CLASS(wxImageModule, wxModule)
2592
2593
2594 //-----------------------------------------------------------------------------
2595
2596 // GRG, Dic/99
2597 // Counts and returns the number of different colours. Optionally stops
2598 // when it exceeds 'stopafter' different colours. This is useful, for
2599 // example, to see if the image can be saved as 8-bit (256 colour or
2600 // less, in this case it would be invoked as CountColours(256)). Default
2601 // value for stopafter is -1 (don't care).
2602 //
2603 unsigned long wxImage::CountColours( unsigned long stopafter )
2604 {
2605 wxHashTable h;
2606 wxNode *node;
2607 wxHNode *hnode;
2608 unsigned char r, g, b, *p;
2609 unsigned long size, nentries, key;
2610
2611 p = GetData();
2612 size = GetWidth() * GetHeight();
2613 nentries = 0;
2614
2615 for (unsigned long j = 0; (j < size) && (nentries <= stopafter) ; j++)
2616 {
2617 r = *(p++);
2618 g = *(p++);
2619 b = *(p++);
2620 key = (r << 16) | (g << 8) | b;
2621
2622 hnode = (wxHNode *) h.Get(key);
2623
2624 if (!hnode)
2625 {
2626 h.Put(key, (wxObject *)(new wxHNode));
2627 nentries++;
2628 }
2629 }
2630
2631 // delete all HNodes
2632 h.BeginFind();
2633 while ((node = h.Next()) != NULL)
2634 delete (wxHNode *)node->GetData();
2635
2636 return nentries;
2637 }
2638
2639
2640 // GRG, Dic/99
2641 // Computes the histogram of the image and fills a hash table, indexed
2642 // with integer keys built as 0xRRGGBB, containing wxHNode objects. Each
2643 // wxHNode contains an 'index' (useful to build a palette with the image
2644 // colours) and a 'value', which is the number of pixels in the image with
2645 // that colour.
2646 //
2647 unsigned long wxImage::ComputeHistogram( wxHashTable &h )
2648 {
2649 unsigned char r, g, b, *p;
2650 unsigned long size, nentries, key;
2651 wxHNode *hnode;
2652
2653 p = GetData();
2654 size = GetWidth() * GetHeight();
2655 nentries = 0;
2656
2657 for (unsigned long j = 0; j < size; j++)
2658 {
2659 r = *(p++);
2660 g = *(p++);
2661 b = *(p++);
2662 key = (r << 16) | (g << 8) | b;
2663
2664 hnode = (wxHNode *) h.Get(key);
2665
2666 if (hnode)
2667 hnode->value++;
2668 else
2669 {
2670 hnode = new wxHNode();
2671 hnode->index = nentries++;
2672 hnode->value = 1;
2673
2674 h.Put(key, (wxObject *)hnode);
2675 }
2676 }
2677
2678 return nentries;
2679 }
2680
2681