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