]> git.saurik.com Git - wxWidgets.git/blob - src/common/image.cpp
Finally deprecated callbacks.
[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 // Create mask
1949
1950 XImage *mask_image = (XImage*) NULL;
1951 if (HasMask())
1952 {
1953 mask_image = XCreateImage( dpy, vis, 1, ZPixmap, 0, 0, width, height, 32, 0 );
1954 mask_image->data = (char*) malloc( mask_image->bytes_per_line * mask_image->height );
1955 }
1956
1957 // Retrieve depth info
1958
1959 XVisualInfo vinfo_template;
1960 XVisualInfo *vi;
1961
1962 vinfo_template.visual = vis;
1963 vinfo_template.visualid = XVisualIDFromVisual( vis );
1964 vinfo_template.depth = bpp;
1965 int nitem = 0;
1966
1967 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
1968
1969 wxCHECK_MSG( vi, wxNullBitmap, wxT("no visual") );
1970
1971 XFree( vi );
1972
1973 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
1974 if (bpp < 8) bpp = 8;
1975
1976 // Render
1977
1978 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1979 byte_order b_o = RGB;
1980
1981 if (bpp >= 24)
1982 {
1983 if ((vi->red_mask > vi->green_mask) && (vi->green_mask > vi->blue_mask)) b_o = RGB;
1984 else if ((vi->red_mask > vi->blue_mask) && (vi->blue_mask > vi->green_mask)) b_o = RGB;
1985 else if ((vi->blue_mask > vi->red_mask) && (vi->red_mask > vi->green_mask)) b_o = BRG;
1986 else if ((vi->blue_mask > vi->green_mask) && (vi->green_mask > vi->red_mask)) b_o = BGR;
1987 else if ((vi->green_mask > vi->red_mask) && (vi->red_mask > vi->blue_mask)) b_o = GRB;
1988 else if ((vi->green_mask > vi->blue_mask) && (vi->blue_mask > vi->red_mask)) b_o = GBR;
1989 }
1990
1991 int r_mask = GetMaskRed();
1992 int g_mask = GetMaskGreen();
1993 int b_mask = GetMaskBlue();
1994
1995 XColor colors[256];
1996 if (bpp == 8)
1997 {
1998 Colormap cmap = (Colormap) wxTheApp->GetMainColormap( dpy );
1999
2000 for (int i = 0; i < 256; i++) colors[i].pixel = i;
2001 XQueryColors( dpy, cmap, colors, 256 );
2002 }
2003
2004 wxSearchColor scolor( 256, colors );
2005 unsigned char* data = GetData();
2006
2007 bool hasMask = HasMask();
2008
2009 int index = 0;
2010 for (int y = 0; y < height; y++)
2011 {
2012 for (int x = 0; x < width; x++)
2013 {
2014 int r = data[index];
2015 index++;
2016 int g = data[index];
2017 index++;
2018 int b = data[index];
2019 index++;
2020
2021 if (hasMask)
2022 {
2023 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
2024 XPutPixel( mask_image, x, y, 0 );
2025 else
2026 XPutPixel( mask_image, x, y, 1 );
2027 }
2028
2029 switch (bpp)
2030 {
2031 case 8:
2032 {
2033 #if 0 // Old, slower code
2034 int pixel = -1;
2035 /*
2036 if (wxTheApp->m_colorCube)
2037 {
2038 pixel = wxTheApp->m_colorCube
2039 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
2040 }
2041 else
2042 {
2043 */
2044 int max = 3 * (65536);
2045 for (int i = 0; i < 256; i++)
2046 {
2047 int rdiff = (r << 8) - colors[i].red;
2048 int gdiff = (g << 8) - colors[i].green;
2049 int bdiff = (b << 8) - colors[i].blue;
2050 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
2051 if (sum < max) { pixel = i; max = sum; }
2052 }
2053 /*
2054 }
2055 */
2056 #endif
2057
2058 // And this is all to get the 'right' color...
2059 int pixel = scolor.SearchColor( r, g, b );
2060 XPutPixel( data_image, x, y, pixel );
2061 break;
2062 }
2063 case 15:
2064 {
2065 int pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
2066 XPutPixel( data_image, x, y, pixel );
2067 break;
2068 }
2069 case 16:
2070 {
2071 int pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
2072 XPutPixel( data_image, x, y, pixel );
2073 break;
2074 }
2075 case 32:
2076 case 24:
2077 {
2078 int pixel = 0;
2079 switch (b_o)
2080 {
2081 case RGB: pixel = (r << 16) | (g << 8) | b; break;
2082 case RBG: pixel = (r << 16) | (b << 8) | g; break;
2083 case BRG: pixel = (b << 16) | (r << 8) | g; break;
2084 case BGR: pixel = (b << 16) | (g << 8) | r; break;
2085 case GRB: pixel = (g << 16) | (r << 8) | b; break;
2086 case GBR: pixel = (g << 16) | (b << 8) | r; break;
2087 }
2088 XPutPixel( data_image, x, y, pixel );
2089 }
2090 default: break;
2091 }
2092 } // for
2093 } // for
2094
2095 // Blit picture
2096
2097 XGCValues gcvalues;
2098 gcvalues.foreground = BlackPixel( dpy, DefaultScreen( dpy ) );
2099 GC gc = XCreateGC( dpy, RootWindow ( dpy, DefaultScreen(dpy) ), GCForeground, &gcvalues );
2100 XPutImage( dpy, (Drawable)bitmap.GetPixmap(), gc, data_image, 0, 0, 0, 0, width, height );
2101
2102 XDestroyImage( data_image );
2103 XFreeGC( dpy, gc );
2104
2105 // Blit mask
2106 if (HasMask())
2107 {
2108 wxBitmap maskBitmap(width, height, 1);
2109
2110 GC gcMask = XCreateGC( dpy, (Pixmap) maskBitmap.GetPixmap(), (XtGCMask) 0, (XGCValues*)NULL );
2111 XPutImage( dpy, (Drawable)maskBitmap.GetPixmap(), gcMask, mask_image, 0, 0, 0, 0, width, height );
2112
2113 XDestroyImage( mask_image );
2114 XFreeGC( dpy, gcMask );
2115
2116 wxMask* mask = new wxMask;
2117 mask->SetPixmap(maskBitmap.GetPixmap());
2118
2119 bitmap.SetMask(mask);
2120
2121 maskBitmap.SetPixmapNull();
2122 }
2123
2124 return bitmap;
2125 }
2126
2127 wxImage::wxImage( const wxBitmap &bitmap )
2128 {
2129 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
2130
2131 Display *dpy = (Display*) wxGetDisplay();
2132 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
2133 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
2134
2135 XImage *ximage = XGetImage( dpy,
2136 (Drawable)bitmap.GetPixmap(),
2137 0, 0,
2138 bitmap.GetWidth(), bitmap.GetHeight(),
2139 AllPlanes, ZPixmap );
2140
2141 wxCHECK_RET( ximage, wxT("couldn't create image") );
2142
2143 Create( bitmap.GetWidth(), bitmap.GetHeight() );
2144 char unsigned *data = GetData();
2145
2146 if (!data)
2147 {
2148 XDestroyImage( ximage );
2149 wxFAIL_MSG( wxT("couldn't create image") );
2150 return;
2151 }
2152
2153 /*
2154 GdkImage *gdk_image_mask = (GdkImage*) NULL;
2155 if (bitmap.GetMask())
2156 {
2157 gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(),
2158 0, 0,
2159 bitmap.GetWidth(), bitmap.GetHeight() );
2160
2161 SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
2162 }
2163 */
2164
2165 // Retrieve depth info
2166
2167 XVisualInfo vinfo_template;
2168 XVisualInfo *vi;
2169
2170 vinfo_template.visual = vis;
2171 vinfo_template.visualid = XVisualIDFromVisual( vis );
2172 vinfo_template.depth = bpp;
2173 int nitem = 0;
2174
2175 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
2176
2177 wxCHECK_RET( vi, wxT("no visual") );
2178
2179 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
2180
2181 XFree( vi );
2182
2183 XColor colors[256];
2184 if (bpp == 8)
2185 {
2186 Colormap cmap = (Colormap)wxTheApp->GetMainColormap( dpy );
2187
2188 for (int i = 0; i < 256; i++) colors[i].pixel = i;
2189 XQueryColors( dpy, cmap, colors, 256 );
2190 }
2191
2192 long pos = 0;
2193 for (int j = 0; j < bitmap.GetHeight(); j++)
2194 {
2195 for (int i = 0; i < bitmap.GetWidth(); i++)
2196 {
2197 int pixel = XGetPixel( ximage, i, j );
2198 if (bpp <= 8)
2199 {
2200 data[pos] = colors[pixel].red >> 8;
2201 data[pos+1] = colors[pixel].green >> 8;
2202 data[pos+2] = colors[pixel].blue >> 8;
2203 } else if (bpp == 15)
2204 {
2205 data[pos] = (pixel >> 7) & 0xf8;
2206 data[pos+1] = (pixel >> 2) & 0xf8;
2207 data[pos+2] = (pixel << 3) & 0xf8;
2208 } else if (bpp == 16)
2209 {
2210 data[pos] = (pixel >> 8) & 0xf8;
2211 data[pos+1] = (pixel >> 3) & 0xfc;
2212 data[pos+2] = (pixel << 3) & 0xf8;
2213 } else
2214 {
2215 data[pos] = (pixel >> 16) & 0xff;
2216 data[pos+1] = (pixel >> 8) & 0xff;
2217 data[pos+2] = pixel & 0xff;
2218 }
2219
2220 /*
2221 if (gdk_image_mask)
2222 {
2223 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
2224 if (mask_pixel == 0)
2225 {
2226 data[pos] = 16;
2227 data[pos+1] = 16;
2228 data[pos+2] = 16;
2229 }
2230 }
2231 */
2232
2233 pos += 3;
2234 }
2235 }
2236
2237 XDestroyImage( ximage );
2238 /*
2239 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
2240 */
2241 }
2242 #endif
2243
2244 #ifdef __WXPM__
2245 // OS/2 Presentation manager conversion routings
2246
2247 wxBitmap wxImage::ConvertToBitmap() const
2248 {
2249 if ( !Ok() )
2250 return wxNullBitmap;
2251 wxBitmap bitmap; // remove
2252 // TODO:
2253 /*
2254 int sizeLimit = 1024*768*3;
2255
2256 // width and height of the device-dependent bitmap
2257 int width = GetWidth();
2258 int bmpHeight = GetHeight();
2259
2260 // calc the number of bytes per scanline and padding
2261 int bytePerLine = width*3;
2262 int sizeDWORD = sizeof( DWORD );
2263 int lineBoundary = bytePerLine % sizeDWORD;
2264 int padding = 0;
2265 if( lineBoundary > 0 )
2266 {
2267 padding = sizeDWORD - lineBoundary;
2268 bytePerLine += padding;
2269 }
2270 // calc the number of DIBs and heights of DIBs
2271 int numDIB = 1;
2272 int hRemain = 0;
2273 int height = sizeLimit/bytePerLine;
2274 if( height >= bmpHeight )
2275 height = bmpHeight;
2276 else
2277 {
2278 numDIB = bmpHeight / height;
2279 hRemain = bmpHeight % height;
2280 if( hRemain >0 ) numDIB++;
2281 }
2282
2283 // set bitmap parameters
2284 wxBitmap bitmap;
2285 wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
2286 bitmap.SetWidth( width );
2287 bitmap.SetHeight( bmpHeight );
2288 bitmap.SetDepth( wxDisplayDepth() );
2289
2290 // create a DIB header
2291 int headersize = sizeof(BITMAPINFOHEADER);
2292 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2293 wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
2294 // Fill in the DIB header
2295 lpDIBh->bmiHeader.biSize = headersize;
2296 lpDIBh->bmiHeader.biWidth = (DWORD)width;
2297 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2298 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2299 // the general formula for biSizeImage:
2300 // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
2301 lpDIBh->bmiHeader.biPlanes = 1;
2302 lpDIBh->bmiHeader.biBitCount = 24;
2303 lpDIBh->bmiHeader.biCompression = BI_RGB;
2304 lpDIBh->bmiHeader.biClrUsed = 0;
2305 // These seem not really needed for our purpose here.
2306 lpDIBh->bmiHeader.biClrImportant = 0;
2307 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2308 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2309 // memory for DIB data
2310 unsigned char *lpBits;
2311 lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
2312 if( !lpBits )
2313 {
2314 wxFAIL_MSG( wxT("could not allocate memory for DIB") );
2315 free( lpDIBh );
2316 return bitmap;
2317 }
2318
2319 // create and set the device-dependent bitmap
2320 HDC hdc = ::GetDC(NULL);
2321 HDC memdc = ::CreateCompatibleDC( hdc );
2322 HBITMAP hbitmap;
2323 hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
2324 ::SelectObject( memdc, hbitmap);
2325
2326 // copy image data into DIB data and then into DDB (in a loop)
2327 unsigned char *data = GetData();
2328 int i, j, n;
2329 int origin = 0;
2330 unsigned char *ptdata = data;
2331 unsigned char *ptbits;
2332
2333 for( n=0; n<numDIB; n++ )
2334 {
2335 if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
2336 {
2337 // redefine height and size of the (possibly) last smaller DIB
2338 // memory is not reallocated
2339 height = hRemain;
2340 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2341 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2342 }
2343 ptbits = lpBits;
2344
2345 for( j=0; j<height; j++ )
2346 {
2347 for( i=0; i<width; i++ )
2348 {
2349 *(ptbits++) = *(ptdata+2);
2350 *(ptbits++) = *(ptdata+1);
2351 *(ptbits++) = *(ptdata );
2352 ptdata += 3;
2353 }
2354 for( i=0; i< padding; i++ ) *(ptbits++) = 0;
2355 }
2356 ::StretchDIBits( memdc, 0, origin, width, height,\
2357 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2358 origin += height;
2359 // if numDIB = 1, lines below can also be used
2360 // hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
2361 // The above line is equivalent to the following two lines.
2362 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2363 // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
2364 // or the following lines
2365 // hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
2366 // HDC memdc = ::CreateCompatibleDC( hdc );
2367 // ::SelectObject( memdc, hbitmap);
2368 // ::SetDIBitsToDevice( memdc, 0, 0, width, height,
2369 // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
2370 // ::SelectObject( memdc, 0 );
2371 // ::DeleteDC( memdc );
2372 }
2373 bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
2374
2375 // similarly, created an mono-bitmap for the possible mask
2376 if( HasMask() )
2377 {
2378 hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
2379 ::SelectObject( memdc, hbitmap);
2380 if( numDIB == 1 ) height = bmpHeight;
2381 else height = sizeLimit/bytePerLine;
2382 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2383 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2384 origin = 0;
2385 unsigned char r = GetMaskRed();
2386 unsigned char g = GetMaskGreen();
2387 unsigned char b = GetMaskBlue();
2388 unsigned char zero = 0, one = 255;
2389 ptdata = data;
2390 for( n=0; n<numDIB; n++ )
2391 {
2392 if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
2393 {
2394 // redefine height and size of the (possibly) last smaller DIB
2395 // memory is not reallocated
2396 height = hRemain;
2397 lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
2398 lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
2399 }
2400 ptbits = lpBits;
2401 for( int j=0; j<height; j++ )
2402 {
2403 for(i=0; i<width; i++ )
2404 {
2405 if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
2406 {
2407 *(ptbits++) = one;
2408 *(ptbits++) = one;
2409 *(ptbits++) = one;
2410 }
2411 else
2412 {
2413 *(ptbits++) = zero;
2414 *(ptbits++) = zero;
2415 *(ptbits++) = zero;
2416 }
2417 }
2418 for( i=0; i< padding; i++ ) *(ptbits++) = zero;
2419 }
2420 ::StretchDIBits( memdc, 0, origin, width, height,\
2421 0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
2422 origin += height;
2423 }
2424 // create a wxMask object
2425 wxMask *mask = new wxMask();
2426 mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
2427 bitmap.SetMask( mask );
2428 }
2429
2430 // free allocated resources
2431 ::SelectObject( memdc, 0 );
2432 ::DeleteDC( memdc );
2433 ::ReleaseDC(NULL, hdc);
2434 free(lpDIBh);
2435 free(lpBits);
2436
2437 // check the wxBitmap object
2438 if( bitmap.GetHBITMAP() )
2439 bitmap.SetOk( TRUE );
2440 else
2441 bitmap.SetOk( FALSE );
2442 */
2443 return bitmap;
2444 }
2445
2446 wxImage::wxImage( const wxBitmap &bitmap )
2447 {
2448 // check the bitmap
2449 if( !bitmap.Ok() )
2450 {
2451 wxFAIL_MSG( wxT("invalid bitmap") );
2452 return;
2453 }
2454
2455 // create an wxImage object
2456 int width = bitmap.GetWidth();
2457 int height = bitmap.GetHeight();
2458 Create( width, height );
2459 unsigned char *data = GetData();
2460 if( !data )
2461 {
2462 wxFAIL_MSG( wxT("could not allocate data for image") );
2463 return;
2464 }
2465
2466 // calc the number of bytes per scanline and padding in the DIB
2467 int bytePerLine = width*3;
2468 int sizeDWORD = sizeof( DWORD );
2469 int lineBoundary = bytePerLine % sizeDWORD;
2470 int padding = 0;
2471 if( lineBoundary > 0 )
2472 {
2473 padding = sizeDWORD - lineBoundary;
2474 bytePerLine += padding;
2475 }
2476 // TODO:
2477 /*
2478 // create a DIB header
2479 int headersize = sizeof(BITMAPINFOHEADER);
2480 LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
2481 if( !lpDIBh )
2482 {
2483 wxFAIL_MSG( wxT("could not allocate data for DIB header") );
2484 free( data );
2485 return;
2486 }
2487 // Fill in the DIB header
2488 lpDIBh->bmiHeader.biSize = headersize;
2489 lpDIBh->bmiHeader.biWidth = width;
2490 lpDIBh->bmiHeader.biHeight = -height;
2491 lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
2492 lpDIBh->bmiHeader.biPlanes = 1;
2493 lpDIBh->bmiHeader.biBitCount = 24;
2494 lpDIBh->bmiHeader.biCompression = BI_RGB;
2495 lpDIBh->bmiHeader.biClrUsed = 0;
2496 // These seem not really needed for our purpose here.
2497 lpDIBh->bmiHeader.biClrImportant = 0;
2498 lpDIBh->bmiHeader.biXPelsPerMeter = 0;
2499 lpDIBh->bmiHeader.biYPelsPerMeter = 0;
2500 // memory for DIB data
2501 unsigned char *lpBits;
2502 lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
2503 if( !lpBits )
2504 {
2505 wxFAIL_MSG( wxT("could not allocate data for DIB") );
2506 free( data );
2507 free( lpDIBh );
2508 return;
2509 }
2510
2511 // copy data from the device-dependent bitmap to the DIB
2512 HDC hdc = ::GetDC(NULL);
2513 HBITMAP hbitmap;
2514 hbitmap = (HBITMAP) bitmap.GetHBITMAP();
2515 ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2516
2517 // copy DIB data into the wxImage object
2518 int i, j;
2519 unsigned char *ptdata = data;
2520 unsigned char *ptbits = lpBits;
2521 for( i=0; i<height; i++ )
2522 {
2523 for( j=0; j<width; j++ )
2524 {
2525 *(ptdata++) = *(ptbits+2);
2526 *(ptdata++) = *(ptbits+1);
2527 *(ptdata++) = *(ptbits );
2528 ptbits += 3;
2529 }
2530 ptbits += padding;
2531 }
2532
2533 // similarly, set data according to the possible mask bitmap
2534 if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
2535 {
2536 hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
2537 // memory DC created, color set, data copied, and memory DC deleted
2538 HDC memdc = ::CreateCompatibleDC( hdc );
2539 ::SetTextColor( memdc, RGB( 0, 0, 0 ) );
2540 ::SetBkColor( memdc, RGB( 255, 255, 255 ) );
2541 ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
2542 ::DeleteDC( memdc );
2543 // background color set to RGB(16,16,16) in consistent with wxGTK
2544 unsigned char r=16, g=16, b=16;
2545 ptdata = data;
2546 ptbits = lpBits;
2547 for( i=0; i<height; i++ )
2548 {
2549 for( j=0; j<width; j++ )
2550 {
2551 if( *ptbits != 0 )
2552 ptdata += 3;
2553 else
2554 {
2555 *(ptdata++) = r;
2556 *(ptdata++) = g;
2557 *(ptdata++) = b;
2558 }
2559 ptbits += 3;
2560 }
2561 ptbits += padding;
2562 }
2563 SetMaskColour( r, g, b );
2564 SetMask( TRUE );
2565 }
2566 else
2567 {
2568 SetMask( FALSE );
2569 }
2570 // free allocated resources
2571 ::ReleaseDC(NULL, hdc);
2572 free(lpDIBh);
2573 free(lpBits);
2574 */
2575 }
2576
2577 #endif
2578
2579 // A module to allow wxImage initialization/cleanup
2580 // without calling these functions from app.cpp or from
2581 // the user's application.
2582
2583 class wxImageModule: public wxModule
2584 {
2585 DECLARE_DYNAMIC_CLASS(wxImageModule)
2586 public:
2587 wxImageModule() {}
2588 bool OnInit() { wxImage::InitStandardHandlers(); return TRUE; };
2589 void OnExit() { wxImage::CleanUpHandlers(); };
2590 };
2591
2592 IMPLEMENT_DYNAMIC_CLASS(wxImageModule, wxModule)
2593
2594
2595 //-----------------------------------------------------------------------------
2596
2597 // GRG, Dic/99
2598 // Counts and returns the number of different colours. Optionally stops
2599 // when it exceeds 'stopafter' different colours. This is useful, for
2600 // example, to see if the image can be saved as 8-bit (256 colour or
2601 // less, in this case it would be invoked as CountColours(256)). Default
2602 // value for stopafter is -1 (don't care).
2603 //
2604 unsigned long wxImage::CountColours( unsigned long stopafter )
2605 {
2606 wxHashTable h;
2607 wxObject dummy;
2608 unsigned char r, g, b, *p;
2609 unsigned long size, nentries, key;
2610
2611 p = GetData();
2612 size = GetWidth() * GetHeight();
2613 nentries = 0;
2614
2615 for (unsigned long j = 0; (j < size) && (nentries <= stopafter) ; j++)
2616 {
2617 r = *(p++);
2618 g = *(p++);
2619 b = *(p++);
2620 key = (r << 16) | (g << 8) | b;
2621
2622 if (h.Get(key) == NULL)
2623 {
2624 h.Put(key, &dummy);
2625 nentries++;
2626 }
2627 }
2628
2629 return nentries;
2630 }
2631
2632
2633 // GRG, Dic/99
2634 // Computes the histogram of the image and fills a hash table, indexed
2635 // with integer keys built as 0xRRGGBB, containing wxHNode objects. Each
2636 // wxHNode contains an 'index' (useful to build a palette with the image
2637 // colours) and a 'value', which is the number of pixels in the image with
2638 // that colour.
2639 //
2640 unsigned long wxImage::ComputeHistogram( wxHashTable &h )
2641 {
2642 unsigned char r, g, b, *p;
2643 unsigned long size, nentries, key;
2644 wxHNode *hnode;
2645
2646 p = GetData();
2647 size = GetWidth() * GetHeight();
2648 nentries = 0;
2649
2650 for (unsigned long j = 0; j < size; j++)
2651 {
2652 r = *(p++);
2653 g = *(p++);
2654 b = *(p++);
2655 key = (r << 16) | (g << 8) | b;
2656
2657 hnode = (wxHNode *) h.Get(key);
2658
2659 if (hnode)
2660 hnode->value++;
2661 else
2662 {
2663 hnode = new wxHNode();
2664 hnode->index = nentries++;
2665 hnode->value = 1;
2666
2667 h.Put(key, (wxObject *)hnode);
2668 }
2669 }
2670
2671 return nentries;
2672 }
2673
2674 /*
2675 * Rotation code by Carlos Moreno
2676 */
2677
2678 // GRG: I've removed wxRotationPoint - we already have wxRealPoint which
2679 // does exactly the same thing. And I also got rid of wxRotationPixel
2680 // bacause of potential problems in architectures where alignment
2681 // is an issue, so I had to rewrite parts of the code.
2682
2683 static const double gs_Epsilon = 1e-10;
2684
2685 static inline int wxCint (double x)
2686 {
2687 return (x > 0) ? (int) (x + 0.5) : (int) (x - 0.5);
2688 }
2689
2690
2691 // Auxiliary function to rotate a point (x,y) with respect to point p0
2692 // make it inline and use a straight return to facilitate optimization
2693 // also, the function receives the sine and cosine of the angle to avoid
2694 // repeating the time-consuming calls to these functions -- sin/cos can
2695 // be computed and stored in the calling function.
2696
2697 inline wxRealPoint rotated_point (const wxRealPoint & p, double cos_angle, double sin_angle, const wxRealPoint & p0)
2698 {
2699 return wxRealPoint (p0.x + (p.x - p0.x) * cos_angle - (p.y - p0.y) * sin_angle,
2700 p0.y + (p.y - p0.y) * cos_angle + (p.x - p0.x) * sin_angle);
2701 }
2702
2703 inline wxRealPoint rotated_point (double x, double y, double cos_angle, double sin_angle, const wxRealPoint & p0)
2704 {
2705 return rotated_point (wxRealPoint(x,y), cos_angle, sin_angle, p0);
2706 }
2707
2708 wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool interpolating, wxPoint * offset_after_rotation) const
2709 {
2710 int i;
2711 angle = -angle; // screen coordinates are a mirror image of "real" coordinates
2712
2713 // Create pointer-based array to accelerate access to wxImage's data
2714 unsigned char ** data = new unsigned char * [GetHeight()];
2715
2716 data[0] = GetData();
2717
2718 for (i = 1; i < GetHeight(); i++)
2719 data[i] = data[i - 1] + (3 * GetWidth());
2720
2721 // precompute coefficients for rotation formula
2722 // (sine and cosine of the angle)
2723 const double cos_angle = cos(angle);
2724 const double sin_angle = sin(angle);
2725
2726 // Create new Image to store the result
2727 // First, find rectangle that covers the rotated image; to do that,
2728 // rotate the four corners
2729
2730 const wxRealPoint p0(centre_of_rotation.x, centre_of_rotation.y);
2731
2732 wxRealPoint p1 = rotated_point (0, 0, cos_angle, sin_angle, p0);
2733 wxRealPoint p2 = rotated_point (0, GetHeight(), cos_angle, sin_angle, p0);
2734 wxRealPoint p3 = rotated_point (GetWidth(), 0, cos_angle, sin_angle, p0);
2735 wxRealPoint p4 = rotated_point (GetWidth(), GetHeight(), cos_angle, sin_angle, p0);
2736
2737 int x1 = (int) floor (wxMin (wxMin(p1.x, p2.x), wxMin(p3.x, p4.x)));
2738 int y1 = (int) floor (wxMin (wxMin(p1.y, p2.y), wxMin(p3.y, p4.y)));
2739 int x2 = (int) ceil (wxMax (wxMax(p1.x, p2.x), wxMax(p3.x, p4.x)));
2740 int y2 = (int) ceil (wxMax (wxMax(p1.y, p2.y), wxMax(p3.y, p4.y)));
2741
2742 wxImage rotated (x2 - x1 + 1, y2 - y1 + 1);
2743
2744 if (offset_after_rotation != NULL)
2745 {
2746 *offset_after_rotation = wxPoint (x1, y1);
2747 }
2748
2749 // GRG: The rotated (destination) image is always accessed
2750 // sequentially, so there is no need for a pointer-based
2751 // array here (and in fact it would be slower).
2752 //
2753 unsigned char * dst = rotated.GetData();
2754
2755 // GRG: if the original image has a mask, use its RGB values
2756 // as the blank pixel, else, fall back to default (black).
2757 //
2758 unsigned char blank_r = 0;
2759 unsigned char blank_g = 0;
2760 unsigned char blank_b = 0;
2761
2762 if (HasMask())
2763 {
2764 blank_r = GetMaskRed();
2765 blank_g = GetMaskGreen();
2766 blank_b = GetMaskBlue();
2767 rotated.SetMaskColour( blank_r, blank_g, blank_b );
2768 }
2769
2770 // Now, for each point of the rotated image, find where it came from, by
2771 // performing an inverse rotation (a rotation of -angle) and getting the
2772 // pixel at those coordinates
2773
2774 // GRG: I've taken the (interpolating) test out of the loops, so that
2775 // it is done only once, instead of repeating it for each pixel.
2776
2777 int x;
2778 if (interpolating)
2779 {
2780 for (int y = 0; y < rotated.GetHeight(); y++)
2781 {
2782 for (x = 0; x < rotated.GetWidth(); x++)
2783 {
2784 wxRealPoint src = rotated_point (x + x1, y + y1, cos_angle, -sin_angle, p0);
2785
2786 if (-0.25 < src.x && src.x < GetWidth() - 0.75 &&
2787 -0.25 < src.y && src.y < GetHeight() - 0.75)
2788 {
2789 // interpolate using the 4 enclosing grid-points. Those
2790 // points can be obtained using floor and ceiling of the
2791 // exact coordinates of the point
2792 // C.M. 2000-02-17: when the point is near the border, special care is required.
2793
2794 int x1, y1, x2, y2;
2795
2796 if (0 < src.x && src.x < GetWidth() - 1)
2797 {
2798 x1 = wxCint(floor(src.x));
2799 x2 = wxCint(ceil(src.x));
2800 }
2801 else // else means that x is near one of the borders (0 or width-1)
2802 {
2803 x1 = x2 = wxCint (src.x);
2804 }
2805
2806 if (0 < src.y && src.y < GetHeight() - 1)
2807 {
2808 y1 = wxCint(floor(src.y));
2809 y2 = wxCint(ceil(src.y));
2810 }
2811 else
2812 {
2813 y1 = y2 = wxCint (src.y);
2814 }
2815
2816 // get four points and the distances (square of the distance,
2817 // for efficiency reasons) for the interpolation formula
2818
2819 // GRG: Do not calculate the points until they are
2820 // really needed -- this way we can calculate
2821 // just one, instead of four, if d1, d2, d3
2822 // or d4 are < gs_Epsilon
2823
2824 const double d1 = (src.x - x1) * (src.x - x1) + (src.y - y1) * (src.y - y1);
2825 const double d2 = (src.x - x2) * (src.x - x2) + (src.y - y1) * (src.y - y1);
2826 const double d3 = (src.x - x2) * (src.x - x2) + (src.y - y2) * (src.y - y2);
2827 const double d4 = (src.x - x1) * (src.x - x1) + (src.y - y2) * (src.y - y2);
2828
2829 // Now interpolate as a weighted average of the four surrounding
2830 // points, where the weights are the distances to each of those points
2831
2832 // If the point is exactly at one point of the grid of the source
2833 // image, then don't interpolate -- just assign the pixel
2834
2835 if (d1 < gs_Epsilon) // d1,d2,d3,d4 are positive -- no need for abs()
2836 {
2837 unsigned char *p = data[y1] + (3 * x1);
2838 *(dst++) = *(p++);
2839 *(dst++) = *(p++);
2840 *(dst++) = *(p++);
2841 }
2842 else if (d2 < gs_Epsilon)
2843 {
2844 unsigned char *p = data[y1] + (3 * x2);
2845 *(dst++) = *(p++);
2846 *(dst++) = *(p++);
2847 *(dst++) = *(p++);
2848 }
2849 else if (d3 < gs_Epsilon)
2850 {
2851 unsigned char *p = data[y2] + (3 * x2);
2852 *(dst++) = *(p++);
2853 *(dst++) = *(p++);
2854 *(dst++) = *(p++);
2855 }
2856 else if (d4 < gs_Epsilon)
2857 {
2858 unsigned char *p = data[y2] + (3 * x1);
2859 *(dst++) = *(p++);
2860 *(dst++) = *(p++);
2861 *(dst++) = *(p++);
2862 }
2863 else
2864 {
2865 // weights for the weighted average are proportional to the inverse of the distance
2866 unsigned char *v1 = data[y1] + (3 * x1);
2867 unsigned char *v2 = data[y1] + (3 * x2);
2868 unsigned char *v3 = data[y2] + (3 * x2);
2869 unsigned char *v4 = data[y2] + (3 * x1);
2870
2871 const double w1 = 1/d1, w2 = 1/d2, w3 = 1/d3, w4 = 1/d4;
2872
2873 // GRG: Unrolled.
2874
2875 *(dst++) = (unsigned char)
2876 ( (w1 * *(v1++) + w2 * *(v2++) +
2877 w3 * *(v3++) + w4 * *(v4++)) /
2878 (w1 + w2 + w3 + w4) );
2879 *(dst++) = (unsigned char)
2880 ( (w1 * *(v1++) + w2 * *(v2++) +
2881 w3 * *(v3++) + w4 * *(v4++)) /
2882 (w1 + w2 + w3 + w4) );
2883 *(dst++) = (unsigned char)
2884 ( (w1 * *(v1++) + w2 * *(v2++) +
2885 w3 * *(v3++) + w4 * *(v4++)) /
2886 (w1 + w2 + w3 + w4) );
2887 }
2888 }
2889 else
2890 {
2891 *(dst++) = blank_r;
2892 *(dst++) = blank_g;
2893 *(dst++) = blank_b;
2894 }
2895 }
2896 }
2897 }
2898 else // not interpolating
2899 {
2900 for (int y = 0; y < rotated.GetHeight(); y++)
2901 {
2902 for (x = 0; x < rotated.GetWidth(); x++)
2903 {
2904 wxRealPoint src = rotated_point (x + x1, y + y1, cos_angle, -sin_angle, p0);
2905
2906 const int xs = wxCint (src.x); // wxCint rounds to the
2907 const int ys = wxCint (src.y); // closest integer
2908
2909 if (0 <= xs && xs < GetWidth() &&
2910 0 <= ys && ys < GetHeight())
2911 {
2912 unsigned char *p = data[ys] + (3 * xs);
2913 *(dst++) = *(p++);
2914 *(dst++) = *(p++);
2915 *(dst++) = *(p++);
2916 }
2917 else
2918 {
2919 *(dst++) = blank_r;
2920 *(dst++) = blank_g;
2921 *(dst++) = blank_b;
2922 }
2923 }
2924 }
2925 }
2926
2927 delete [] data;
2928
2929 return rotated;
2930 }
2931