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