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