1 /********************************************************************************
2 *                                                                               *
3 *                             I m a g e    O b j e c t                          *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1997,2020 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or modify          *
9 * it under the terms of the GNU Lesser General Public License as published by   *
10 * the Free Software Foundation; either version 3 of the License, or             *
11 * (at your option) any later version.                                           *
12 *                                                                               *
13 * This library is distributed in the hope that it will be useful,               *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                 *
16 * GNU Lesser General Public License for more details.                           *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public License      *
19 * along with this program.  If not, see <http://www.gnu.org/licenses/>          *
20 ********************************************************************************/
21 #include "xincs.h"
22 #include "fxver.h"
23 #include "fxdefs.h"
24 #include "fxmath.h"
25 #include "FXArray.h"
26 #include "FXHash.h"
27 #include "FXMutex.h"
28 #include "FXElement.h"
29 #include "FXStream.h"
30 #include "FXString.h"
31 #include "FXSize.h"
32 #include "FXPoint.h"
33 #include "FXRectangle.h"
34 #include "FXException.h"
35 #include "FXStringDictionary.h"
36 #include "FXSettings.h"
37 #include "FXRegistry.h"
38 #include "FXVisual.h"
39 #include "FXEvent.h"
40 #include "FXWindow.h"
41 #include "FXDCWindow.h"
42 #include "FXApp.h"
43 #include "FXImage.h"
44 
45 
46 /*
47   Notes:
48   - FXImage::create() renders rgb[a] data into X/GDI resident, device
49     dependent pixmap.
50   - Need to be able to re-render subpart of image.
51   - We should implement shared pixmaps.
52   - If IMAGE_KEEP, repeated rendering is usually desired; should we
53     hang on to XImage, and the shared memory segment in that case?
54     How about shared pixmaps...
55   - Slight change in interpretation of IMAGE_OWNED flag:- if passed, the
56     FXImage will own client-side pixel buffer, otherwise it will not; if
57     no pixel-buffer has been passed and IMAGE_OWNED *is* passed, a pixel
58     buffer will be allocated [and cleared to zero].
59     No pixel buffer will be allocated if neither IMAGE_OWNED nor pixels
60     are passed.
61   - When using shared image/pixmaps, if IMAGE_KEEP is set, hang on to pixel buffer.
62   - We need to speed up 16/15 bpp true color.
63   - We need dither tables with 3bit and 2bit rounding for 5,6,5/5,5,5 modes
64   - We need dither tables with 5bit, 6bit rounding for 3,3,2 mode.
65   - We need to split true color from direct color, because direct color
66     has random mapping, true has not.
67   - Just because I always forget:
68 
69       StaticGray   0
70       GrayScale    1
71       StaticColor  2
72       PseudoColor  3
73       TrueColor    4
74       DirectColor  5
75 
76   - The smooth scaling algorithm is based on the idea of keeping track which
77     pixels of the source are contributing to each pixel in the destination.
78 
79     The smallest fraction of a pixel of interest is 1/(w*w'), where w is
80     the old width, and w' is the new one.
81 
82     Consider scaling from 3->7 pixels, with 1/(w*w') being 1/21:
83 
84       Source Pixel 2 --------------+        Source Pixel is 7/21 units wide
85       Source Pixel 1 --------+     |
86       Source Pixel 0 -+      |     |
87                       |      |     |
88                       v      v     v
89       Original:    000000011111112222222
90       Scaled:      000111222333444555666
91                     ^  ^  ^  ^  ^  ^  ^
92                     |  |  |  |  |  |  |
93       Dest Pixel 0 -+  |  |  |  |  |  |
94       Dest Pixel 1 ----+  |  |  |  |  |
95       Dest Pixel 2 -------+  |  |  |  |
96       Dest Pixel 3 ----------+  |  |  |
97       Dest Pixel 4 -------------+  |  |
98       Dest Pixel 5 ----------------+  |
99       Dest Pixel 6 -------------------+     Dest Pixel is 3/21 units wide
100 
101     As can be seen from the picture above, destination pixel 2 is comprised
102     of 1/3 times source pixel 0, and 2/3 times source pixel 1.  Splitting
103     into the individual fragments yields 9 fragments total:
104 
105       Fragment     0   1 2  3   4  5 6   7   8
106       ========================================
107       Original:  000 000 0 11 111 11 2 222 222
108       Scaled:    000 111 2 22 333 44 4 555 666
109 
110     Note no fragment can be smaller than one unit, or 1/(w*w').
111 
112     The algorithm iterates over fragments; and for each fragment, it adds
113     the source pixel multiplied by the length of the fragment.  It repeats
114     until enough fragments have been collected to make one output pixel:
115 
116       fin  = w';                        The fractions fin and fout have
117       fout = w;                         been multiplied by w*w'
118       in   = 0;
119       out  = 0;
120       acc  = 0;
121       while out < w' do
122         if fin < fout then
123           acc = acc + fin*source[in];   Add fin units of source pixel
124           fout = fout - fin;
125           fin = outw;
126           in = in + 1;
127         else
128           acc = acc + fout*source[in];  Add fout (the remaining unfilled fraction) of source pixel
129           dest[out] = acc / w;          Output one pixel
130           acc = 0;
131           fin = fin - fout;
132           fout = inw;
133           out = out + 1;
134         end if
135       end while
136 
137     Remember, you saw it here first!!!!
138 
139   - When compositing, out-of-image data behaves as if clear (0,0,0,0)
140   - Absence of data behaves as if clear
141   - Operations work on subrectangle of an image
142   - Images and regions are at least 1x1 pixels
143   - Operations of the form a = a op b, or a = op a.
144   - Fast blend (0..255) colors:
145 
146       blue  = (ALPHA * (sb - db) >> 8) + db;
147       green = (ALPHA * (sg - dg) >> 8) + dg;
148       red   = (ALPHA * (sr - dr) >> 8) + dr;
149 
150   - Fast division by 255:
151 
152       r=(i+(i>>8)+1)>>8);
153 
154   - Rotate using 3 shear operations:
155 
156      { cos(phi) -sin(phi) }   { 1 -tan(phi/2) }   { 1         0 }   { 1  -tan(phi/2) }
157      {                    } = {               } x {             } x {                }
158      { sin(phi)  cos(phi) }   { 0      1      }   { sin(phi)  1 }   { 0      1       }
159 
160   - Need to move to BGRA components; 4x faster with OpenGL!
161 */
162 
163 
164 #define DISPLAY(app) ((Display*)((app)->display))
165 
166 // Changable image options
167 #define IMAGE_MASK   (IMAGE_KEEP|IMAGE_NEAREST|IMAGE_OPAQUE|IMAGE_ALPHACOLOR|IMAGE_SHMI|IMAGE_SHMP|IMAGE_ALPHAGUESS|IMAGE_THRESGUESS)
168 
169 // Maximum size of the colormap; for high-end graphics systems
170 // you may want to define HIGHENDGRAPHICS to allow for large colormaps
171 #ifdef HIGHENDGRAPHICS
172 #define MAX_MAPSIZE 4096
173 #else
174 #define MAX_MAPSIZE 256
175 #endif
176 
177 using namespace FX;
178 
179 /*******************************************************************************/
180 
181 namespace FX {
182 
183 // RGB Ordering code
184 enum {
185   RGB = 7,   // RGB 111      > | R  G  B
186   BGR = 0,   // BGR 000      --+--------
187   RBG = 6,   // RBG 110      R | x  4  2
188   GBR = 1,   // GBR 001      G |    x  1
189   BRG = 4,   // BRG 100      B |       x
190   GRB = 3    // GRB 011
191   };
192 
193 
194 // Object implementation
195 FXIMPLEMENT(FXImage,FXDrawable,NULL,0)
196 
197 
198 // For deserialization
FXImage()199 FXImage::FXImage():data(NULL),options(0){
200   }
201 
202 
203 // Initialize
FXImage(FXApp * a,const FXColor * pix,FXuint opts,FXint w,FXint h)204 FXImage::FXImage(FXApp* a,const FXColor *pix,FXuint opts,FXint w,FXint h):FXDrawable(a,w,h){
205   FXTRACE((100,"FXImage::FXImage %p\n",this));
206   FXASSERT((opts&~(IMAGE_OWNED|IMAGE_MASK))==0);
207   visual=getApp()->getDefaultVisual();
208   data=(FXColor*)pix;
209   options=opts;
210   if(!data && (options&IMAGE_OWNED)){           // This is confusing use of IMAGE_OWNED
211     if(!callocElms(data,width*height)){ throw FXMemoryException("unable to construct image"); }
212     }
213   }
214 
215 
216 // Change options
setOptions(FXuint opts)217 void FXImage::setOptions(FXuint opts){
218   options=(options&~IMAGE_MASK) | (opts&IMAGE_MASK);
219   }
220 
221 
222 // Set pixel data ownership flag
setOwned(FXbool owned)223 void FXImage::setOwned(FXbool owned){
224   options^=((0-owned)^options)&IMAGE_OWNED;
225   }
226 
227 
228 // Get pixel ownership flag
isOwned() const229 FXbool FXImage::isOwned() const {
230   return (options&IMAGE_OWNED)!=0;
231   }
232 
233 
234 // Attach pixel buffer to image, and assume ownership of it if IMAGE_OWNED is passed
setData(FXColor * pix,FXuint opts)235 void FXImage::setData(FXColor *pix,FXuint opts){
236 
237   // Free old data
238   if(options&IMAGE_OWNED){ freeElms(data); }
239 
240   // Only own pixel buffer if one was passed
241   if(pix && (opts&IMAGE_OWNED)){
242     options|=IMAGE_OWNED;
243     }
244   else{
245     options&=~IMAGE_OWNED;
246     }
247 
248   // Set the pointer
249   data=pix;
250   }
251 
252 
253 // Populate the image with new pixel data
setData(FXColor * pix,FXuint opts,FXint w,FXint h)254 void FXImage::setData(FXColor *pix,FXuint opts,FXint w,FXint h){
255 
256   // Free old data
257   if(options&IMAGE_OWNED){ freeElms(data); }
258 
259   // Resize pixmap
260   resize(w,h);
261 
262   // Only own pixel buffer if one was passed
263   if(pix && (opts&IMAGE_OWNED)){
264     options|=IMAGE_OWNED;
265     }
266   else{
267     options&=~IMAGE_OWNED;
268     }
269 
270   // Set the pointer
271   data=pix;
272   }
273 
274 
275 // Scan the image and return false if fully opaque
hasAlpha() const276 FXbool FXImage::hasAlpha() const {
277   if(data){
278     FXint i=width*height-1;
279     do{
280       if(((const FXuchar*)(data+i))[3]<255) return true;
281       }
282     while(--i>=0);
283     }
284   return false;
285   }
286 
287 
288 #ifdef WIN32
289 
290 // Return the device context; the image already selected into it
GetDC() const291 FXID FXImage::GetDC() const {
292   HDC hdc=::CreateCompatibleDC(NULL);
293   SelectObject(hdc,(HBITMAP)xid);
294   return hdc;
295   }
296 
297 
298 // Release it (no-op)
ReleaseDC(FXID hdc) const299 int FXImage::ReleaseDC(FXID hdc) const {
300   return ::DeleteDC((HDC)hdc);
301   }
302 
303 #endif
304 
305 
306 // Create image
create()307 void FXImage::create(){
308   if(!xid){
309     if(getApp()->isInitialized()){
310       FXTRACE((100,"%s::create %p\n",getClassName(),this));
311 
312       // Initialize visual
313       visual->create();
314 
315 #ifdef WIN32
316 
317       // Create a bitmap compatible with current display
318       HDC hdc=::GetDC(GetDesktopWindow());
319       xid=CreateCompatibleBitmap(hdc,FXMAX(width,1),FXMAX(height,1));
320       ::ReleaseDC(GetDesktopWindow(),hdc);
321 
322 #else
323 
324       // Make pixmap
325       xid=XCreatePixmap(DISPLAY(getApp()),XDefaultRootWindow(DISPLAY(getApp())),FXMAX(width,1),FXMAX(height,1),visual->depth);
326 
327 #endif
328 
329       // Were we successful?
330       if(!xid){ throw FXImageException("unable to create image"); }
331 
332       // Render pixels
333       render();
334 
335       // Release pixel buffer
336       if(!(options&IMAGE_KEEP)) release();
337       }
338     }
339   }
340 
341 
342 // Detach image
detach()343 void FXImage::detach(){
344   visual->detach();
345   if(xid){
346     FXTRACE((100,"%s::detach %p\n",getClassName(),this));
347     xid=0;
348     }
349   }
350 
351 
352 // Destroy image
destroy()353 void FXImage::destroy(){
354   if(xid){
355     if(getApp()->isInitialized()){
356       FXTRACE((100,"%s::destroy %p\n",getClassName(),this));
357 #ifdef WIN32
358       DeleteObject(xid);
359 #else
360       XFreePixmap(DISPLAY(getApp()),xid);
361 #endif
362       }
363     xid=0;
364     }
365   }
366 
367 
368 #ifdef WIN32
369 
370 
371 // Restore client-side pixel buffer from image
restore()372 void FXImage::restore(){
373   if(xid){
374     FXint size,bytes_per_line,skip,x,y;
375     FXuchar *pix,*img;
376     FXuchar *pixels;
377     BITMAPINFO bmi;
378     HDC hdcmem;
379 
380     FXTRACE((100,"%s::restore image %p\n",getClassName(),this));
381 
382     // Check for legal size
383     if(width<1 || height<1){ fxerror("%s::restore: illegal image size %dx%d.\n",getClassName(),width,height); }
384 
385     // Make array for data if needed
386     if(!data){
387       size=width*height;
388       if(!allocElms(data,size)){ throw FXMemoryException("unable to restore image"); }
389       options|=IMAGE_OWNED;
390       }
391 
392     // Got local buffer to receive into
393     if(data){
394 
395       // Set up the bitmap info
396       bytes_per_line=(width*3+3)/4*4;
397       skip=bytes_per_line-width*3;
398 
399       bmi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
400       bmi.bmiHeader.biWidth=width;
401       bmi.bmiHeader.biHeight=-height; // Negative heights means upside down!
402       bmi.bmiHeader.biPlanes=1;
403       bmi.bmiHeader.biBitCount=24;
404       bmi.bmiHeader.biCompression=BI_RGB;
405       bmi.bmiHeader.biSizeImage=0;
406       bmi.bmiHeader.biXPelsPerMeter=0;
407       bmi.bmiHeader.biYPelsPerMeter=0;
408       bmi.bmiHeader.biClrUsed=0;
409       bmi.bmiHeader.biClrImportant=0;
410 
411       // DIB format pads to multiples of 4 bytes...
412       pixels=(FXuchar*)VirtualAlloc(0,bytes_per_line*height,MEM_COMMIT,PAGE_READWRITE);
413       if(!pixels){ throw FXMemoryException("unable to restore image"); }
414 
415       // Make device context
416       hdcmem=::CreateCompatibleDC(NULL);
417       if(!GetDIBits(hdcmem,(HBITMAP)xid,0,height,pixels,&bmi,DIB_RGB_COLORS)){
418         throw FXImageException("unable to restore image");
419         }
420 
421       // Stuff it into our own data structure
422       for(y=0,img=(FXuchar*)data,pix=pixels; y<height; y++){
423         for(x=0; x<width; x++){
424           img[0]=pix[0];
425           img[1]=pix[1];
426           img[2]=pix[2];
427           img[3]=255;
428           img+=4;
429           pix+=3;
430           }
431         pix+=skip;
432         }
433       VirtualFree(pixels,0,MEM_RELEASE);
434       ::DeleteDC(hdcmem);
435       }
436     }
437   }
438 
439 
440 #else                   // X11
441 
442 
443 // Find shift amount
findshift(FXPixel mask)444 static inline FXuint findshift(FXPixel mask){
445   FXuint sh=0;
446   while(!(mask&(1UL<<sh))) sh++;
447   return sh;
448   }
449 
450 
451 // Find low bit in mask
lowbit(FXPixel mask)452 static inline FXPixel lowbit(FXPixel mask){
453   return (~mask+1)&mask;
454   }
455 
456 
457 // Restore client-side pixel buffer from image
restore()458 void FXImage::restore(){
459   if(xid){
460     FXPixel red,green,blue;
461     FXPixel red1,green1,blue1;
462     FXPixel pixel;
463     FXuint  redshift,greenshift,blueshift;
464     FXPixel redmask,greenmask,bluemask;
465     int size,i;
466     FXbool shmi=false;
467     XImage *xim=NULL;
468     Visual *vis;
469     FXint x,y;
470     FXuchar *img;
471     FXuint r,g,b;
472     FXuchar rtab[MAX_MAPSIZE];
473     FXuchar gtab[MAX_MAPSIZE];
474     FXuchar btab[MAX_MAPSIZE];
475 #ifdef HAVE_XSHM_H
476     XShmSegmentInfo shminfo;
477 #endif
478 
479     FXTRACE((100,"%s::restore image %p\n",getClassName(),this));
480 
481     // Check for legal size
482     if(width<1 || height<1){ fxerror("%s::restore: illegal image size %dx%d.\n",getClassName(),width,height); }
483 
484     // Get Visual
485     vis=(Visual*)visual->visual;
486 
487     // Just in case you're on a high-end system
488     FXASSERT(vis->map_entries<=MAX_MAPSIZE);
489 
490     // Make array for data if needed
491     if(!data){
492       size=width*height;
493       if(!allocElms(data,size)){ throw FXMemoryException("unable to restore image"); }
494       options|=IMAGE_OWNED;
495       }
496 
497     // Got local buffer to receive into
498     if(data){
499 
500       // Turn it on iff both supported and desired
501 #ifdef HAVE_XSHM_H
502       if(options&IMAGE_SHMI) shmi=getApp()->shmi;
503 #endif
504 
505       // First try XShm
506 #ifdef HAVE_XSHM_H
507       if(shmi){
508         xim=XShmCreateImage(DISPLAY(getApp()),vis,visual->depth,(visual->depth==1)?XYPixmap:ZPixmap,NULL,&shminfo,width,height);
509         if(!xim){ shmi=0; }
510         if(shmi){
511           shminfo.shmid=shmget(IPC_PRIVATE,xim->bytes_per_line*xim->height,IPC_CREAT|0777);
512           if(shminfo.shmid==-1){ xim->data=NULL; XDestroyImage(xim); xim=NULL; shmi=0; }
513           if(shmi){
514             shminfo.shmaddr=xim->data=(char*)shmat(shminfo.shmid,0,0);
515             shminfo.readOnly=false;
516             XShmAttach(DISPLAY(getApp()),&shminfo);
517             FXTRACE((150,"RGBPixmap XSHM attached at memory=%p (%d bytes)\n",xim->data,xim->bytes_per_line*xim->height));
518             XShmGetImage(DISPLAY(getApp()),xid,xim,0,0,AllPlanes);
519             XSync(DISPLAY(getApp()),False);
520             }
521           }
522         }
523 #endif
524 
525       // Try the old fashioned way
526       if(!shmi){
527         xim=XGetImage(DISPLAY(getApp()),xid,0,0,width,height,AllPlanes,ZPixmap);
528         if(!xim){ throw FXImageException("unable to restore image"); }
529         }
530 
531       // Should have succeeded
532       FXASSERT(xim);
533 
534       FXTRACE((150,"im width = %d\n",xim->width));
535       FXTRACE((150,"im height = %d\n",xim->height));
536       FXTRACE((150,"im format = %s\n",xim->format==XYBitmap?"XYBitmap":xim->format==XYPixmap?"XYPixmap":"ZPixmap"));
537       FXTRACE((150,"im byte_order = %s\n",(xim->byte_order==MSBFirst)?"MSBFirst":"LSBFirst"));
538       FXTRACE((150,"im bitmap_unit = %d\n",xim->bitmap_unit));
539       FXTRACE((150,"im bitmap_bit_order = %s\n",(xim->bitmap_bit_order==MSBFirst)?"MSBFirst":"LSBFirst"));
540       FXTRACE((150,"im bitmap_pad = %d\n",xim->bitmap_pad));
541       FXTRACE((150,"im bitmap_unit = %d\n",xim->bitmap_unit));
542       FXTRACE((150,"im depth = %d\n",xim->depth));
543       FXTRACE((150,"im bytes_per_line = %d\n",xim->bytes_per_line));
544       FXTRACE((150,"im bits_per_pixel = %d\n",xim->bits_per_pixel));
545 
546 
547       {
548       XColor colors[MAX_MAPSIZE];
549 
550       // Get masks
551       redmask=vis->red_mask;
552       greenmask=vis->green_mask;
553       bluemask=vis->blue_mask;
554 
555       // Read back the colormap and convert to more usable form
556       if(vis->c_class!=TrueColor && vis->c_class!=DirectColor){
557         for(i=0 ; i<vis->map_entries; i++){
558           colors[i].pixel=i;
559           colors[i].flags=DoRed|DoGreen|DoBlue;
560           }
561         }
562       else{
563         red=green=blue=0;
564         red1=lowbit(redmask);
565         green1=lowbit(greenmask);
566         blue1=lowbit(bluemask);
567         for(i=0; i<vis->map_entries; i++){
568           colors[i].pixel=red|green|blue;
569           colors[i].flags=DoRed|DoGreen|DoBlue;
570           if(red<redmask) red+=red1;
571           if(green<greenmask) green+=green1;
572           if(blue<bluemask) blue+=blue1;
573           }
574         }
575       XQueryColors(DISPLAY(getApp()),visual->colormap,colors,vis->map_entries);
576       for(i=0; i<vis->map_entries; i++){
577         rtab[i]=colors[i].red >> 8;
578         gtab[i]=colors[i].green >> 8;
579         btab[i]=colors[i].blue >> 8;
580         }
581       }
582 
583       // Now we convert the pixels back to color
584       switch(xim->bits_per_pixel){
585         case 0:
586         case 1:
587         case 2:
588         case 3:
589         case 4:
590         case 5:
591         case 6:
592         case 7:
593         case 8:
594           for(y=0,img=(FXuchar*)data; y<height; y++){
595             for(x=0; x<width; x++){
596               pixel=XGetPixel(xim,x,y);
597               img[0]=btab[pixel];
598               img[1]=gtab[pixel];
599               img[2]=rtab[pixel];
600               img[3]=255;
601               img+=4;
602               }
603             }
604           break;
605         case 15:
606         case 16:
607         case 24:
608         case 32:
609         default:
610           FXASSERT(vis->c_class==TrueColor || vis->c_class==DirectColor);
611           redshift=findshift(redmask);
612           greenshift=findshift(greenmask);
613           blueshift=findshift(bluemask);
614           for(y=0,img=(FXuchar*)data; y<height; y++){
615             for(x=0; x<width; x++){
616               pixel=XGetPixel(xim,x,y);
617               r=(pixel&redmask)>>redshift;
618               g=(pixel&greenmask)>>greenshift;
619               b=(pixel&bluemask)>>blueshift;
620               img[0]=btab[b];
621               img[1]=gtab[g];
622               img[2]=rtab[r];
623               img[3]=255;
624               img+=4;
625               }
626             }
627           break;
628         }
629 
630       // Destroy image
631 #ifdef HAVE_XSHM_H
632       if(shmi){
633         FXTRACE((150,"RGBPixmap XSHM detached at memory=%p (%d bytes)\n",xim->data,xim->bytes_per_line*xim->height));
634         XShmDetach(DISPLAY(getApp()),&shminfo);
635         XDestroyImage(xim);
636         shmdt(shminfo.shmaddr);
637         shmctl(shminfo.shmid,IPC_RMID,0);
638         }
639 #endif
640 
641       // Destroy image
642       if(!shmi){
643         XDestroyImage(xim);
644         }
645       }
646     }
647   }
648 
649 #endif
650 
651 
652 
653 #ifdef WIN32            // WINDOWS
654 
655 
656 // Render into pixmap
render()657 void FXImage::render(){
658   if(xid){
659     FXint bytes_per_line,skip,h,w;
660     FXuchar *src,*dst;
661     BITMAPINFO bmi;
662     FXuchar *pixels;
663     HDC hdcmem;
664 
665     FXTRACE((100,"%s::render %p\n",getClassName(),this));
666 
667     // Fill with pixels if there is data
668     if(data && 0<width && 0<height){
669 
670       // Set up the bitmap info
671       bmi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
672       bmi.bmiHeader.biWidth=width;
673       bmi.bmiHeader.biHeight=height;
674       bmi.bmiHeader.biPlanes=1;
675       bmi.bmiHeader.biBitCount=24;
676       bmi.bmiHeader.biCompression=BI_RGB;
677       bmi.bmiHeader.biSizeImage=0;
678       bmi.bmiHeader.biXPelsPerMeter=0;
679       bmi.bmiHeader.biYPelsPerMeter=0;
680       bmi.bmiHeader.biClrUsed=0;
681       bmi.bmiHeader.biClrImportant=0;
682 
683       // DIB format pads to multiples of 4 bytes...
684       bytes_per_line=(width*3+3)&~3;
685       pixels=(FXuchar*)VirtualAlloc(0,bytes_per_line*height,MEM_COMMIT,PAGE_READWRITE);
686       if(!pixels){ throw FXMemoryException("unable to render image"); }
687       skip=-bytes_per_line-width*3;
688       src=(FXuchar*)data;
689       dst=pixels+height*bytes_per_line+width*3;
690       h=height;
691       do{
692         dst+=skip;
693         w=width;
694         do{
695           dst[0]=src[0];
696           dst[1]=src[1];
697           dst[2]=src[2];
698           src+=4;
699           dst+=3;
700           }
701         while(--w);
702         }
703       while(--h);
704       // The MSDN documentation for SetDIBits() states that "the device context
705       // identified by the (first) parameter is used only if the DIB_PAL_COLORS
706       // constant is set for the (last) parameter". This may be true, but under
707       // Win95 you must pass in a non-NULL hdc for the first parameter; otherwise
708       // this call to SetDIBits() will fail (in contrast, it works fine under
709       // Windows NT if you pass in a NULL hdc).
710       hdcmem=::CreateCompatibleDC(NULL);
711       if(!SetDIBits(hdcmem,(HBITMAP)xid,0,height,pixels,&bmi,DIB_RGB_COLORS)){
712 //    if(!StretchDIBits(hdcmem,0,0,width,height,0,0,width,height,pixels,&bmi,DIB_RGB_COLORS,SRCCOPY)){
713         throw FXImageException("unable to render image");
714         }
715       GdiFlush();
716       VirtualFree(pixels,0,MEM_RELEASE);
717       ::DeleteDC(hdcmem);
718       }
719     }
720   }
721 
722 
723 #else                   // X11
724 
725 
726 // True generic mode
render_true_N_fast(void * xim,FXuchar * img)727 void FXImage::render_true_N_fast(void *xim,FXuchar *img){
728   FXint x,y;
729   FXTRACE((150,"True MSB/LSB N bpp render nearest\n"));
730   y=0;
731   do{
732     x=0;
733     do{
734       XPutPixel(((XImage*)xim),x,y,visual->rpix[1][img[2]] | visual->gpix[1][img[1]] | visual->bpix[1][img[0]]);
735       img+=4;
736       }
737     while(++x<width);
738     }
739   while(++y<height);
740   }
741 
742 
743 // True generic mode
render_true_N_dither(void * xim,FXuchar * img)744 void FXImage::render_true_N_dither(void *xim,FXuchar *img){
745   FXint x,y,d;
746   FXTRACE((150,"True MSB/LSB N bpp render dither\n"));
747   y=0;
748   do{
749     x=0;
750     do{
751       d=((y&3)<<2)|(x&3);
752       XPutPixel(((XImage*)xim),x,y,visual->rpix[d][img[2]] | visual->gpix[d][img[1]] | visual->bpix[d][img[0]]);
753       img+=4;
754       }
755     while(++x<width);
756     }
757   while(++y<height);
758   }
759 
760 
761 // True 24 bit color
render_true_24(void * xim,FXuchar * img)762 void FXImage::render_true_24(void *xim,FXuchar *img){
763   FXuint jmp=((XImage*)xim)->bytes_per_line-(width*3);
764   FXuchar *pix=(FXuchar*)((XImage*)xim)->data;
765   FXPixel val;
766   FXint w,h;
767   if(((XImage*)xim)->byte_order==MSBFirst){    // MSB
768     FXTRACE((150,"True MSB 24bpp render\n"));
769     h=height-1;
770     do{
771       w=width-1;
772       do{
773         val=visual->rpix[1][img[2]] | visual->gpix[1][img[1]] | visual->bpix[1][img[0]];
774         pix[0]=(FXuchar)(val>>16);
775         pix[1]=(FXuchar)(val>>8);
776         pix[2]=(FXuchar)val;
777         img+=4;
778         pix+=3;
779         }
780       while(--w>=0);
781       pix+=jmp;
782       }
783     while(--h>=0);
784     }
785   else{                             // LSB
786     FXTRACE((150,"True LSB 24bpp render\n"));
787     h=height-1;
788     do{
789       w=width-1;
790       do{
791         val=visual->rpix[1][img[2]] | visual->gpix[1][img[1]] | visual->bpix[1][img[0]];
792         pix[0]=(FXuchar)val;
793         pix[1]=(FXuchar)(val>>8);
794         pix[2]=(FXuchar)(val>>16);
795         img+=4;
796         pix+=3;
797         }
798       while(--w>=0);
799       pix+=jmp;
800       }
801     while(--h>=0);
802     }
803   }
804 
805 
806 // True 32 bit color
render_true_32(void * xim,FXuchar * img)807 void FXImage::render_true_32(void *xim,FXuchar *img){
808   FXuchar *pix=(FXuchar*)((XImage*)xim)->data;
809   FXuint jmp=((XImage*)xim)->bytes_per_line-(width<<2);
810   FXPixel val;
811   FXint w,h;
812 
813   // Byte order matches
814   if(((XImage*)xim)->byte_order == FOX_BIGENDIAN){
815     FXTRACE((150,"True MSB/LSB 32bpp render\n"));
816     h=height-1;
817     do{
818       w=width-1;
819       do{
820         *((FXuint*)pix)=visual->rpix[1][img[2]] | visual->gpix[1][img[1]] | visual->bpix[1][img[0]];
821         img+=4;
822         pix+=4;
823         }
824       while(--w>=0);
825       pix+=jmp;
826       }
827     while(--h>=0);
828     }
829 
830   // MSB Byte order
831   else if(((XImage*)xim)->byte_order==MSBFirst){
832     FXTRACE((150,"True MSB 32bpp render\n"));
833     h=height-1;
834     do{
835       w=width-1;
836       do{
837         val=visual->rpix[1][img[2]] | visual->gpix[1][img[1]] | visual->bpix[1][img[0]];
838         pix[0]=(FXuchar)(val>>24);
839         pix[1]=(FXuchar)(val>>16);
840         pix[2]=(FXuchar)(val>>8);
841         pix[3]=(FXuchar)val;
842         img+=4;
843         pix+=4;
844         }
845       while(--w>=0);
846       pix+=jmp;
847       }
848     while(--h>=0);
849     }
850 
851   // LSB Byte order
852   else{
853     FXTRACE((150,"True LSB 32bpp render\n"));
854     h=height-1;
855     do{
856       w=width-1;
857       do{
858         val=visual->rpix[1][img[2]] | visual->gpix[1][img[1]] | visual->bpix[1][img[0]];
859         pix[0]=(FXuchar)val;
860         pix[1]=(FXuchar)(val>>8);
861         pix[2]=(FXuchar)(val>>16);
862         pix[3]=(FXuchar)(val>>24);
863         img+=4;
864         pix+=4;
865         }
866       while(--w>=0);
867       pix+=jmp;
868       }
869     while(--h>=0);
870     }
871   }
872 
873 
874 // True 16 bit color
render_true_16_fast(void * xim,FXuchar * img)875 void FXImage::render_true_16_fast(void *xim,FXuchar *img){
876   FXuint jmp=((XImage*)xim)->bytes_per_line-(width<<1);
877   FXuchar *pix=(FXuchar*)((XImage*)xim)->data;
878   FXPixel val;
879   FXint w,h;
880 
881   // Byte order matches
882   if(((XImage*)xim)->byte_order == FOX_BIGENDIAN){
883     FXTRACE((150,"True MSB/LSB 16bpp 5,6,5/5,5,5 render nearest\n"));
884     h=height-1;
885     do{
886       w=width-1;
887       do{
888         *((FXushort*)pix)=visual->rpix[1][img[2]] | visual->gpix[1][img[1]] | visual->bpix[1][img[0]];
889         img+=4;
890         pix+=2;
891         }
892       while(--w>=0);
893       pix+=jmp;
894       }
895     while(--h>=0);
896     }
897 
898   // MSB Byte order
899   else if(((XImage*)xim)->byte_order==MSBFirst){
900     FXTRACE((150,"True MSB 16bpp 5,6,5/5,5,5 render nearest\n"));
901     h=height-1;
902     do{
903       w=width-1;
904       do{
905         val=visual->rpix[1][img[2]] | visual->gpix[1][img[1]] | visual->bpix[1][img[0]];
906         pix[0]=(FXuchar)(val>>8);
907         pix[1]=(FXuchar)val;
908         img+=4;
909         pix+=2;
910         }
911       while(--w>=0);
912       pix+=jmp;
913       }
914     while(--h>=0);
915     }
916 
917   // LSB Byte order
918   else{
919     FXTRACE((150,"True LSB 16bpp 5,6,5/5,5,5 render nearest\n"));
920     h=height-1;
921     do{
922       w=width-1;
923       do{
924         val=visual->rpix[1][img[2]] | visual->gpix[1][img[1]] | visual->bpix[1][img[0]];
925         pix[0]=(FXuchar)val;
926         pix[1]=(FXuchar)(val>>8);
927         img+=4;
928         pix+=2;
929         }
930       while(--w>=0);
931       pix+=jmp;
932       }
933     while(--h>=0);
934     }
935   }
936 
937 
938 // True 16 bit color, dithered
render_true_16_dither(void * xim,FXuchar * img)939 void FXImage::render_true_16_dither(void *xim,FXuchar *img){
940   FXuint jmp=((XImage*)xim)->bytes_per_line-(width<<1);
941   FXuchar *pix=(FXuchar*)((XImage*)xim)->data;
942   FXPixel val;
943   FXint w,h,d;
944 
945   // Byte order matches
946   if(((XImage*)xim)->byte_order == FOX_BIGENDIAN){
947     FXTRACE((150,"True MSB/LSB 16bpp 5,6,5/5,5,5 render dither\n"));
948     h=height-1;
949     do{
950       w=width-1;
951       do{
952         d=((h&3)<<2)|(w&3);
953         *((FXushort*)pix)=visual->rpix[d][img[2]] | visual->gpix[d][img[1]] | visual->bpix[d][img[0]];
954         img+=4;
955         pix+=2;
956         }
957       while(--w>=0);
958       pix+=jmp;
959       }
960     while(--h>=0);
961     }
962 
963   // MSB Byte order
964   else if(((XImage*)xim)->byte_order==MSBFirst){
965     FXTRACE((150,"True MSB 16bpp 5,6,5/5,5,5 render dither\n"));
966     h=height-1;
967     do{
968       w=width-1;
969       do{
970         d=((h&3)<<2)|(w&3);
971         val=visual->rpix[d][img[2]] | visual->gpix[d][img[1]] | visual->bpix[d][img[0]];
972         pix[0]=(FXuchar)(val>>8);
973         pix[1]=(FXuchar)val;
974         img+=4;
975         pix+=2;
976         }
977       while(--w>=0);
978       pix+=jmp;
979       }
980     while(--h>=0);
981     }
982 
983   // LSB Byte order
984   else{
985     FXTRACE((150,"True LSB 16bpp 5,6,5/5,5,5 render dither\n"));
986     h=height-1;
987     do{
988       w=width-1;
989       do{
990         d=((h&3)<<2)|(w&3);
991         val=visual->rpix[d][img[2]] | visual->gpix[d][img[1]] | visual->bpix[d][img[0]];
992         pix[0]=(FXuchar)val;
993         pix[1]=(FXuchar)(val>>8);
994         img+=4;
995         pix+=2;
996         }
997       while(--w>=0);
998       pix+=jmp;
999       }
1000     while(--h>=0);
1001     }
1002   }
1003 
1004 
1005 // True 8 bit color
render_true_8_fast(void * xim,FXuchar * img)1006 void FXImage::render_true_8_fast(void *xim,FXuchar *img){
1007   FXuint jmp=((XImage*)xim)->bytes_per_line-width;
1008   FXuchar *pix=(FXuchar*)((XImage*)xim)->data;
1009   FXint w,h;
1010   FXTRACE((150,"True MSB/LSB 8bpp render nearest\n"));
1011   h=height-1;
1012   do{
1013     w=width-1;
1014     do{
1015       *pix=visual->rpix[1][img[2]] | visual->gpix[1][img[1]] | visual->bpix[1][img[0]];
1016       img+=4;
1017       pix++;
1018       }
1019     while(--w>=0);
1020     pix+=jmp;
1021     }
1022   while(--h>=0);
1023   }
1024 
1025 
1026 // True 8 bit color, dithered
render_true_8_dither(void * xim,FXuchar * img)1027 void FXImage::render_true_8_dither(void *xim,FXuchar *img){
1028   FXuint jmp=((XImage*)xim)->bytes_per_line-width;
1029   FXuchar *pix=(FXuchar*)((XImage*)xim)->data;
1030   FXint w,h,d;
1031   FXTRACE((150,"True MSB/LSB 8bpp render dither\n"));
1032   h=height-1;
1033   do{
1034     w=width-1;
1035     do{
1036       d=((h&3)<<2)|(w&3);
1037       *pix=visual->rpix[d][img[2]] | visual->gpix[d][img[1]] | visual->bpix[d][img[0]];
1038       img+=4;
1039       pix++;
1040       }
1041     while(--w>=0);
1042     pix+=jmp;
1043     }
1044   while(--h>=0);
1045   }
1046 
1047 
1048 // Render 4 bit index color mode
render_index_4_fast(void * xim,FXuchar * img)1049 void FXImage::render_index_4_fast(void *xim,FXuchar *img){
1050   FXuchar *pix=(FXuchar*)((XImage*)xim)->data;
1051   FXuint jmp=((XImage*)xim)->bytes_per_line-width;
1052   FXuint val,half;
1053   FXint w,h;
1054   if(((XImage*)xim)->byte_order==MSBFirst){    // MSB
1055     FXTRACE((150,"Index MSB 4bpp render nearest\n"));
1056     h=height-1;
1057     do{
1058       w=width-1;
1059       half=0;
1060       do{
1061         val=visual->lut[visual->rpix[1][img[2]]+visual->gpix[1][img[1]]+visual->bpix[1][img[0]]];
1062         if(half) *pix++|=val;
1063         else *pix=val<<4;
1064         half^=1;
1065         img+=4;
1066         }
1067       while(--w>=0);
1068       pix+=jmp;
1069       }
1070     while(--h>=0);
1071     }
1072   else{                               // LSB
1073     FXTRACE((150,"Index LSB 4bpp render nearest\n"));
1074     h=height-1;
1075     do{
1076       w=width-1;
1077       half=0;
1078       do{
1079         val=visual->lut[visual->rpix[1][img[2]]+visual->gpix[1][img[1]]+visual->bpix[1][img[0]]];
1080         if(half) *pix++|=val<<4;
1081         else *pix=val;
1082         half^=1;
1083         img+=4;
1084         }
1085       while(--w>=0);
1086       pix+=jmp;
1087       }
1088     while(--h>=0);
1089     }
1090   }
1091 
1092 
1093 // Render 4 bit index color mode
render_index_4_dither(void * xim,FXuchar * img)1094 void FXImage::render_index_4_dither(void *xim,FXuchar *img){
1095   FXuchar *pix=(FXuchar*)((XImage*)xim)->data;
1096   FXuint jmp=((XImage*)xim)->bytes_per_line-width;
1097   FXuint val,half,d;
1098   FXint w,h;
1099   if(((XImage*)xim)->byte_order==MSBFirst){    // MSB
1100     FXTRACE((150,"Index MSB 4bpp render dither\n"));
1101     h=height-1;
1102     do{
1103       w=width-1;
1104       half=0;
1105       do{
1106         d=((h&3)<<2)|(w&3);
1107         val=visual->lut[visual->rpix[d][img[2]]+visual->gpix[d][img[1]]+visual->bpix[d][img[0]]];
1108         if(half) *pix++|=val;
1109         else *pix=val<<4;
1110         half^=1;
1111         img+=4;
1112         }
1113       while(--w>=0);
1114       pix+=jmp;
1115       }
1116     while(--h>=0);
1117     }
1118   else{                               // LSB
1119     FXTRACE((150,"Index LSB 4bpp render dither\n"));
1120     h=height-1;
1121     do{
1122       w=width-1;
1123       half=0;
1124       do{
1125         d=((h&3)<<2)|(w&3);
1126         val=visual->lut[visual->rpix[d][img[2]]+visual->gpix[d][img[1]]+visual->bpix[d][img[0]]];
1127         if(half) *pix++|=val<<4;
1128         else *pix=val;
1129         half^=1;
1130         img+=4;
1131         }
1132       while(--w>=0);
1133       pix+=jmp;
1134       }
1135     while(--h>=0);
1136     }
1137   }
1138 
1139 
1140 // Render 8 bit index color mode
render_index_8_fast(void * xim,FXuchar * img)1141 void FXImage::render_index_8_fast(void *xim,FXuchar *img){
1142   FXuint jmp=((XImage*)xim)->bytes_per_line-width;
1143   FXuchar *pix=(FXuchar*)((XImage*)xim)->data;
1144   FXint w,h;
1145   FXTRACE((150,"Index MSB/LSB 8bpp render nearest\n"));
1146   h=height-1;
1147   do{
1148     w=width-1;
1149     do{
1150       *pix=visual->lut[visual->rpix[1][img[2]]+visual->gpix[1][img[1]]+visual->bpix[1][img[0]]];
1151       img+=4;
1152       pix++;
1153       }
1154     while(--w>=0);
1155     pix+=jmp;
1156     }
1157   while(--h>=0);
1158   }
1159 
1160 
1161 // Render 8 bit index color mode
render_index_8_dither(void * xim,FXuchar * img)1162 void FXImage::render_index_8_dither(void *xim,FXuchar *img){
1163   FXuint jmp=((XImage*)xim)->bytes_per_line-width;
1164   FXuchar *pix=(FXuchar*)((XImage*)xim)->data;
1165   FXint w,h,d;
1166   FXTRACE((150,"Index MSB/LSB 8bpp render dither\n"));
1167   h=height-1;
1168   do{
1169     w=width-1;
1170     do{
1171       d=((h&3)<<2)|(w&3);
1172       *pix=visual->lut[visual->rpix[d][img[2]]+visual->gpix[d][img[1]]+visual->bpix[d][img[0]]];
1173       img+=4;
1174       pix++;
1175       }
1176     while(--w>=0);
1177     pix+=jmp;
1178     }
1179   while(--h>=0);
1180   }
1181 
1182 
1183 // Render generic N bit index color mode
render_index_N_fast(void * xim,FXuchar * img)1184 void FXImage::render_index_N_fast(void *xim,FXuchar *img){
1185   FXint x,y;
1186   FXTRACE((150,"Index MSB/LSB N bpp render nearest\n"));
1187   y=0;
1188   do{
1189     x=0;
1190     do{
1191       XPutPixel(((XImage*)xim),x,y,visual->lut[visual->rpix[1][img[2]]+visual->gpix[1][img[1]]+visual->bpix[1][img[0]]]);
1192       img+=4;
1193       }
1194     while(++x<width);
1195     }
1196   while(++y<height);
1197   }
1198 
1199 
1200 // Render generic N bit index color mode
render_index_N_dither(void * xim,FXuchar * img)1201 void FXImage::render_index_N_dither(void *xim,FXuchar *img){
1202   FXint x,y,d;
1203   FXTRACE((150,"Index MSB/LSB N bpp render dither\n"));
1204   y=0;
1205   do{
1206     x=0;
1207     do{
1208       d=((y&3)<<2)|(x&3);
1209       XPutPixel(((XImage*)xim),x,y,visual->lut[visual->rpix[d][img[2]]+visual->gpix[d][img[1]]+visual->bpix[d][img[0]]]);
1210       img+=4;
1211       }
1212     while(++x<width);
1213     }
1214   while(++y<height);
1215   }
1216 
1217 
1218 // Render 8 bit gray mode
render_gray_8_fast(void * xim,FXuchar * img)1219 void FXImage::render_gray_8_fast(void *xim,FXuchar *img){
1220   FXuchar *pix=(FXuchar*)((XImage*)xim)->data;
1221   FXuint jmp=((XImage*)xim)->bytes_per_line-width;
1222   FXint w,h;
1223   FXTRACE((150,"Gray MSB/LSB 8bpp render nearest\n"));
1224   h=height-1;
1225   do{
1226     w=width-1;
1227     do{
1228       *pix=visual->gpix[1][(77*img[2]+151*img[1]+29*img[0])>>8];
1229       img+=4;
1230       pix++;
1231       }
1232     while(--w>=0);
1233     pix+=jmp;
1234     }
1235   while(--h>=0);
1236   }
1237 
1238 
1239 // Render 8 bit gray mode
render_gray_8_dither(void * xim,FXuchar * img)1240 void FXImage::render_gray_8_dither(void *xim,FXuchar *img){
1241   FXuchar *pix=(FXuchar*)((XImage*)xim)->data;
1242   FXuint jmp=((XImage*)xim)->bytes_per_line-width;
1243   FXint w,h;
1244   FXTRACE((150,"Gray MSB/LSB 8bpp render dither\n"));
1245   h=height-1;
1246   do{
1247     w=width-1;
1248     do{
1249       *pix=visual->gpix[((h&3)<<2)|(w&3)][(77*img[2]+151*img[1]+29*img[0])>>8];
1250       img+=4;
1251       pix++;
1252       }
1253     while(--w>=0);
1254     pix+=jmp;
1255     }
1256   while(--h>=0);
1257   }
1258 
1259 
1260 // Render generic N bit gray mode
render_gray_N_fast(void * xim,FXuchar * img)1261 void FXImage::render_gray_N_fast(void *xim,FXuchar *img){
1262   FXint x,y;
1263   FXTRACE((150,"Gray MSB/LSB N bpp render nearest\n"));
1264   y=0;
1265   do{
1266     x=0;
1267     do{
1268       XPutPixel(((XImage*)xim),x,y,visual->gpix[1][(77*img[2]+151*img[1]+29*img[0])>>8]);
1269       img+=4;
1270       }
1271     while(++x<width);
1272     }
1273   while(++y<height);
1274   }
1275 
1276 
1277 // Render generic N bit gray mode
render_gray_N_dither(void * xim,FXuchar * img)1278 void FXImage::render_gray_N_dither(void *xim,FXuchar *img){
1279   FXint x,y;
1280   FXTRACE((150,"Gray MSB/LSB N bpp render dither\n"));
1281   y=0;
1282   do{
1283     x=0;
1284     do{
1285       XPutPixel(((XImage*)xim),x,y,visual->gpix[((y&3)<<2)|(x&3)][(77*img[2]+151*img[1]+29*img[0])>>8]);
1286       img+=4;
1287       }
1288     while(++x<width);
1289     }
1290   while(++y<height);
1291   }
1292 
1293 
1294 // Render monochrome mode
render_mono_1_fast(void * xim,FXuchar * img)1295 void FXImage::render_mono_1_fast(void *xim,FXuchar *img){
1296   FXint x,y;
1297   FXTRACE((150,"Monochrome MSB/LSB 1bpp render nearest\n"));
1298   y=0;
1299   do{
1300     x=0;
1301     do{
1302       XPutPixel(((XImage*)xim),x,y,visual->gpix[1][(77*img[2]+151*img[1]+29*img[0])>>8]);
1303       img+=4;
1304       }
1305     while(++x<width);
1306     }
1307   while(++y<height);
1308   }
1309 
1310 
1311 // Render monochrome mode
render_mono_1_dither(void * xim,FXuchar * img)1312 void FXImage::render_mono_1_dither(void *xim,FXuchar *img){
1313   FXint x,y;
1314   FXTRACE((150,"Monochrome MSB/LSB 1bpp render dither\n"));
1315   y=0;
1316   do{
1317     x=0;
1318     do{
1319       XPutPixel(((XImage*)xim),x,y,visual->gpix[((y&3)<<2)|(x&3)][(77*img[2]+151*img[1]+29*img[0])>>8]);
1320       img+=4;
1321       }
1322     while(++x<width);
1323     }
1324   while(++y<height);
1325   }
1326 
1327 
1328 // Render into pixmap
render()1329 void FXImage::render(){
1330   if(xid){
1331     FXbool shmi=false;
1332     XImage *xim=NULL;
1333     XGCValues values;
1334     GC gc;
1335 #ifdef HAVE_XSHM_H
1336     XShmSegmentInfo shminfo;
1337 #endif
1338 
1339     FXTRACE((100,"%s::render image %p\n",getClassName(),this));
1340 
1341     // Fill with pixels if there is data
1342     if(data && 0<width && 0<height){
1343 
1344       // Make GC
1345       values.foreground=BlackPixel(DISPLAY(getApp()),DefaultScreen(DISPLAY(getApp())));
1346       values.background=WhitePixel(DISPLAY(getApp()),DefaultScreen(DISPLAY(getApp())));
1347       gc=XCreateGC(DISPLAY(getApp()),xid,GCForeground|GCBackground,&values);
1348 
1349       // Turn it on iff both supported and desired
1350 #ifdef HAVE_XSHM_H
1351       if(options&IMAGE_SHMI) shmi=getApp()->shmi;
1352 #endif
1353 
1354       // First try XShm
1355 #ifdef HAVE_XSHM_H
1356       if(shmi){
1357         xim=XShmCreateImage(DISPLAY(getApp()),(Visual*)visual->visual,visual->depth,(visual->depth==1)?XYPixmap:ZPixmap,NULL,&shminfo,width,height);
1358         if(!xim){ shmi=0; }
1359         if(shmi){
1360           shminfo.shmid=shmget(IPC_PRIVATE,xim->bytes_per_line*xim->height,IPC_CREAT|0777);
1361           if(shminfo.shmid==-1){ xim->data=NULL; XDestroyImage(xim); xim=NULL; shmi=0; }
1362           if(shmi){
1363             shminfo.shmaddr=xim->data=(char*)shmat(shminfo.shmid,0,0);
1364             shminfo.readOnly=false;
1365             XShmAttach(DISPLAY(getApp()),&shminfo);
1366             FXTRACE((150,"RGBPixmap XSHM attached at memory=%p (%d bytes)\n",xim->data,xim->bytes_per_line*xim->height));
1367             }
1368           }
1369         }
1370 #endif
1371 
1372       // Try the old fashioned way
1373       if(!shmi){
1374         xim=XCreateImage(DISPLAY(getApp()),(Visual*)visual->visual,visual->depth,(visual->depth==1)?XYPixmap:ZPixmap,0,NULL,width,height,32,0);
1375         if(!xim){ throw FXImageException("unable to render image"); }
1376 
1377         // Try create temp pixel store
1378         if(!allocElms(xim->data,xim->bytes_per_line*height)){ throw FXMemoryException("unable to render image"); }
1379         }
1380 
1381       // Should have succeeded
1382       FXASSERT(xim);
1383 
1384       FXTRACE((150,"im width = %d\n",xim->width));
1385       FXTRACE((150,"im height = %d\n",xim->height));
1386       FXTRACE((150,"im format = %s\n",xim->format==XYBitmap?"XYBitmap":xim->format==XYPixmap?"XYPixmap":"ZPixmap"));
1387       FXTRACE((150,"im byte_order = %s\n",(xim->byte_order==MSBFirst)?"MSBFirst":"LSBFirst"));
1388       FXTRACE((150,"im bitmap_unit = %d\n",xim->bitmap_unit));
1389       FXTRACE((150,"im bitmap_bit_order = %s\n",(xim->bitmap_bit_order==MSBFirst)?"MSBFirst":"LSBFirst"));
1390       FXTRACE((150,"im bitmap_pad = %d\n",xim->bitmap_pad));
1391       FXTRACE((150,"im bitmap_unit = %d\n",xim->bitmap_unit));
1392       FXTRACE((150,"im depth = %d\n",xim->depth));
1393       FXTRACE((150,"im bytes_per_line = %d\n",xim->bytes_per_line));
1394       FXTRACE((150,"im bits_per_pixel = %d\n",xim->bits_per_pixel));
1395 
1396       // Determine what to do
1397       switch(visual->getType()){
1398         case FXVisual::Color:
1399           switch(xim->bits_per_pixel){
1400             case 32:
1401               render_true_32(xim,(FXuchar*)data);
1402               break;
1403             case 24:
1404               render_true_24(xim,(FXuchar*)data);
1405               break;
1406             case 15:
1407             case 16:
1408               if(options&IMAGE_NEAREST)
1409                 render_true_16_fast(xim,(FXuchar*)data);
1410               else
1411                 render_true_16_dither(xim,(FXuchar*)data);
1412               break;
1413             case 8:
1414               if(options&IMAGE_NEAREST)
1415                 render_true_8_fast(xim,(FXuchar*)data);
1416               else
1417                 render_true_8_dither(xim,(FXuchar*)data);
1418               break;
1419             default:
1420               if(options&IMAGE_NEAREST)
1421                 render_true_N_fast(xim,(FXuchar*)data);
1422               else
1423                 render_true_N_dither(xim,(FXuchar*)data);
1424               break;
1425             }
1426           break;
1427         case FXVisual::Gray:
1428           switch(xim->bits_per_pixel){
1429             case 1:
1430               if(options&IMAGE_NEAREST)
1431                 render_mono_1_fast(xim,(FXuchar*)data);
1432               else
1433                 render_mono_1_dither(xim,(FXuchar*)data);
1434               break;
1435             case 8:
1436               if(options&IMAGE_NEAREST)
1437                 render_gray_8_fast(xim,(FXuchar*)data);
1438               else
1439                 render_gray_8_dither(xim,(FXuchar*)data);
1440               break;
1441             default:
1442               if(options&IMAGE_NEAREST)
1443                 render_gray_N_fast(xim,(FXuchar*)data);
1444               else
1445                 render_gray_N_dither(xim,(FXuchar*)data);
1446               break;
1447             }
1448           break;
1449         case FXVisual::Index:
1450           switch(xim->bits_per_pixel){
1451             case 4:
1452               if(options&IMAGE_NEAREST)
1453                 render_index_4_fast(xim,(FXuchar*)data);
1454               else
1455                 render_index_4_dither(xim,(FXuchar*)data);
1456               break;
1457             case 8:
1458               if(options&IMAGE_NEAREST)
1459                 render_index_8_fast(xim,(FXuchar*)data);
1460               else
1461                 render_index_8_dither(xim,(FXuchar*)data);
1462               break;
1463             default:
1464               if(options&IMAGE_NEAREST)
1465                 render_index_N_fast(xim,(FXuchar*)data);
1466               else
1467                 render_index_N_dither(xim,(FXuchar*)data);
1468               break;
1469             }
1470           break;
1471         case FXVisual::Mono:
1472           if(options&IMAGE_NEAREST)
1473             render_mono_1_fast(xim,(FXuchar*)data);
1474           else
1475             render_mono_1_dither(xim,(FXuchar*)data);
1476         }
1477 
1478       // Transfer image with shared memory
1479 #ifdef HAVE_XSHM_H
1480       if(shmi){
1481         XShmPutImage(DISPLAY(getApp()),xid,gc,xim,0,0,0,0,width,height,False);
1482         XSync(DISPLAY(getApp()),False);
1483         FXTRACE((150,"RGBPixmap XSHM detached at memory=%p (%d bytes)\n",xim->data,xim->bytes_per_line*xim->height));
1484         XShmDetach(DISPLAY(getApp()),&shminfo);
1485         xim->data=NULL;
1486         XDestroyImage(xim);
1487         shmdt(shminfo.shmaddr);
1488         shmctl(shminfo.shmid,IPC_RMID,0);
1489         }
1490 #endif
1491 
1492       // Transfer the image old way
1493       if(!shmi){
1494         XPutImage(DISPLAY(getApp()),xid,gc,xim,0,0,0,0,width,height);
1495         freeElms(xim->data);
1496         XDestroyImage(xim);
1497         }
1498       XFreeGC(DISPLAY(getApp()),gc);
1499       }
1500     }
1501   }
1502 
1503 #endif
1504 
1505 
1506 // Release the client-side buffer, free it if it was owned.
release()1507 void FXImage::release(){
1508   if(options&IMAGE_OWNED){
1509     options&=~IMAGE_OWNED;
1510     freeElms(data);
1511     }
1512   data=NULL;
1513   }
1514 
1515 
1516 // Resize pixmap to the specified width and height; the data
1517 // array is resized also, but its contents will be undefined.
resize(FXint w,FXint h)1518 void FXImage::resize(FXint w,FXint h){
1519   if(w<1) w=1;
1520   if(h<1) h=1;
1521   FXTRACE((100,"%s::resize(%d,%d)\n",getClassName(),w,h));
1522   if(width!=w || height!=h){
1523 
1524     // Resize device dependent pixmap
1525     if(xid){
1526 #ifdef WIN32
1527       DeleteObject(xid);
1528       HDC hdc=::GetDC(GetDesktopWindow());
1529       xid=CreateCompatibleBitmap(hdc,w,h);
1530       ::ReleaseDC(GetDesktopWindow(),hdc);
1531       if(!xid){ throw FXImageException("unable to resize image"); }
1532 #else
1533       int dd=visual->getDepth();
1534       XFreePixmap(DISPLAY(getApp()),xid);
1535       xid=XCreatePixmap(DISPLAY(getApp()),XDefaultRootWindow(DISPLAY(getApp())),w,h,dd);
1536       if(!xid){ throw FXImageException("unable to resize image"); }
1537 #endif
1538       }
1539     }
1540 
1541   // Resize data array
1542   if(data){
1543     if(!(options&IMAGE_OWNED)){         // Need to own array
1544       if(!allocElms(data,w*h)){ throw FXMemoryException("unable to resize image"); }
1545       options|=IMAGE_OWNED;
1546       }
1547     else if(w*h!=width*height){
1548       if(!resizeElms(data,w*h)){ throw FXMemoryException("unable to resize image"); }
1549       }
1550     }
1551 
1552   // Remember new size
1553   width=w;
1554   height=h;
1555   }
1556 
1557 
1558 // Gamma-corrected image scaling.
1559 // In a nutshell: convert pixel value to intensities, scale, then convert
1560 // them back to pixel value:
1561 //
1562 //      I = pow(P,2.2)
1563 //      P = pow(I,1/2.2)
1564 //
1565 // Reference: http://www.ericbrasseur.org/gamma.html
1566 // At some future time this should be based around the gamma used in
1567 // FXVisual; this means generating the table at run time.
1568 
1569 // Table lookup: y=pow(x,2.2)
1570 static const FXuint gammatable[256]={
1571        0,     1,     4,    11,    21,    34,    51,    72,
1572       97,   125,   158,   195,   236,   282,   332,   386,
1573      445,   509,   577,   650,   728,   810,   898,   990,
1574     1087,  1189,  1297,  1409,  1526,  1649,  1776,  1909,
1575     2048,  2191,  2340,  2494,  2653,  2818,  2988,  3164,
1576     3346,  3532,  3725,  3923,  4126,  4335,  4550,  4771,
1577     4997,  5229,  5466,  5710,  5959,  6214,  6475,  6742,
1578     7014,  7293,  7577,  7868,  8164,  8466,  8775,  9089,
1579     9410,  9736, 10069, 10407, 10752, 11103, 11460, 11824,
1580    12193, 12569, 12951, 13339, 13733, 14134, 14541, 14954,
1581    15374, 15800, 16232, 16671, 17116, 17567, 18025, 18490,
1582    18961, 19438, 19922, 20412, 20908, 21412, 21922, 22438,
1583    22961, 23490, 24026, 24569, 25118, 25674, 26237, 26806,
1584    27382, 27965, 28554, 29150, 29753, 30362, 30978, 31601,
1585    32231, 32867, 33511, 34161, 34818, 35482, 36152, 36830,
1586    37514, 38205, 38903, 39608, 40320, 41039, 41765, 42497,
1587    43237, 43984, 44737, 45498, 46266, 47040, 47822, 48610,
1588    49406, 50209, 51019, 51836, 52660, 53491, 54329, 55174,
1589    56027, 56886, 57753, 58627, 59508, 60396, 61291, 62194,
1590    63103, 64020, 64944, 65876, 66815, 67760, 68714, 69674,
1591    70642, 71617, 72599, 73588, 74585, 75590, 76601, 77620,
1592    78646, 79680, 80721, 81769, 82825, 83888, 84958, 86036,
1593    87122, 88214, 89314, 90422, 91537, 92660, 93790, 94927,
1594    96072, 97224, 98384, 99552,100727,101909,103099,104297,
1595   105502,106715,107935,109163,110398,111641,112892,114150,
1596   115415,116689,117970,119259,120555,121859,123170,124490,
1597   125817,127151,128493,129843,131201,132566,133940,135320,
1598   136709,138105,139509,140921,142340,143768,145203,146646,
1599   148096,149555,151021,152495,153977,155466,156964,158469,
1600   159982,161503,163032,164569,166114,167666,169226,170795,
1601   172371,173955,175547,177147,178754,180370,181994,183625,
1602   185265,186912,188568,190231,191902,193582,195269,196964
1603   };
1604 
1605 
gammaLookup(FXuint i)1606 static FXuint gammaLookup(FXuint i){
1607   return gammatable[i];
1608   }
1609 
1610 
1611 #if 0
1612 static FXuint gammaInvertLookup(FXuint val){    // New
1613   FXint m,l=0,h=255;
1614   while(l<(m=(h+l)>>1)){
1615     if(gammatable[m]<=val) l=m; else h=m;
1616     }
1617   return l;
1618   }
1619 #endif
1620 
gammaInvertLookup(FXuint val)1621 static FXuint gammaInvertLookup(FXuint val){
1622   FXint mid,low=0,high=255;
1623   while((high-low)>1){
1624     mid=low+(high-low)/2;
1625     if(val<gammatable[mid])
1626       high=mid;
1627     else
1628       low=mid;
1629     }
1630   return (gammatable[high]==val) ? high : low;
1631   }
1632 
1633 
1634 // Horizontal box-filtered, gamma-corrected
hscalergbagamma(FXuchar * dst,const FXuchar * src,FXint dw,FXint dh,FXint sw,FXint)1635 static void hscalergbagamma(FXuchar *dst,const FXuchar* src,FXint dw,FXint dh,FXint sw,FXint ){
1636   FXint fin,fout,ar,ag,ab,aa;
1637   FXint ss=4*sw;
1638   FXint ds=4*dw;
1639   FXuchar *end=dst+ds*dh;
1640   FXuchar *d;
1641   const FXuchar *s;
1642   do{
1643     s=src; src+=ss;
1644     d=dst; dst+=ds;
1645     fin=dw;
1646     fout=sw;
1647     ar=ag=ab=aa=0;
1648     while(1){
1649       if(fin<fout){
1650         aa+=fin*s[3];
1651         ar+=fin*gammaLookup(s[2]);
1652         ag+=fin*gammaLookup(s[1]);
1653         ab+=fin*gammaLookup(s[0]);
1654         fout-=fin;
1655         fin=dw;
1656         s+=4;
1657         }
1658       else{
1659         aa+=fout*s[3];              d[3]=aa/sw;
1660         ar+=fout*gammaLookup(s[2]); d[2]=gammaInvertLookup(ar/sw);
1661         ag+=fout*gammaLookup(s[1]); d[1]=gammaInvertLookup(ag/sw);
1662         ab+=fout*gammaLookup(s[0]); d[0]=gammaInvertLookup(ab/sw);
1663         ar=ag=ab=aa=0;
1664         fin-=fout;
1665         fout=sw;
1666         d+=4;
1667         if(d>=dst) break;
1668         }
1669       }
1670     }
1671   while(dst<end);
1672   }
1673 
1674 
1675 // Vertical box-filtered, gamma-corrected
vscalergbagamma(FXuchar * dst,const FXuchar * src,FXint dw,FXint dh,FXint sw,FXint sh)1676 static void vscalergbagamma(FXuchar *dst,const FXuchar* src,FXint dw,FXint dh,FXint sw,FXint sh){
1677   FXint fin,fout,ar,ag,ab,aa;
1678   FXint ss=4*sw;
1679   FXint ds=4*dw;
1680   FXint dss=ds*dh;
1681   FXuchar *end=dst+ds;
1682   FXuchar *d,*dd;
1683   const FXuchar *s;
1684   do{
1685     s=src; src+=4;
1686     d=dst; dst+=4;
1687     dd=d+dss;
1688     fin=dh;
1689     fout=sh;
1690     ar=ag=ab=aa=0;
1691     while(1){
1692       if(fin<fout){
1693         aa+=fin*s[3];
1694         ar+=fin*gammaLookup(s[2]);
1695         ag+=fin*gammaLookup(s[1]);
1696         ab+=fin*gammaLookup(s[0]);
1697         fout-=fin;
1698         fin=dh;
1699         s+=ss;
1700         }
1701       else{
1702         aa+=fout*s[3];              d[3]=aa/sh;
1703         ar+=fout*gammaLookup(s[2]); d[2]=gammaInvertLookup(ar/sh);
1704         ag+=fout*gammaLookup(s[1]); d[1]=gammaInvertLookup(ag/sh);
1705         ab+=fout*gammaLookup(s[0]); d[0]=gammaInvertLookup(ab/sh);
1706         ar=ag=ab=aa=0;
1707         fin-=fout;
1708         fout=sh;
1709         d+=ds;
1710         if(d>=dd) break;
1711         }
1712       }
1713     }
1714   while(dst<end);
1715   }
1716 
1717 
1718 // Horizontal box-filtered
hscalergba(FXuchar * dst,const FXuchar * src,FXint dw,FXint dh,FXint sw,FXint)1719 static void hscalergba(FXuchar *dst,const FXuchar* src,FXint dw,FXint dh,FXint sw,FXint ){
1720   FXint fin,fout,ar,ag,ab,aa;
1721   FXint ss=4*sw;
1722   FXint ds=4*dw;
1723   FXuchar *end=dst+ds*dh;
1724   FXuchar *d;
1725   const FXuchar *s;
1726   do{
1727     s=src; src+=ss;
1728     d=dst; dst+=ds;
1729     fin=dw;
1730     fout=sw;
1731     ar=ag=ab=aa=0;
1732     while(1){
1733       if(fin<fout){
1734         aa+=fin*s[3];
1735         ar+=fin*s[2];
1736         ag+=fin*s[1];
1737         ab+=fin*s[0];
1738         fout-=fin;
1739         fin=dw;
1740         s+=4;
1741         }
1742       else{
1743         aa+=fout*s[3]; d[3]=aa/sw; aa=0;
1744         ar+=fout*s[2]; d[2]=ar/sw; ar=0;
1745         ag+=fout*s[1]; d[1]=ag/sw; ag=0;
1746         ab+=fout*s[0]; d[0]=ab/sw; ab=0;
1747         fin-=fout;
1748         fout=sw;
1749         d+=4;
1750         if(d>=dst) break;
1751         }
1752       }
1753     }
1754   while(dst<end);
1755   }
1756 
1757 
1758 // Vertical box-filtered
vscalergba(FXuchar * dst,const FXuchar * src,FXint dw,FXint dh,FXint sw,FXint sh)1759 static void vscalergba(FXuchar *dst,const FXuchar* src,FXint dw,FXint dh,FXint sw,FXint sh){
1760   FXint fin,fout,ar,ag,ab,aa;
1761   FXint ss=4*sw;
1762   FXint ds=4*dw;
1763   FXint dss=ds*dh;
1764   FXuchar *end=dst+ds;
1765   FXuchar *d,*dd;
1766   const FXuchar *s;
1767   do{
1768     s=src; src+=4;
1769     d=dst; dst+=4;
1770     dd=d+dss;
1771     fin=dh;
1772     fout=sh;
1773     ar=ag=ab=aa=0;
1774     while(1){
1775       if(fin<fout){
1776         aa+=fin*s[3];
1777         ar+=fin*s[2];
1778         ag+=fin*s[1];
1779         ab+=fin*s[0];
1780         fout-=fin;
1781         fin=dh;
1782         s+=ss;
1783         }
1784       else{
1785         aa+=fout*s[3]; d[3]=aa/sh; aa=0;
1786         ar+=fout*s[2]; d[2]=ar/sh; ar=0;
1787         ag+=fout*s[1]; d[1]=ag/sh; ag=0;
1788         ab+=fout*s[0]; d[0]=ab/sh; ab=0;
1789         fin-=fout;
1790         fout=sh;
1791         d+=ds;
1792         if(d>=dd) break;
1793         }
1794       }
1795     }
1796   while(dst<end);
1797   }
1798 
1799 
1800 // Simple nearest neighbor scaling; fast but ugly
scalenearest(FXColor * dst,const FXColor * src,FXint dw,FXint dh,FXint sw,FXint sh)1801 static void scalenearest(FXColor *dst,const FXColor* src,FXint dw,FXint dh,FXint sw,FXint sh){
1802   FXint xs=(sw<<16)/dw;
1803   FXint ys=(sh<<16)/dh;
1804   FXint i,j,x,y;
1805   const FXColor *q;
1806   FXColor *p;
1807   i=0;
1808   y=ys>>1;
1809   p=dst;
1810   do{
1811     j=0;
1812     x=xs>>1;
1813     q=src+(y>>16)*sw;
1814     do{
1815       p[j]=q[x>>16];
1816       x+=xs;
1817       }
1818     while(++j<dw);
1819     p+=dw;
1820     y+=ys;
1821     }
1822   while(++i<dh);
1823   }
1824 
1825 
1826 // Resize drawable to the specified width and height
scale(FXint w,FXint h,FXint quality)1827 void FXImage::scale(FXint w,FXint h,FXint quality){
1828   if(w<1) w=1;
1829   if(h<1) h=1;
1830   FXTRACE((100,"%s::scale(%d,%d)\n",getClassName(),w,h));
1831   if(w!=width || h!=height){
1832     if(data){
1833       FXint ow=width;
1834       FXint oh=height;
1835       FXColor *interim;
1836 
1837       switch(quality){
1838         case 0:         // Fast but ugly scale
1839 
1840           // Copy to old buffer
1841           if(!dupElms(interim,data,ow*oh)){ throw FXMemoryException("unable to scale image"); }
1842 
1843           // Resize the pixmap and target buffer
1844           resize(w,h);
1845 
1846           // Fast nearest neighbor scale
1847           scalenearest(data,interim,w,h,ow,oh);
1848 
1849           // Free old buffer
1850           freeElms(interim);
1851           break;
1852         case 1:         // Slower box filtered scale
1853 
1854           // Allocate interim buffer
1855           if(!allocElms(interim,w*oh)){ throw FXMemoryException("unable to scale image"); }
1856 
1857           // Scale horizontally first, placing result into interim buffer
1858           if(w==ow){
1859             memcpy((FXuchar*)interim,(FXuchar*)data,w*oh*4);
1860             }
1861           else{
1862             hscalergba((FXuchar*)interim,(FXuchar*)data,w,oh,ow,oh);
1863             }
1864 
1865           // Resize the pixmap and target buffer
1866           resize(w,h);
1867 
1868           // Scale vertically from the interim buffer into target buffer
1869           if(h==oh){
1870             memcpy((FXuchar*)data,(FXuchar*)interim,w*h*4);
1871             }
1872           else{
1873             vscalergba((FXuchar*)data,(FXuchar*)interim,w,h,w,oh);
1874             }
1875 
1876           // Free interim buffer
1877           freeElms(interim);
1878           break;
1879         case 2:         // Slow gamma corrected scale
1880         default:
1881 
1882           // Allocate interim buffer
1883           if(!allocElms(interim,w*oh)){ throw FXMemoryException("unable to scale image"); }
1884 
1885           // Scale horizontally first, placing result into interim buffer
1886           if(w==ow){
1887             memcpy((FXuchar*)interim,(FXuchar*)data,w*oh*4);
1888             }
1889           else{
1890             hscalergbagamma((FXuchar*)interim,(FXuchar*)data,w,oh,ow,oh);
1891             }
1892 
1893           // Resize the pixmap and target buffer
1894           resize(w,h);
1895 
1896           // Scale vertically from the interim buffer into target buffer
1897           if(h==oh){
1898             memcpy((FXuchar*)data,(FXuchar*)interim,w*h*4);
1899             }
1900           else{
1901             vscalergbagamma((FXuchar*)data,(FXuchar*)interim,w,h,w,oh);
1902             }
1903 
1904           // Free interim buffer
1905           freeElms(interim);
1906           break;
1907         }
1908       render();
1909       }
1910     else{
1911       resize(w,h);
1912       }
1913     }
1914   }
1915 
1916 
1917 // Mirror image horizontally and/or vertically
mirror(FXbool horizontal,FXbool vertical)1918 void FXImage::mirror(FXbool horizontal,FXbool vertical){
1919   FXTRACE((100,"%s::mirror(%d,%d)\n",getClassName(),horizontal,vertical));
1920   if(horizontal || vertical){
1921     if(data){
1922       FXColor *paa,*pa,*pbb,*pb,t;
1923       if(vertical && height>1){     // Mirror vertically
1924         paa=data;
1925         pbb=data+width*(height-1);
1926         do{
1927           pa=paa; paa+=width;
1928           pb=pbb; pbb-=width;
1929           do{
1930             t=*pa; *pa++=*pb; *pb++=t;
1931             }
1932           while(pa<paa);
1933           }
1934         while(paa<pbb);
1935         }
1936       if(horizontal && width>1){    // Mirror horizontally
1937         paa=data;
1938         pbb=data+width*height;
1939         do{
1940           pa=paa; paa+=width;
1941           pb=paa;
1942           do{
1943             t=*--pb; *pb=*pa; *pa++=t;
1944             }
1945           while(pa<pb);
1946           }
1947         while(paa<pbb);
1948         }
1949       render();
1950       }
1951     }
1952   }
1953 
1954 
1955 // Rotate image by degrees ccw
rotate(FXint degrees)1956 void FXImage::rotate(FXint degrees){
1957   FXTRACE((100,"%s::rotate(%d)\n",getClassName(),degrees));
1958   degrees=(degrees+360)%360;
1959   if(degrees!=0 && width>1 && height>1){
1960     if(data){
1961       FXColor *paa,*pbb,*end,*pa,*pb;
1962       FXint size=width*height;
1963       FXColor *olddata;
1964       if(!dupElms(olddata,data,size)){ throw FXMemoryException("unable to rotate image"); }
1965       switch(degrees){
1966         case 90:
1967           resize(height,width);
1968           paa=data;
1969           pbb=olddata+(height-1);
1970           end=data+size;
1971           do{
1972             pa=paa; paa+=width;
1973             pb=pbb; pbb-=1;
1974             do{
1975               *pa=*pb;
1976               pa+=1;
1977               pb+=height;
1978               }
1979             while(pa<paa);
1980             }
1981           while(paa<end);
1982           break;
1983         case 180:
1984           paa=data;
1985           pbb=olddata+size;
1986           end=data+size;
1987           do{
1988             pa=paa; paa+=width;
1989             pb=pbb; pbb-=width;
1990             do{
1991               pb-=1;
1992               *pa=*pb;
1993               pa+=1;
1994               }
1995             while(pa<paa);
1996             }
1997           while(paa<end);
1998           break;
1999         case 270:
2000           resize(height,width);
2001           paa=data;
2002           pbb=olddata+height*(width-1);
2003           end=data+size;
2004           do{
2005             pa=paa; paa+=width;
2006             pb=pbb; pbb+=1;
2007             do{
2008               *pa=*pb;
2009               pa+=1;
2010               pb-=height;
2011               }
2012             while(pa<paa);
2013             }
2014           while(paa<end);
2015           break;
2016         default:
2017           fxwarning("%s::rotate: rotation by %d degrees not implemented.\n",getClassName(),degrees);
2018           break;
2019         }
2020       freeElms(olddata);
2021       render();
2022       }
2023     else{
2024       switch(degrees){
2025         case 90:
2026           resize(height,width);
2027           break;
2028         case 180:
2029           resize(width,height);
2030           break;
2031         case 270:
2032           resize(height,width);
2033           break;
2034         default:
2035           fxwarning("%s::rotate: rotation by %d degrees not implemented.\n",getClassName(),degrees);
2036           break;
2037         }
2038       }
2039     }
2040   }
2041 
2042 
2043 // Crop image to given rectangle; must have at least one pixel overlap.
crop(FXint x,FXint y,FXint w,FXint h,FXColor color)2044 void FXImage::crop(FXint x,FXint y,FXint w,FXint h,FXColor color){
2045   if(w<1) w=1;
2046   if(h<1) h=1;
2047   if(x>=width || y>=height || x+w<=0 || y+h<=0){ fxerror("%s::crop: bad arguments.\n",getClassName()); }
2048   FXTRACE((100,"%s::crop(%d,%d,%d,%d)\n",getClassName(),x,y,w,h));
2049   if(data){
2050     FXColor *pnn,*poo,*yyy,*pn,*po,*xx;
2051     FXint ow=width;
2052     FXint oh=height;
2053     FXint nw=w;
2054     FXint nh=h;
2055     FXint cw;
2056     FXint ch;
2057     FXColor *olddata;
2058     if(!dupElms(olddata,data,width*height)){ throw FXMemoryException("unable to crop image"); }
2059     resize(nw,nh);
2060     pnn=data;
2061     yyy=data+nw*nh;
2062     do{
2063       *pnn++=color;
2064       }
2065     while(pnn<yyy);
2066     if(x<0){
2067       cw=FXMIN(ow,x+nw);
2068       if(y<0){
2069         pnn=data-nw*y;
2070         poo=olddata;
2071         ch=FXMIN(oh,y+nh);
2072         }
2073       else{
2074         pnn=data;
2075         poo=olddata+ow*y;
2076         ch=FXMIN(oh,y+nh)-y;
2077         }
2078       pnn-=x;
2079       }
2080     else{
2081       cw=FXMIN(ow,x+nw)-x;
2082       if(y<0){
2083         pnn=data-nw*y;
2084         poo=olddata;
2085         ch=FXMIN(oh,y+nh);
2086         }
2087       else{
2088         pnn=data;
2089         poo=olddata+ow*y;
2090         ch=FXMIN(oh,y+nh)-y;
2091         }
2092       poo+=x;
2093       }
2094     FXASSERT(cw>0);
2095     FXASSERT(ch>0);
2096     yyy=pnn+nw*ch;
2097     do{
2098       pn=pnn;
2099       po=poo;
2100       xx=pnn+cw;
2101       do{
2102         *pn++=*po++;
2103         }
2104       while(pn<xx);
2105       pnn+=nw;
2106       poo+=ow;
2107       }
2108     while(pnn<yyy);
2109     freeElms(olddata);
2110     render();
2111     }
2112   else{
2113     resize(w,h);
2114     }
2115   }
2116 
2117 
2118 /*
2119     FXuint r=FXREDVAL(color);
2120     FXuint g=FXGREENVAL(color);
2121     FXuint b=FXBLUEVAL(color);
2122     FXuint a=FXALPHAVAL(color);
2123     FXuchar *pix=data;
2124     FXuchar *end=pix+height*width*channels;
2125     FXuchar  tbl[512];
2126 
2127     // Fill table
2128     for(int i=0; i<256; i++){
2129       tbl[255+i]=-(i*factor+127)/255;
2130       tbl[255-i]= (i*factor+127)/255;
2131       }
2132 
2133     // Fade
2134     if(channels==4){
2135       do{
2136         pix[0]=pix[0]+tbl[255+pix[0]-r];
2137         pix[1]=pix[1]+tbl[255+pix[1]-g];
2138         pix[2]=pix[2]+tbl[255+pix[2]-b];
2139         pix[3]=pix[3]+tbl[255+pix[3]-a];
2140         pix+=4;
2141         }
2142       while(pix<end);
2143       }
2144     else{
2145       do{
2146         pix[0]=pix[0]+tbl[255+pix[0]-r];
2147         pix[1]=pix[1]+tbl[255+pix[1]-g];
2148         pix[2]=pix[2]+tbl[255+pix[2]-b];
2149         pix+=3;
2150         }
2151       while(pix<end);
2152       }
2153     }
2154 */
2155 
2156   // FXColor ____blend(FXColor fg,FXColor bg){
2157 //   FXuint r,g,b,s,t,tmp;
2158 //   s=FXALPHAVAL(fg);
2159 //   t=~s;
2160 //   tmp=FXREDVAL(fg)*s+FXREDVAL(bg)*t+127;     r=(tmp+(tmp>>8))>>8;
2161 //   tmp=FXGREENVAL(fg)*s+FXGREENVAL(bg)*t+127; g=(tmp+(tmp>>8))>>8;
2162 //   tmp=FXBLUEVAL(fg)*s+FXBLUEVAL(bg)*t+127;   b=(tmp+(tmp>>8))>>8;
2163 //   return FXRGB(r,g,b);
2164 //   }
2165 /*
2166         s=pix[3];
2167         t=s^0xff;
2168         w=pix[0]*s+r*t; pix[0]=(w+(w>>8))>>8;
2169         w=pix[1]*s+g*t; pix[1]=(w+(w>>8))>>8;
2170         w=pix[2]*s+b*t; pix[2]=(w+(w>>8))>>8;
2171         s=pix[3];
2172 
2173 */
2174 
2175 
2176 // Fill image with color
fill(FXColor color)2177 void FXImage::fill(FXColor color){
2178   if(data){
2179     FXColor *pix=data;
2180     FXColor *end=pix+height*width;
2181     do{ *pix++=color; }while(pix<end);
2182     }
2183   }
2184 
2185 
2186 
2187 // Fade image to uniform color
fade(FXColor color,FXint factor)2188 void FXImage::fade(FXColor color,FXint factor){
2189   if(data){
2190     FXuint s=factor;
2191     FXuint t=~factor;
2192     FXuint r=FXREDVAL(color)*t;
2193     FXuint g=FXGREENVAL(color)*t;
2194     FXuint b=FXBLUEVAL(color)*t;
2195     FXuint a=FXALPHAVAL(color)*t;
2196     FXuint w;
2197     FXuchar *pix=(FXuchar*)data;
2198     FXuchar *end=pix+height*width*4;
2199     do{
2200       w=pix[3]*s+a; pix[3]=(w+(w>>8))>>8;
2201       w=pix[2]*s+r; pix[2]=(w+(w>>8))>>8;
2202       w=pix[1]*s+g; pix[1]=(w+(w>>8))>>8;
2203       w=pix[0]*s+b; pix[0]=(w+(w>>8))>>8;
2204       pix+=4;
2205       }
2206     while(pix<end);
2207     }
2208   }
2209 
2210 
2211 // Shear in X
shearx(FXuchar * out,FXuchar * in,FXint nwidth,FXint owidth,FXint height,FXint shear,FXColor clr)2212 static void shearx(FXuchar *out,FXuchar* in,FXint nwidth,FXint owidth,FXint height,FXint shear,FXColor clr){
2213   FXuchar *ppp,*pp,*qq,*p,*q,*k;
2214   FXuint r=FXREDVAL(clr);
2215   FXuint g=FXGREENVAL(clr);
2216   FXuint b=FXBLUEVAL(clr);
2217   FXuint a=FXALPHAVAL(clr);
2218   FXint dp=owidth<<2;
2219   FXint dq=nwidth<<2;
2220   FXint s,z,y,d;
2221   if(shear){
2222     if(shear>0){ y=height-1; d=-1; } else { shear=-shear; y=0; d=1; }
2223     pp=in;
2224     ppp=pp+height*dp;
2225     qq=out;
2226     do{
2227       p=pp; pp+=dp;
2228       q=qq; qq+=dq;
2229       z=(y*shear-1)/(height-1); y+=d;
2230       s=z&255;
2231       k=q+(z>>8)*4;
2232       while(q<k){
2233         q[3]=a;
2234         q[2]=r;
2235         q[1]=g;
2236         q[0]=b;
2237         q+=4;
2238         }
2239       q[3]=((a-p[3])*s+(p[3]<<8)+127)>>8;
2240       q[2]=((r-p[2])*s+(p[2]<<8)+127)>>8;
2241       q[1]=((g-p[1])*s+(p[1]<<8)+127)>>8;
2242       q[0]=((b-p[0])*s+(p[0]<<8)+127)>>8;
2243       q+=4;
2244       p+=4;
2245       while(p<pp){
2246         q[3]=((p[3-4]-p[3])*s+(p[3]<<8)+127)>>8;
2247         q[2]=((p[2-4]-p[2])*s+(p[2]<<8)+127)>>8;
2248         q[1]=((p[1-4]-p[1])*s+(p[1]<<8)+127)>>8;
2249         q[0]=((p[0-4]-p[0])*s+(p[0]<<8)+127)>>8;
2250         q+=4;
2251         p+=4;
2252         }
2253       q[3]=((p[3-4]-a)*s+(a<<8)+127)>>8;
2254       q[2]=((p[2-4]-r)*s+(r<<8)+127)>>8;
2255       q[1]=((p[1-4]-g)*s+(g<<8)+127)>>8;
2256       q[0]=((p[0-4]-b)*s+(b<<8)+127)>>8;
2257       q+=4;
2258       while(q<qq){
2259         q[3]=a;
2260         q[2]=r;
2261         q[1]=g;
2262         q[0]=b;
2263         q+=4;
2264         }
2265       }
2266     while(pp!=ppp);
2267     }
2268   else{
2269     memcpy(out,in,owidth*height*4);
2270     }
2271   }
2272 
2273 
2274 // Shear in Y
sheary(FXuchar * out,FXuchar * in,FXint width,FXint nheight,FXint oheight,FXint shear,FXColor clr)2275 static void sheary(FXuchar *out,FXuchar* in,FXint width,FXint nheight,FXint oheight,FXint shear,FXColor clr){
2276   FXuchar *ppp,*pp,*qq,*p,*q,*k;
2277   FXuint r=FXREDVAL(clr);
2278   FXuint g=FXGREENVAL(clr);
2279   FXuint b=FXBLUEVAL(clr);
2280   FXuint a=FXALPHAVAL(clr);
2281   FXint dp=width<<2;
2282   FXint s,z,x,d;
2283   if(shear){
2284     if(shear>0){ x=width-1; d=-1; } else { shear=-shear; x=0; d=1; }
2285     pp=in+dp*oheight;
2286     ppp=pp+dp;
2287     qq=out+dp*nheight;
2288     do{
2289       p=pp-dp*oheight;
2290       q=qq-dp*nheight;
2291       z=(x*shear-1)/(width-1); x+=d;
2292       s=z&255;
2293       k=q+(z>>8)*dp;
2294       while(q<k){
2295         q[3]=r;
2296         q[2]=g;
2297         q[1]=b;
2298         q[0]=a;
2299         q+=dp;
2300         }
2301       q[3]=((a-p[3])*s+(p[3]<<8)+127)>>8;
2302       q[2]=((r-p[2])*s+(p[2]<<8)+127)>>8;
2303       q[1]=((g-p[1])*s+(p[1]<<8)+127)>>8;
2304       q[0]=((b-p[0])*s+(p[0]<<8)+127)>>8;
2305       q+=dp;
2306       p+=dp;
2307       while(p<pp){
2308         q[3]=((p[3-dp]-p[3])*s+(p[3]<<8)+127)>>8;
2309         q[2]=((p[2-dp]-p[2])*s+(p[2]<<8)+127)>>8;
2310         q[1]=((p[1-dp]-p[1])*s+(p[1]<<8)+127)>>8;
2311         q[0]=((p[0-dp]-p[0])*s+(p[0]<<8)+127)>>8;
2312         q+=dp;
2313         p+=dp;
2314         }
2315       q[3]=((p[3-dp]-a)*s+(a<<8)+127)>>8;
2316       q[2]=((p[2-dp]-r)*s+(r<<8)+127)>>8;
2317       q[1]=((p[1-dp]-g)*s+(g<<8)+127)>>8;
2318       q[0]=((p[0-dp]-b)*s+(b<<8)+127)>>8;
2319       q+=dp;
2320       while(q<qq){
2321         q[3]=a;
2322         q[2]=r;
2323         q[1]=g;
2324         q[0]=b;
2325         q+=dp;
2326         }
2327       pp+=4;
2328       qq+=4;
2329       }
2330     while(pp!=ppp);
2331     }
2332   else{
2333     memcpy(out,in,width*oheight*4);
2334     }
2335   }
2336 
2337 
2338 // Shear image horizontally
xshear(FXint shear,FXColor clr)2339 void FXImage::xshear(FXint shear,FXColor clr){
2340   FXint neww=width+((FXABS(shear)+255)>>8);
2341   FXint oldw=width;
2342   FXTRACE((100,"%s::xshear(%d)\n",getClassName(),shear));
2343   if(data){
2344     FXColor *olddata;
2345     if(!dupElms(olddata,data,width*height)){ throw FXMemoryException("unable to xshear image"); }
2346     resize(neww,height);
2347     shearx((FXuchar*)data,(FXuchar*)olddata,neww,oldw,height,shear,clr);
2348     freeElms(olddata);
2349     render();
2350     }
2351   else{
2352     resize(neww,height);
2353     }
2354   }
2355 
2356 
2357 // Shear image vertically
yshear(FXint shear,FXColor clr)2358 void FXImage::yshear(FXint shear,FXColor clr){
2359   FXint newh=height+((FXABS(shear)+255)>>8);
2360   FXint oldh=height;
2361   FXTRACE((100,"%s::yshear(%d)\n",getClassName(),shear));
2362   if(data){
2363     FXColor *olddata;
2364     if(!dupElms(olddata,data,width*height)){ throw FXMemoryException("unable to yshear image"); }
2365     resize(width,newh);
2366     sheary((FXuchar*)data,(FXuchar*)olddata,width,newh,oldh,shear,clr);
2367     freeElms(olddata);
2368     render();
2369     }
2370   else{
2371     resize(width,newh);
2372     }
2373   }
2374 
2375 
2376 // Fill horizontal gradient
hgradient(FXColor left,FXColor right)2377 void FXImage::hgradient(FXColor left,FXColor right){
2378   FXint rr,gg,bb,aa,dr,dg,db,da,r1,g1,b1,a1,r2,g2,b2,a2,x;
2379   FXuchar *ptr=(FXuchar*)data;
2380   FXuchar *prv=(FXuchar*)data;
2381   if(ptr && width>1 && height>1){
2382     r1=FXREDVAL(left);
2383     r2=FXREDVAL(right);
2384     rr=(r1<<16)+32768;
2385     dr=((r2-r1)<<16)/(width-1);
2386     g1=FXGREENVAL(left);
2387     g2=FXGREENVAL(right);
2388     gg=(g1<<16)+32768;
2389     dg=((g2-g1)<<16)/(width-1);
2390     b1=FXBLUEVAL(left);
2391     b2=FXBLUEVAL(right);
2392     bb=(b1<<16)+32768;
2393     db=((b2-b1)<<16)/(width-1);
2394     a1=FXALPHAVAL(left);
2395     a2=FXALPHAVAL(right);
2396     aa=(a1<<16)+32768;
2397     da=((a2-a1)<<16)/(width-1);
2398     x=width;
2399     do{
2400       ptr[3]=aa>>16; aa+=da;
2401       ptr[2]=rr>>16; rr+=dr;
2402       ptr[1]=gg>>16; gg+=dg;
2403       ptr[0]=bb>>16; bb+=db;
2404       ptr+=4;
2405       }
2406     while(--x);
2407     x=width*(height-1);
2408     do{
2409       ptr[0]=prv[0];
2410       ptr[1]=prv[1];
2411       ptr[2]=prv[2];
2412       ptr[3]=prv[3];
2413       ptr+=4;
2414       prv+=4;
2415       }
2416     while(--x);
2417     }
2418   }
2419 
2420 
2421 // Fill vertical gradient
vgradient(FXColor top,FXColor bottom)2422 void FXImage::vgradient(FXColor top,FXColor bottom){
2423   FXint rr,gg,bb,aa,dr,dg,db,da,r1,g1,b1,a1,r2,g2,b2,a2,x,y;
2424   FXuchar *ptr=(FXuchar*)data;
2425   if(ptr && width>1 && height>1){
2426     r1=FXREDVAL(top);
2427     r2=FXREDVAL(bottom);
2428     rr=(r1<<16)+32768;
2429     dr=((r2-r1)<<16)/(height-1);
2430     g1=FXGREENVAL(top);
2431     g2=FXGREENVAL(bottom);
2432     gg=(g1<<16)+32768;
2433     dg=((g2-g1)<<16)/(height-1);
2434     b1=FXBLUEVAL(top);
2435     b2=FXBLUEVAL(bottom);
2436     bb=(b1<<16)+32768;
2437     db=((b2-b1)<<16)/(height-1);
2438     a1=FXALPHAVAL(top);
2439     a2=FXALPHAVAL(bottom);
2440     aa=(a1<<16)+32768;
2441     da=((a2-a1)<<16)/(height-1);
2442     y=height;
2443     do{
2444       a1=aa>>16; aa+=da;
2445       r1=rr>>16; rr+=dr;
2446       g1=gg>>16; gg+=dg;
2447       b1=bb>>16; bb+=db;
2448       x=width;
2449       do{
2450         ptr[3]=a1;
2451         ptr[2]=r1;
2452         ptr[1]=g1;
2453         ptr[0]=b1;
2454         ptr+=4;
2455         }
2456       while(--x);
2457       }
2458     while(--y);
2459     }
2460   }
2461 
2462 
2463 // Fill with gradient
gradient(FXColor topleft,FXColor topright,FXColor bottomleft,FXColor bottomright)2464 void FXImage::gradient(FXColor topleft,FXColor topright,FXColor bottomleft,FXColor bottomright){
2465   FXint rl,gl,bl,al,rr,gr,br,ar,drl,dgl,dbl,dal,drr,dgr,dbr,dar,r,g,b,a,dr,dg,db,da,x,y;
2466   FXint rtl,gtl,btl,atl,rtr,gtr,btr,atr,rbl,gbl,bbl,abl,rbr,gbr,bbr,abr;
2467   FXuchar *ptr=(FXuchar*)data;
2468   if(ptr && width>1 && height>1){
2469 
2470     rtl=FXREDVAL(topleft);
2471     rbl=FXREDVAL(bottomleft);
2472     rl=(rtl<<16)+32768; drl=((rbl-rtl)<<16)/(height-1);
2473 
2474     gtl=FXGREENVAL(topleft);
2475     gbl=FXGREENVAL(bottomleft);
2476     gl=(gtl<<16)+32768; dgl=((gbl-gtl)<<16)/(height-1);
2477 
2478     btl=FXBLUEVAL(topleft);
2479     bbl=FXBLUEVAL(bottomleft);
2480     bl=(btl<<16)+32768; dbl=((bbl-btl)<<16)/(height-1);
2481 
2482     rtr=FXREDVAL(topright);
2483     rbr=FXREDVAL(bottomright);
2484     rr=(rtr<<16)+32768; drr=((rbr-rtr)<<16)/(height-1);
2485 
2486     gtr=FXGREENVAL(topright);
2487     gbr=FXGREENVAL(bottomright);
2488     gr=(gtr<<16)+32768; dgr=((gbr-gtr)<<16)/(height-1);
2489 
2490     btr=FXBLUEVAL(topright);
2491     bbr=FXBLUEVAL(bottomright);
2492     br=(btr<<16)+32768; dbr=((bbr-btr)<<16)/(height-1);
2493 
2494     atl=FXALPHAVAL(topleft);
2495     abl=FXALPHAVAL(bottomleft);
2496     al=(atl<<16)+32768; dal=((abl-atl)<<16)/(height-1);
2497 
2498     atr=FXALPHAVAL(topright);
2499     abr=FXALPHAVAL(bottomright);
2500     ar=(atr<<16)+32768; dar=((abr-atr)<<16)/(height-1);
2501 
2502     y=height;
2503     do{
2504       a=al; da=(ar-al)/(width-1);
2505       r=rl; dr=(rr-rl)/(width-1);
2506       g=gl; dg=(gr-gl)/(width-1);
2507       b=bl; db=(br-bl)/(width-1);
2508       x=width;
2509       do{
2510         ptr[3]=a>>16; a+=da;
2511         ptr[2]=r>>16; r+=dr;
2512         ptr[1]=g>>16; g+=dg;
2513         ptr[0]=b>>16; b+=db;
2514         ptr+=4;
2515         }
2516       while(--x);
2517       rl+=drl;
2518       gl+=dgl;
2519       bl+=dbl;
2520       al+=dal;
2521       rr+=drr;
2522       gr+=dgr;
2523       br+=dbr;
2524       ar+=dar;
2525       }
2526     while(--y);
2527     }
2528   }
2529 
2530 
2531 // Blend image over uniform color
blend(FXColor color)2532 void FXImage::blend(FXColor color){
2533   if(data){
2534     FXuchar *pix=(FXuchar*)data;
2535     FXuchar *end=pix+height*width*4;
2536     FXint r=FXREDVAL(color);
2537     FXint g=FXGREENVAL(color);
2538     FXint b=FXBLUEVAL(color);
2539     FXint s,w;
2540     do{
2541       s=pix[3];
2542       w=(pix[2]-r)*s; pix[2]=r+((w+(w>>8)+128)>>8);
2543       w=(pix[1]-g)*s; pix[1]=g+((w+(w>>8)+128)>>8);
2544       w=(pix[0]-b)*s; pix[0]=b+((w+(w>>8)+128)>>8);             /* FIXME need to write new alpha also */
2545       pix+=4;
2546       }
2547     while(pix<end);
2548     }
2549   }
2550 
2551 
2552 // Invert colors of an image
invert()2553 void FXImage::invert(){
2554   if(data){
2555     FXuchar *pix=(FXuchar*)data;
2556     FXuchar *end=pix+height*width*4;
2557     do{
2558       pix[1]=255-pix[1];
2559       pix[2]=255-pix[2];
2560       pix[3]=255-pix[3];
2561       pix+=4;
2562       }
2563     while(pix<end);
2564     }
2565   }
2566 
2567 
2568 // Colorize image based on luminance
colorize(FXColor color)2569 void FXImage::colorize(FXColor color){
2570   if(data){
2571     FXuchar *pix=(FXuchar*)data;
2572     FXuchar *end=pix+height*width*4;
2573     FXint r=FXREDVAL(color);
2574     FXint g=FXGREENVAL(color);
2575     FXint b=FXBLUEVAL(color);
2576     FXint lum,w;
2577     do{
2578       if(pix[3]){
2579         lum=(77*pix[2]+151*pix[1]+29*pix[0])>>8;
2580         w=r*lum; pix[2]=(w+(w>>8))>>8;
2581         w=g*lum; pix[1]=(w+(w>>8))>>8;
2582         w=b*lum; pix[0]=(w+(w>>8))>>8;
2583         }
2584       pix+=4;
2585       }
2586     while(pix<end);
2587     }
2588   }
2589 
2590 /*
2591 
2592 
2593 // Fill with diagonal gradient RGB
2594 static void dgradientrgba(FXuchar *dst,FXint w,FXint h,FXint r1,FXint g1,FXint b1,FXint a1,FXint r2,FXint g2,FXint b2,FXint a2){
2595   FXint rr,gg,bb,aa,drx,dgx,dbx,dax,dry,dgy,dby,day,x,y;
2596   FXuchar *ptr=dst;
2597   FXuchar xtable[4][2048];
2598   FXuchar ytable[4][2048];
2599   FXASSERT(w>0 && h>0);
2600   FXASSERT(w<2048 && h<2048);
2601   drx=dry=((r2-r1)<<16);
2602   dgx=dgy=((g2-g1)<<16);
2603   dbx=dby=((b2-b1)<<16);
2604   dax=day=((a2-a1)<<16);
2605   rr=(r1<<16)+32768;
2606   gg=(g1<<16)+32768;
2607   bb=(b1<<16)+32768;
2608   aa=(a1<<16)+32768;
2609   drx/=(w-1)*2;
2610   dgx/=(w-1)*2;
2611   dbx/=(w-1)*2;
2612   dax/=(w-1)*2;
2613   x=w;
2614   do{
2615     --x;
2616     xtable[0][x]=rr>>16; rr+=drx;
2617     xtable[1][x]=gg>>16; gg+=dgx;
2618     xtable[2][x]=bb>>16; bb+=dbx;
2619     xtable[3][x]=aa>>16; aa+=dax;
2620     }
2621   while(x);
2622   rr=32768;
2623   gg=32768;
2624   bb=32768;
2625   aa=32768;
2626   dry/=(h-1)*2;
2627   dgy/=(h-1)*2;
2628   dby/=(h-1)*2;
2629   day/=(h-1)*2;
2630   y=h;
2631   do{
2632     --y;
2633     ytable[0][y]=rr>>16; rr+=dry;
2634     ytable[1][y]=gg>>16; gg+=dgy;
2635     ytable[2][y]=bb>>16; bb+=dby;
2636     ytable[3][y]=aa>>16; aa+=day;
2637     }
2638   while(y);
2639   y=h;
2640   do{
2641     --y;
2642     x=w;
2643     do{
2644       --x;
2645       ptr[0]=xtable[0][x]+ytable[0][y];
2646       ptr[1]=xtable[1][x]+ytable[1][y];
2647       ptr[2]=xtable[2][x]+ytable[2][y];
2648       ptr[3]=xtable[3][x]+ytable[3][y];
2649       ptr+=4;
2650       }
2651     while(x);
2652     }
2653   while(y);
2654   }
2655 */
2656 
2657 
2658 
2659 
2660 // Save pixel data only
savePixels(FXStream & store) const2661 FXbool FXImage::savePixels(FXStream& store) const {
2662   FXuint size=width*height;
2663   store.save(data,size);
2664   return true;
2665   }
2666 
2667 
2668 // Load pixel data only
loadPixels(FXStream & store)2669 FXbool FXImage::loadPixels(FXStream& store){
2670   FXuint size=width*height;
2671   if(options&IMAGE_OWNED){freeElms(data);}
2672   if(!allocElms(data,size)) return false;
2673   store.load(data,size);
2674   options|=IMAGE_OWNED;
2675   return true;
2676   }
2677 
2678 
2679 // Save data
save(FXStream & store) const2680 void FXImage::save(FXStream& store) const {
2681   FXuchar haspixels=(data!=NULL);
2682   FXDrawable::save(store);
2683   store << options;
2684   store << haspixels;
2685   if(haspixels) savePixels(store);
2686   }
2687 
2688 
2689 // Load data
load(FXStream & store)2690 void FXImage::load(FXStream& store){
2691   FXuchar haspixels;
2692   FXDrawable::load(store);
2693   store >> options;
2694   store >> haspixels;
2695   if(haspixels) loadPixels(store);
2696   }
2697 
2698 
2699 // Clean up
~FXImage()2700 FXImage::~FXImage(){
2701   FXTRACE((100,"FXImage::~FXImage %p\n",this));
2702   destroy();
2703   if(options&IMAGE_OWNED){freeElms(data);}
2704   data=(FXColor*)-1L;
2705   }
2706 
2707 }
2708