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