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