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