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