1 /* Part of XPCE --- The SWI-Prolog GUI toolkit
2
3 Author: Jan Wielemaker and Anjo Anjewierden
4 E-mail: jan@swi.psy.uva.nl
5 WWW: http://www.swi.psy.uva.nl/projects/xpce/
6 Copyright (c) 1985-2002, University of Amsterdam
7 All rights reserved.
8
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions
11 are met:
12
13 1. Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
15
16 2. Redistributions in binary form must reproduce the above copyright
17 notice, this list of conditions and the following disclaimer in
18 the documentation and/or other materials provided with the
19 distribution.
20
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include <h/kernel.h>
36 #include <h/graphics.h>
37 #include <h/unix.h>
38
39 #include <math.h>
40 #ifndef M_PI
41 #define M_PI 3.14159265358979323846
42 #endif
43
44 static status drawInImage(Image image, Graphical gr, Point pos);
45
46 /********************************
47 * CREATE/DESTROY *
48 ********************************/
49
50 status
initialiseImage(Image image,SourceSink data,Int w,Int h,Name kind)51 initialiseImage(Image image, SourceSink data, Int w, Int h, Name kind)
52 { Name name = FAIL;
53
54 if ( isDefault(data) )
55 data = (SourceSink) NIL;
56
57 if ( notNil(data) && hasGetMethodObject(data, NAME_name) )
58 name = get(data, NAME_name, EAV);
59 if ( !name )
60 name = NIL;
61
62 assign(image, name, name);
63 assign(image, background, DEFAULT);
64 assign(image, foreground, DEFAULT);
65 ws_init_image(image);
66
67 if ( isNil(data) || notDefault(w) || notDefault(h) || notDefault(kind) )
68 { if ( isDefault(w) ) w = toInt(16);
69 if ( isDefault(h) ) h = toInt(16);
70 if ( isDefault(kind) ) kind = NAME_bitmap;
71
72 assign(image, kind, kind);
73 assign(image, file, NIL);
74 assign(image, depth, kind == NAME_bitmap ? ONE : (Int) DEFAULT);
75 assign(image, size, newObject(ClassSize, w, h, EAV));
76 assign(image, access, NAME_both);
77 } else
78 { assign(image, kind, NAME_bitmap);
79 assign(image, file, data);
80 assign(image, depth, ONE);
81 assign(image, size, newObject(ClassSize, EAV));
82 TRY(loadImage(image, DEFAULT, DEFAULT));
83 assign(image, access, NAME_read);
84 }
85
86 if ( notNil(name) )
87 { protectObject(image);
88 appendHashTable(ImageTable, name, image);
89 }
90
91 succeed;
92 }
93
94
95 static Image
getLookupImage(Class class,Any from)96 getLookupImage(Class class, Any from)
97 { if ( !isName(from) )
98 from = qadGetv(from, NAME_name, 0, NULL);
99
100 answer(getMemberHashTable(ImageTable, from));
101 }
102
103
104 static status
unlinkImage(Image image)105 unlinkImage(Image image)
106 { XcloseImage(image, DEFAULT);
107 ws_destroy_image(image);
108
109 if ( notNil(image->bitmap) && image->bitmap->image == image )
110 { BitmapObj bm = image->bitmap;
111
112 assign(image, bitmap, NIL);
113 freeObject(bm);
114 }
115
116 if ( notNil(image->name) )
117 deleteHashTable(ImageTable, image->name);
118
119 succeed;
120 }
121
122
123 static BitmapObj
getContainedInImage(Image image)124 getContainedInImage(Image image)
125 { if ( notNil(image->bitmap) )
126 return image->bitmap;
127
128 fail;
129 }
130
131 /********************************
132 * CONVERSION *
133 ********************************/
134
135 Image
getConvertImage(Class class,Any obj)136 getConvertImage(Class class, Any obj)
137 { Image image;
138 Name name;
139
140 if ( (image = getConvertObject(class, obj)) )
141 { if ( instanceOfObject(image, ClassImage) )
142 answer(image);
143
144 obj = image;
145 }
146
147 if ( instanceOfObject(obj, ClassBitmap) )
148 answer(((BitmapObj)obj)->image);
149
150 if ( instanceOfObject(obj, ClassRC) )
151 { RC rc = obj;
152
153 if ( (image = getMemberHashTable(ImageTable, rc->name)) )
154 answer(image);
155
156 answer(answerObject(ClassImage, obj, EAV));
157 }
158
159 if ( (name = checkType(obj, TypeName, class)) )
160 { if ( (image = getMemberHashTable(ImageTable, name)) )
161 answer(image);
162 else
163 answer(answerObject(ClassImage, name, EAV));
164 }
165
166 if ( instanceOfObject(obj, ClassGraphical) )
167 { Graphical gr = obj;
168 Image img;
169
170 ComputeGraphical(gr);
171 if ( (img = newObject(ClassImage, NIL, gr->area->w, gr->area->h, EAV)) )
172 { drawInImage(img, gr, answerObject(ClassPoint, EAV));
173 answer(img);
174 }
175 }
176
177 fail;
178 }
179
180
181 /********************************
182 * CHANGES *
183 ********************************/
184
185 /* TBD: function! */
186 #define CHANGING_IMAGE(img, code) \
187 { BitmapObj _b = (img)->bitmap; \
188 \
189 code; \
190 \
191 if ( notNil(_b) ) \
192 { Size _s = (img)->size; \
193 Area _a = _b->area; \
194 \
195 if ( _s->w != _a->w || _s->h != _a->h ) \
196 { Int _w = _a->w, _h = _a->h; \
197 \
198 assign(_a, w, _s->w); \
199 assign(_a, h, _s->h); \
200 changedAreaGraphical(_b, _a->x, _a->y, _w, _h); \
201 } \
202 } \
203 }
204
205
206 /********************************
207 * LOAD/STORE *
208 ********************************/
209
210 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
211 Store/load images to/form file. Format:
212
213 <image> ::= <pce-slots>
214 'X' <image> | 'O'
215 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
216
217 static status
storeImage(Image image,FileObj file)218 storeImage(Image image, FileObj file)
219 { TRY( storeSlotsObject(image, file) );
220
221 if ( isNil(image->file) )
222 return ws_store_image(image, file);
223 else
224 { Sputc('O', file->fd);
225 succeed;
226 }
227 }
228
229
230 static status
loadFdImage(Image image,IOSTREAM * fd,ClassDef def)231 loadFdImage(Image image, IOSTREAM *fd, ClassDef def)
232 { FileObj file;
233
234 TRY( loadSlotsObject(image, fd, def) );
235 ws_init_image(image);
236
237 /* convert old path-representation */
238 if ( instanceOfObject((file=(FileObj)image->file), ClassFile) &&
239 isAbsoluteFile(file) &&
240 getBaseNameFile(file) == image->name )
241 { assign(file, path, file->name);
242 assign(file, name, image->name);
243 }
244
245 switch( Sgetc(fd) )
246 { case 'O': /* no image */
247 break;
248 case 'X':
249 return loadXImage(image, fd);
250 case 'P':
251 return loadPNMImage(image, fd);
252 }
253
254 succeed;
255 }
256
257
258 /********************************
259 * XOPEN/XCLOSE *
260 ********************************/
261
262
263 status
XopenImage(Image image,DisplayObj d)264 XopenImage(Image image, DisplayObj d)
265 { if ( image->bits ) /* built-in. See stdImage() */
266 { switch(image->bits->type)
267 { case XBM_DATA:
268 ws_create_image_from_x11_data(image,
269 image->bits->bits.xbm,
270 valInt(image->size->w),
271 valInt(image->size->h));
272 break;
273 case XPM_DATA:
274 ws_create_image_from_xpm_data(image,
275 image->bits->bits.xpm,
276 d);
277 break;
278 default:
279 assert(0);
280 }
281 /* Windows already does the registration */
282 if ( getExistingXrefObject(image, d) )
283 succeed;
284 }
285
286 return ws_open_image(image, d);
287 }
288
289
290 status
XcloseImage(Image image,DisplayObj d)291 XcloseImage(Image image, DisplayObj d)
292 { ws_close_image(image, d);
293
294 succeed;
295 }
296
297 /*******************************
298 * COLOURMAP *
299 *******************************/
300
301 static ColourMap
getColourMapImage(Image image)302 getColourMapImage(Image image)
303 { if ( image->kind != NAME_bitmap )
304 return ws_colour_map_for_image(image);
305
306 fail;
307 }
308
309
310 /********************************
311 * FILE OPERATIONS *
312 ********************************/
313
314 status
loadImage(Image image,SourceSink file,CharArray path)315 loadImage(Image image, SourceSink file, CharArray path)
316 { status rval;
317
318 if ( notDefault(file) )
319 assign(image, file, file);
320
321 if ( isNil(image->file) )
322 fail;
323
324 if ( instanceOfObject(image->file, ClassFile) )
325 { if ( isDefault(path) )
326 TRY(path = getClassVariableValueObject(image, NAME_path));
327
328 TRY(send(image->file, NAME_find, path, NAME_read, EAV));
329 }
330
331 CHANGING_IMAGE(image,
332 (rval = ws_load_image_file(image)));
333
334 return rval;
335 }
336
337
338 static status
saveImage(Image image,SourceSink file,Name fmt)339 saveImage(Image image, SourceSink file, Name fmt)
340 { if ( isDefault(file) )
341 file = image->file;
342 if ( isDefault(fmt) )
343 fmt = NAME_xbm;
344
345 if ( isNil(file) )
346 return errorPce(image, NAME_noFile);
347
348 return ws_save_image_file(image, file, fmt);
349 }
350
351
352
353 /********************************
354 * EDIT OPERATIONS *
355 ********************************/
356
357 static status
verifyAccessImage(Image image,Name sel)358 verifyAccessImage(Image image, Name sel)
359 { if ( image->access != NAME_both )
360 return errorPce(image, NAME_readOnly);
361
362 if ( isNil(image->display) )
363 assign(image, display, CurrentDisplay(image));
364
365 openDisplay(image->display);
366
367 succeed;
368 }
369
370
371 static status
changedImageImage(Image image,Int x,Int y,Int w,Int h)372 changedImageImage(Image image, Int x, Int y, Int w, Int h)
373 { if ( notNil(image->bitmap))
374 return changedImageGraphical(image->bitmap, x, y, w, h);
375
376 succeed;
377 }
378
379
380 static status
changedEntireImageImage(Image image)381 changedEntireImageImage(Image image)
382 { if ( notNil(image->bitmap))
383 return changedImageGraphical(image->bitmap, ZERO, ZERO,
384 image->size->w, image->size->h);
385
386 ws_destroy_image(image); /* remove memory copy */
387
388 succeed;
389 }
390
391
392 static status
inImage(Image image,Int x,Int y)393 inImage(Image image, Int x, Int y)
394 { if ( valInt(x) >= 0 && valInt(y) >= 0 &&
395 valInt(x) < valInt(image->size->w) &&
396 valInt(y) < valInt(image->size->h) )
397 succeed;
398
399 fail;
400 }
401
402
403 static status
clearImage(Image image)404 clearImage(Image image)
405 { TRY( verifyAccessImage(image, NAME_clear) );
406
407 CHANGING_IMAGE(image,
408 if ( image->size->w != ZERO && image->size->h != ZERO &&
409 notNil(image->display) &&
410 getExistingXrefObject(image, image->display) != NULL )
411 { int w = valInt(image->size->w);
412 int h = valInt(image->size->h);
413
414 d_image(image, 0, 0, w, h);
415 d_modify();
416 r_clear(0, 0, w, h);
417 d_done();
418 changedEntireImageImage(image);
419 });
420
421 succeed;
422 }
423
424
425 static status
resizeImage(Image image,Int w,Int h)426 resizeImage(Image image, Int w, Int h)
427 { TRY( verifyAccessImage(image, NAME_resize) );
428
429 CHANGING_IMAGE(image,
430 ws_resize_image(image, w, h));
431
432 succeed;
433 }
434
435
436 static status
copyImage(Image image,Image i2)437 copyImage(Image image, Image i2)
438 { Int w = i2->size->w;
439 Int h = i2->size->h;
440
441 TRY(verifyAccessImage(image, NAME_copy));
442
443 CHANGING_IMAGE(image,
444 TRY(resizeImage(image, w, h));
445
446 d_image(image, 0, 0, valInt(w), valInt(h));
447 d_modify();
448 r_image(i2, 0, 0, 0, 0, valInt(w), valInt(h), OFF);
449 d_done();
450 changedEntireImageImage(image););
451
452
453 succeed;
454 }
455
456
457 static status
drawInImage(Image image,Graphical gr,Point pos)458 drawInImage(Image image, Graphical gr, Point pos)
459 { Int oldx, oldy;
460 Device dev;
461 int x, y, w, h;
462 int iw = valInt(image->size->w);
463 int ih = valInt(image->size->h);
464 int m;
465 Area a;
466 BoolObj olddisplayed = gr->displayed;
467
468 TRY(verifyAccessImage(image, NAME_drawIn));
469
470 if ( notDefault(pos) )
471 { oldx = gr->area->x;
472 oldy = gr->area->y;
473 dev = gr->device;
474 gr->device = NIL;
475 setGraphical(gr, pos->x, pos->y, DEFAULT, DEFAULT);
476 } else
477 { oldx = oldy = DEFAULT;
478 dev = NIL; /* keep compiler happy */
479 }
480
481 displayedGraphical(gr, ON);
482 ComputeGraphical(gr);
483 x = valInt(gr->area->x);
484 y = valInt(gr->area->y);
485 w = valInt(gr->area->w);
486 h = valInt(gr->area->h);
487 NormaliseArea(x,y,w,h);
488
489 if ( x < 0 ) /* clip and normalise the area */
490 { w += x;
491 x = 0;
492 } else if ( x > iw )
493 goto out;
494
495 if ( y < 0 )
496 { h += y;
497 y = 0;
498 } else if ( y > ih )
499 goto out;
500
501 if ( w < 0 || h < 0 )
502 goto out;
503
504 if ( x+w > iw )
505 w = iw - x;
506 if ( y+h > ih )
507 h = ih - y;
508
509 if ( (m=get_extension_margin_graphical(gr)) )
510 { x -= m; y -= m; w += m*2; h += 2*m;
511 }
512
513 a = answerObject(ClassArea, toInt(x), toInt(y), toInt(w), toInt(h), EAV);
514 CHANGING_IMAGE(image,
515 d_image(image, x, y, w, h);
516 d_modify();
517 RedrawArea(gr, a); /* Was gr->area */
518 d_done();
519 if ( notNil(image->bitmap) )
520 changedImageGraphical(image->bitmap,
521 toInt(x), toInt(y), toInt(w), toInt(h)););
522 doneObject(a);
523
524 out:
525 displayedGraphical(gr, olddisplayed);
526 if ( notDefault(oldx) )
527 { setGraphical(gr, oldx, oldy, DEFAULT, DEFAULT);
528 gr->device = dev;
529 }
530
531 succeed;
532 }
533
534 /********************************
535 * FILLING *
536 ********************************/
537
538 status
fillImage(Image image,Any pattern,Area area)539 fillImage(Image image, Any pattern, Area area)
540 { int x, y, w, h;
541
542 TRY(verifyAccessImage(image, NAME_fill));
543
544 if ( isDefault(area) )
545 { x = y = 0;
546 w = valInt(image->size->w);
547 h = valInt(image->size->h);
548 } else
549 { x = valInt(area->x);
550 y = valInt(area->y);
551 w = valInt(area->w);
552 h = valInt(area->h);
553
554 NormaliseArea(x, y, w, h);
555 if ( x < 0 ) w += x, x = 0;
556 if ( y < 0 ) h += y, y = 0;
557 if ( x+w > valInt(image->size->w) ) w = valInt(image->size->w) - x;
558 if ( y+h > valInt(image->size->h) ) h = valInt(image->size->h) - y;
559 }
560
561 if ( w > 0 && h > 0 )
562 { CHANGING_IMAGE(image,
563 d_image(image, 0, 0, valInt(image->size->w), valInt(image->size->h));
564 d_modify();
565 r_fill(x, y, w, h, pattern);
566 d_done();
567 changedEntireImageImage(image));
568 }
569
570 succeed;
571 }
572
573
574 /********************************
575 * PIXELS *
576 ********************************/
577
578
579 static status
pixelImage(Image image,Int X,Int Y,Any val)580 pixelImage(Image image, Int X, Int Y, Any val)
581 { int x = valInt(X);
582 int y = valInt(Y);
583
584 TRY( verifyAccessImage(image, NAME_pixel) );
585
586 if ( inImage(image, X, Y) )
587 { if ( (image->kind == NAME_bitmap && !instanceOfObject(val, ClassBool)) ||
588 (image->kind == NAME_pixmap && !instanceOfObject(val, ClassColour)) )
589 return errorPce(image, NAME_pixelMismatch, val);
590
591 CHANGING_IMAGE(image,
592 d_image(image, 0, 0, valInt(image->size->w), valInt(image->size->h));
593 d_modify();
594 r_pixel(x, y, val);
595 d_done();
596 changedImageImage(image, X, Y, ONE, ONE));
597
598 succeed;
599 }
600
601 fail;
602 }
603
604
605 static status
setPixelImage(Image image,Int x,Int y)606 setPixelImage(Image image, Int x, Int y)
607 { if ( image->kind == NAME_bitmap )
608 return pixelImage(image, x, y, ON);
609 else
610 return pixelImage(image, x, y, image->foreground);
611 }
612
613
614 static status
clearPixelImage(Image image,Int x,Int y)615 clearPixelImage(Image image, Int x, Int y)
616 { if ( image->kind == NAME_bitmap )
617 return pixelImage(image, x, y, OFF);
618 else
619 return pixelImage(image, x, y, image->background);
620 }
621
622
623 static status
invertPixelImage(Image image,Int x,Int y)624 invertPixelImage(Image image, Int x, Int y)
625 { TRY(verifyAccessImage(image, NAME_invertPixel));
626
627 if ( inImage(image, x, y) )
628 { CHANGING_IMAGE(image,
629 d_image(image, 0, 0, valInt(image->size->w), valInt(image->size->h));
630 d_modify();
631 r_complement_pixel(valInt(x), valInt(y));
632 d_done();
633 changedImageImage(image, x, y, ONE, ONE));
634 }
635 succeed;
636 }
637
638
639 static status
invertImage(Image image)640 invertImage(Image image)
641 { TRY(verifyAccessImage(image, NAME_invert));
642
643 CHANGING_IMAGE(image,
644 d_image(image, 0, 0, valInt(image->size->w), valInt(image->size->h));
645 d_modify();
646 r_complement(0, 0, valInt(image->size->w), valInt(image->size->h));
647 d_done();
648 changedEntireImageImage(image));
649
650 succeed;
651 }
652
653
654 static Any
getPixelImage(Image image,Int x,Int y)655 getPixelImage(Image image, Int x, Int y)
656 { if ( inImage(image, x, y) )
657 { Any result;
658 d_image(image, 0, 0, valInt(image->size->w), valInt(image->size->h));
659
660 if ( image->kind == NAME_bitmap )
661 result = (r_get_mono_pixel(valInt(x), valInt(y)) ? ON : OFF);
662 else
663 { unsigned long pixel;
664
665 pixel = r_get_pixel(valInt(x), valInt(y));
666 if ( pixel == NoPixel )
667 result = FAIL;
668 else
669 result = ws_pixel_to_colour(image->display, pixel);
670 }
671 d_done();
672
673 answer(result);
674 }
675
676 fail;
677 }
678
679
680 static status
maskImage(Image image,Image mask)681 maskImage(Image image, Image mask)
682 { assign(image, mask, mask);
683
684 if ( notNil(image->bitmap) )
685 updateSolidBitmap(image->bitmap);
686
687 ws_prepare_image_mask(image);
688
689 return changedEntireImageImage(image);
690 }
691
692
693 /********************************
694 * LOGICAL OPERATIONS *
695 ********************************/
696
697 static status
opImage(Image image,Image i2,Name op,Point pos)698 opImage(Image image, Image i2, Name op, Point pos)
699 { int x, y;
700
701 TRY(verifyAccessImage(image, op));
702 if ( notDefault(pos) )
703 { x = valInt(pos->x);
704 y = valInt(pos->y);
705 } else
706 x = y = 0;
707
708 CHANGING_IMAGE(image,
709 d_image(image, x, y, valInt(image->size->w), valInt(image->size->h));
710 d_modify();
711 r_op_image(i2, 0, 0, x, y, valInt(i2->size->w), valInt(i2->size->h),
712 op);
713 d_done();
714 changedEntireImageImage(image));
715
716 succeed;
717 }
718
719
720 static status
orImage(Image image,Image i2,Point pos)721 orImage(Image image, Image i2, Point pos)
722 { return opImage(image, i2, NAME_or, pos);
723 }
724
725
726 static status
andImage(Image image,Image i2,Point pos)727 andImage(Image image, Image i2, Point pos)
728 { return opImage(image, i2, NAME_and, pos);
729 }
730
731
732 static status
xorImage(Image image,Image i2,Point pos)733 xorImage(Image image, Image i2, Point pos)
734 { return opImage(image, i2, NAME_xor, pos);
735 }
736
737
738 /********************************
739 * GET SUB IMAGES *
740 ********************************/
741
742 static Image
getClipImage(Image image,Area area)743 getClipImage(Image image, Area area)
744 { int x, y, w, h;
745 Image i2;
746
747 if ( isDefault(area) )
748 { x = y = 0;
749 w = valInt(image->size->w);
750 h = valInt(image->size->h);
751 } else
752 { x = valInt(area->x); y = valInt(area->y);
753 w = valInt(area->w); h = valInt(area->h);
754 }
755
756 i2 = answerObject(ClassImage, NIL, toInt(w), toInt(h), image->kind, EAV);
757
758 if ( notNil(image->hot_spot) )
759 { int hx = valInt(image->hot_spot->x) - x;
760 int hy = valInt(image->hot_spot->y) - y;
761
762 if ( hx >= 0 && hx <= w && hy >= 0 && hy <= h )
763 assign(i2, hot_spot, newObject(ClassPoint, toInt(hx), toInt(hy), EAV));
764 }
765 if ( notNil(image->mask) )
766 assign(i2, mask, getClipImage(image->mask, area));
767
768 CHANGING_IMAGE(i2,
769 d_image(i2, 0, 0, w, h);
770 d_modify();
771 r_image(image, x, y, 0, 0, w, h, OFF);
772 d_done();
773 changedEntireImageImage(i2););
774
775 answer(i2);
776 }
777
778
779 Image
getMonochromeImage(Image image)780 getMonochromeImage(Image image)
781 { if ( image->kind == NAME_bitmap )
782 answer(image);
783
784 answer(ws_monochrome_image(image));
785 }
786
787
788 static Image
getScaleImage(Image image,Size size)789 getScaleImage(Image image, Size size)
790 { Image i2;
791
792 if ( equalSize(size, image->size) ) /* just make a copy */
793 return getClipImage(image, DEFAULT);
794 if ( size->w == ZERO || size->h == ZERO )
795 return answerObject(ClassImage, NIL, size->w, size->h, image->kind, EAV);
796
797 i2 = ws_scale_image(image, valInt(size->w), valInt(size->h));
798
799 if ( notNil(image->mask) )
800 { Image m = getScaleImage(image->mask, size);
801
802 if ( m )
803 assign(i2, mask, m);
804 }
805
806 if ( notNil(image->hot_spot) )
807 { int hx = (valInt(image->hot_spot->x) * valInt(size->w)) /
808 valInt(image->size->w);
809 int hy = (valInt(image->hot_spot->y) * valInt(size->h)) /
810 valInt(image->size->h);
811 assign(i2, hot_spot, newObject(ClassPoint, toInt(hx), toInt(hy), EAV));
812 }
813
814 answer(i2);
815 }
816
817
818 static Image
getRotateImage(Image image,Real degrees)819 getRotateImage(Image image, Real degrees)
820 { float a = (float)valReal(degrees);
821 Image rimg;
822
823 a -= (float)(((int)a / 360)*360);
824 if ( a < 0.0 ) /* normalise 0<=a<360 */
825 a += 360.0;
826 else if ( a == 0.0 ) /* just copy */
827 answer(getClipImage(image, DEFAULT));
828
829 rimg = ws_rotate_image(image, a);
830
831 if ( rimg )
832 { if ( notNil(image->hot_spot) )
833 { int hx = valInt(image->hot_spot->x);
834 int hy = valInt(image->hot_spot->y);
835 int nhx, nhy;
836 double rads = (a * M_PI) / 180.0;
837
838 nhx = rfloat((double)hx * cos(rads) + (double)hy * sin(rads));
839 nhy = rfloat((double)hy * cos(rads) - (double)hx * sin(rads));
840
841 if ( a <= 90.0 )
842 { nhy += rfloat(sin(rads) * (double)valInt(image->size->w));
843 } else if ( a <= 180.0 )
844 { nhx -= rfloat(cos(rads) * (double)valInt(image->size->w));
845 nhy += valInt(rimg->size->h);
846 } else if ( a <= 270.0 )
847 { nhx += valInt(rimg->size->w);
848 nhy -= rfloat(cos(rads) * (double)valInt(image->size->h));
849 } else
850 { nhx -= rfloat(sin(rads) * (double)valInt(image->size->h));
851 }
852
853 assign(rimg, hot_spot, newObject(ClassPoint, toInt(nhx), toInt(nhy), EAV));
854 }
855
856 if ( notNil(image->mask) )
857 assign(rimg, mask, getRotateImage(image->mask, degrees));
858 }
859
860 answer(rimg);
861 }
862
863
864 /********************************
865 * POSTSCRIPT *
866 ********************************/
867
868 static Area
getBoundingBoxImage(Image image)869 getBoundingBoxImage(Image image)
870 { answer(answerObject(ClassArea,
871 ZERO, ZERO, image->size->w, image->size->h, EAV));
872 }
873
874
875 static Int
getPostscriptDepthImage(Image image)876 getPostscriptDepthImage(Image image)
877 { if ( image->kind == NAME_bitmap )
878 return ONE;
879 if ( valInt(image->depth) < 3 ) /* 1, 2 */
880 return image->depth;
881 if ( valInt(image->depth) < 8 ) /* 3-7 */
882 return toInt(4);
883
884 return toInt(8);
885 }
886
887
888 static Int
getPostscriptFormatImage(Image image)889 getPostscriptFormatImage(Image image)
890 { if ( image->kind == NAME_bitmap )
891 return NAME_monochrome;
892 else
893 return NAME_colour; /* may also return greyscale */
894 }
895
896
897
898
899 /********************************
900 * PREDEFINED IMAGES *
901 ********************************/
902
903 #if defined(__WINDOWS__) || defined(HAVE_LIBXPM)
904 #define XPM_PCEIMAGE 1 /* use an XPM image */
905 #endif
906
907 #include "bitmaps/cycle_bm"
908 #include "bitmaps/mark_bm"
909 #include "bitmaps/nomark_bm"
910 #include "bitmaps/pullright_bm"
911 #include "bitmaps/mark_handle_bm"
912 #include "bitmaps/ms_mark.bm"
913 #include "bitmaps/ms_nomark.bm"
914 #include "bitmaps/ms_left_arrow.bm"
915 #include "bitmaps/ol_pulldown.bm"
916 #include "bitmaps/ol_pullright.bm"
917 #include "bitmaps/ol_cycle.bm"
918 #include "bitmaps/cnode.bm"
919 #include "bitmaps/enode.bm"
920 #include "bitmaps/intarrows.bm"
921
922 static Image
stdImage(Name name,Image * global,char * bits,int w,int h)923 stdImage(Name name, Image *global, char *bits, int w, int h)
924 { Image image = globalObject(name, ClassImage, name, toInt(w), toInt(h), EAV);
925
926 assign(image, access, NAME_read);
927 image->bits = alloc(sizeof(*image->bits));
928 image->bits->type = XBM_DATA;
929 image->bits->bits.xbm = (unsigned char *)bits;
930 if ( global )
931 *global = image;
932
933 return image;
934 }
935
936
937 static void
stdXPMImage(Name name,Image * global,char ** bits)938 stdXPMImage(Name name, Image *global, char **bits)
939 { int w, h, colours;
940
941 if ( sscanf(bits[0], "%d %d %d", &w, &h, &colours) == 3 )
942 { Image image = globalObject(name, ClassImage, name, toInt(w), toInt(h), EAV);
943
944 if ( colours == 2 )
945 { assign(image, depth, ONE);
946 assign(image, kind, NAME_bitmap);
947 } else
948 { assign(image, kind, NAME_pixmap);
949 }
950
951 assign(image, access, NAME_read);
952 image->bits = alloc(sizeof(*image->bits));
953 image->bits->type = XPM_DATA;
954 image->bits->bits.xpm = bits;
955
956 if ( global )
957 *global = image;
958 } else
959 Cprintf("Failed to initialise image %s\n", pp(name));
960 }
961
962
963 #ifdef XPM_PCEIMAGE
964 #include "bitmaps/swipl48.xpm"
965 #include "bitmaps/hadjusttile.xpm"
966 #include "bitmaps/vadjusttile.xpm"
967 #include "bitmaps/up.xpm"
968 #include "bitmaps/down.xpm"
969 #include "bitmaps/left.xpm"
970 #include "bitmaps/right.xpm"
971 #include "bitmaps/exclamation.xpm"
972 #else
973 #include "bitmaps/pce.bm"
974 #endif
975
976 #include "bitmaps/white_bm"
977 #include "bitmaps/grey12_bm"
978 #include "bitmaps/grey25_bm"
979 #include "bitmaps/grey50_bm"
980 #include "bitmaps/grey75_bm"
981 #include "bitmaps/black_bm"
982
983 static void
greyImage(Name name,int grey,Image * global,char * bits,int w,int h)984 greyImage(Name name, int grey, Image *global,
985 char *bits, int w, int h)
986 { Image image;
987
988 image = stdImage(name, global, bits, w, h);
989
990 attributeObject(image, NAME_postscriptGrey, toInt(grey));
991 }
992
993
994 static void
standardImages(void)995 standardImages(void)
996 { greyImage(NAME_whiteImage, 0, &WHITE_IMAGE,
997 white_bm_bits, white_bm_width, white_bm_height);
998 greyImage(NAME_grey12Image, 12, &GREY12_IMAGE,
999 grey12_bm_bits, grey12_bm_width, grey12_bm_height);
1000 greyImage(NAME_grey25Image, 25, &GREY25_IMAGE,
1001 grey25_bm_bits, grey25_bm_width, grey25_bm_height);
1002 greyImage(NAME_grey50Image, 50, &GREY50_IMAGE,
1003 grey50_bm_bits, grey50_bm_width, grey50_bm_height);
1004 greyImage(NAME_grey75Image, 75, &GREY75_IMAGE,
1005 grey75_bm_bits, grey75_bm_width, grey75_bm_height);
1006 greyImage(NAME_blackImage, 100, &BLACK_IMAGE,
1007 black_bm_bits, black_bm_width, black_bm_height);
1008
1009 stdImage(NAME_cycleImage, &CYCLE_IMAGE,
1010 cycle_bm_bits, cycle_bm_width, cycle_bm_height);
1011 stdImage(NAME_markImage, &MARK_IMAGE,
1012 mark_bm_bits, mark_bm_width, mark_bm_height);
1013 stdImage(NAME_nomarkImage, &NOMARK_IMAGE,
1014 nomark_bm_bits, nomark_bm_width, nomark_bm_height);
1015 stdImage(NAME_msMarkImage, &MS_MARK_IMAGE,
1016 (char *)ms_mark_bits, ms_mark_width, ms_mark_height);
1017 stdImage(NAME_msNomarkImage, &MS_NOMARK_IMAGE,
1018 (char *)ms_nomark_bits, ms_nomark_width, ms_nomark_height);
1019 stdImage(NAME_msLeftArrowImage, NULL,
1020 (char *)ms_left_arrow_bits, ms_left_arrow_width, ms_left_arrow_height);
1021 stdImage(NAME_pullRightImage, &PULLRIGHT_IMAGE,
1022 pullright_bm_bits, pullright_bm_width, pullright_bm_height);
1023 stdImage(NAME_markHandleImage, &MARK_HANDLE_IMAGE,
1024 mark_handle_bm_bits, mark_handle_bm_width, mark_handle_bm_height);
1025 stdImage(NAME_olPullrightImage, NULL,
1026 ol_pullright_bits, ol_pullright_width, ol_pullright_height);
1027 stdImage(NAME_olPulldownImage, NULL,
1028 ol_pulldown_bits, ol_pulldown_width, ol_pulldown_height);
1029 stdImage(NAME_olCycleImage, NULL,
1030 ol_cycle_bits, ol_cycle_width, ol_cycle_height);
1031 stdImage(NAME_treeExpandedImage, NULL,
1032 (char*)enode_bits, enode_width, enode_height);
1033 stdImage(NAME_treeCollapsedImage, NULL,
1034 (char*)cnode_bits, cnode_width, cnode_height);
1035 stdImage(NAME_intItemImage, &INT_ITEM_IMAGE,
1036 (char*)intarrows_bits, intarrows_width, intarrows_height);
1037 #ifdef XPM_PCEIMAGE
1038 stdXPMImage(NAME_pceImage, NULL, swipl48_xpm);
1039 stdXPMImage(NAME_hadjustTileImage, NULL, hadjusttile_xpm);
1040 stdXPMImage(NAME_vadjustTileImage, NULL, vadjusttile_xpm);
1041 stdXPMImage(NAME_scrollUpImage, &SCROLL_UP_IMAGE, up_xpm);
1042 stdXPMImage(NAME_scrollDownImage, &SCROLL_DOWN_IMAGE, down_xpm);
1043 stdXPMImage(NAME_scrollLeftImage, &SCROLL_LEFT_IMAGE, left_xpm);
1044 stdXPMImage(NAME_scrollRightImage, &SCROLL_RIGHT_IMAGE, right_xpm);
1045 stdXPMImage(NAME_exclamationImage, &EXCLAMATION_IMAGE, exclamation_xpm);
1046 #else
1047 stdImage(NAME_pceImage, NULL,
1048 pce_bm_bits, pce_bm_width, pce_bm_height);
1049 #endif
1050
1051 stdImage(NAME_nullImage, &NULL_IMAGE,
1052 NULL, 0, 0);
1053
1054 ws_system_images(); /* make sure system images exist */
1055 }
1056
1057
1058 /*******************************
1059 * CLASS DECLARATION *
1060 *******************************/
1061
1062 /* Type declarations */
1063
1064 static char *T_load[] =
1065 { "from=[source_sink]", "path=[char_array]" };
1066 static char *T_drawIn[] =
1067 { "graphical", "at=[point]" };
1068 static char *T_fill[] =
1069 { "image", "[area]" };
1070 static char *T_initialise[] =
1071 { "name=[source_sink]*", "width=[int]", "height=[int]",
1072 "kind=[{bitmap,pixmap}]" };
1073 static char *T_image_atADpointD[] =
1074 { "image", "at=[point]" };
1075 static char *T_save[] =
1076 { "in=[source_sink]", "format=[{xbm,xpm,pnm,pbm,pgm,ppm,jpeg,gif}]" };
1077 static char *T_postscript[] =
1078 { "landscape=[bool]", "maximum_area=[area]" };
1079 static char *T_resize[] =
1080 { "width=int", "height=int" };
1081 static char *T_xAint_yAint[] =
1082 { "x=int", "y=int" };
1083 static char *T_pixel[] =
1084 { "x=int", "y=int", "value=colour|bool" };
1085 #ifdef O_XLI
1086 static char *T_loadXli[] =
1087 { "file=file", "bright=[0..]" };
1088 #endif
1089
1090 /* Instance Variables */
1091
1092 static vardecl var_image[] =
1093 { IV(NAME_name, "name*", IV_GET,
1094 NAME_name, "Name of the image"),
1095 IV(NAME_kind, "{bitmap,pixmap}", IV_GET,
1096 NAME_colour, "`bitmap' (0 and 1's) or `pixmap' (coloured)"),
1097 IV(NAME_file, "source_sink*", IV_GET,
1098 NAME_file, "Source (file,resource) from which to load"),
1099 IV(NAME_access, "{read,both}", IV_GET,
1100 NAME_permission, "One of {read, both}"),
1101 IV(NAME_background, "[colour|pixmap]", IV_BOTH,
1102 NAME_colour, "Colour of background (pixmap)"),
1103 IV(NAME_foreground, "[colour|pixmap]", IV_BOTH,
1104 NAME_colour, "Colour of foreground (pixmap)"),
1105 IV(NAME_depth, "[int]", IV_GET,
1106 NAME_colour, "Number of bits/pixel"),
1107 IV(NAME_size, "size", IV_GET,
1108 NAME_dimension, "Size of the image in pixels"),
1109 IV(NAME_display, "display*", IV_GET,
1110 NAME_organisation, "X-Display this image belongs to"),
1111 IV(NAME_bitmap, "bitmap*", IV_GET,
1112 NAME_organisation, "Access both and displayed on this bitmap"),
1113 IV(NAME_hotSpot, "point*", IV_BOTH,
1114 NAME_dimension, "Hot-spot position"),
1115 SV(NAME_mask, "image*", IV_GET|IV_STORE, maskImage,
1116 NAME_area, "Image for masked painting"),
1117 IV(NAME_wsRef, "alien:WsRef", IV_NONE,
1118 NAME_storage, "Window System Reference"),
1119 IV(NAME_bits, "alien:char*", IV_NONE,
1120 NAME_storage, "Data for built-in images")
1121 };
1122
1123 /* Send Methods */
1124
1125 #ifdef O_XLI
1126 extern status loadXliImage(Image image, FileObj file, Int bright);
1127 #endif
1128
1129 static senddecl send_image[] =
1130 { SM(NAME_initialise, 4, T_initialise, initialiseImage,
1131 DEFAULT, "Create from name, [width, height, kind]"),
1132 SM(NAME_unlink, 0, NULL, unlinkImage,
1133 DEFAULT, "Destroy private memory and window-system resources"),
1134 SM(NAME_copy, 1, "from=image", copyImage,
1135 NAME_copy, "Copy contents of argument in image"),
1136 SM(NAME_drawIn, 2, T_drawIn, drawInImage,
1137 NAME_copy, "Paint graphical in image [at point]"),
1138 SM(NAME_resize, 2, T_resize, resizeImage,
1139 NAME_dimension, "Resize image to width, height"),
1140 SM(NAME_and, 2, T_image_atADpointD, andImage,
1141 NAME_edit, "Bitwise and with argument"),
1142 SM(NAME_clear, 0, NULL, clearImage,
1143 NAME_edit, "Clear all pixels to 0 or <-background"),
1144 SM(NAME_fill, 2, T_fill, fillImage,
1145 NAME_edit, "Fill rectangular area of image with pattern"),
1146 SM(NAME_invert, 0, NULL, invertImage,
1147 NAME_edit, "Invert all pixels in image"),
1148 SM(NAME_or, 2, T_image_atADpointD, orImage,
1149 NAME_edit, "Bitwise or with argument"),
1150 SM(NAME_xor, 2, T_image_atADpointD, xorImage,
1151 NAME_edit, "Bitwise xor with argument"),
1152 SM(NAME_load, 2, T_load, loadImage,
1153 NAME_file, "Load image from file (searching in path)"),
1154 #ifdef O_XLI
1155 SM(NAME_loadXli, 2, T_loadXli, loadXliImage,
1156 NAME_file, "Load image using xli library"),
1157 #endif
1158 SM(NAME_save, 2, T_save, saveImage,
1159 NAME_file, "Save image to file in specified format"),
1160 SM(NAME_clearPixel, 2, T_xAint_yAint, clearPixelImage,
1161 NAME_pixel, "Clear pixel at x-y (to 0 or background)"),
1162 SM(NAME_invertPixel, 2, T_xAint_yAint, invertPixelImage,
1163 NAME_pixel, "Invert pixel at x-y"),
1164 SM(NAME_pixel, 3, T_pixel, pixelImage,
1165 NAME_pixel, "Set pixel at x-y to bool or colour"),
1166 SM(NAME_setPixel, 2, T_xAint_yAint, setPixelImage,
1167 NAME_pixel, "Set pixel at x-y (to 1 or foreground)"),
1168 SM(NAME_Postscript, 1, "{head,body}", drawPostScriptImage,
1169 NAME_postscript, "Create PostScript"),
1170 SM(NAME_DrawPostScript, 1, "{head,body}", drawPostScriptImage,
1171 NAME_postscript, "Create PostScript"),
1172 SM(NAME_Xclose, 1, "display", XcloseImage,
1173 NAME_x, "Destroy associated window-system resources"),
1174 SM(NAME_Xopen, 1, "display", XopenImage,
1175 NAME_x, "Open X-image")
1176 };
1177
1178 /* Get Methods */
1179
1180 static getdecl get_image[] =
1181 { GM(NAME_containedIn, 0, "bitmap", NULL, getContainedInImage,
1182 DEFAULT, "Equivalent to <-bitmap if ot @nil"),
1183 GM(NAME_convert, 1, "image", "bitmap|name|resource|graphical", getConvertImage,
1184 DEFAULT, "Convert bitmap or (file-)name"),
1185 GM(NAME_clip, 1, "image", "[area]", getClipImage,
1186 NAME_copy, "Get a subimage"),
1187 GM(NAME_monochrome, 0, "image", NULL, getMonochromeImage,
1188 NAME_copy, "Get monochrome version of pixmap image"),
1189 GM(NAME_scale, 1, "image", "size", getScaleImage,
1190 NAME_copy, "Get copy with different dimensions"),
1191 GM(NAME_rotate, 1, "image", "degrees=real", getRotateImage,
1192 NAME_copy, "Get anti-clockwise rotated copy"),
1193 GM(NAME_lookup, 1, "image", "name|resource", getLookupImage,
1194 NAME_oms, "Lookup in @images table"),
1195 GM(NAME_pixel, 2, "value=bool|colour", T_xAint_yAint, getPixelImage,
1196 NAME_pixel, "Get 0-1 (image) or colour for x-y"),
1197 GM(NAME_colourMap, 0, "colour_map", NULL, getColourMapImage,
1198 NAME_colour, "New colour_map for best display of image"),
1199 GM(NAME_boundingBox, 0, "area", NULL, getBoundingBoxImage,
1200 NAME_postscript, "BoundingBox for PostScript generation"),
1201 GM(NAME_postscript, 2, "string", T_postscript, getPostscriptObject,
1202 NAME_postscript, "New string holding PostScript description"),
1203 GM(NAME_postscriptDepth, 0, "int", NULL, getPostscriptDepthImage,
1204 NAME_postscript, "Depth for PostScript image to be generated"),
1205 GM(NAME_postscriptFormat, 0, "{monochrome,greyscale,colour}",
1206 NULL, getPostscriptFormatImage,
1207 NAME_postscript, "Format of generated PostScript")
1208 };
1209
1210 /* Resources */
1211
1212 static classvardecl rc_image[] =
1213 { RC(NAME_path, "string",
1214 "\".:bitmaps:~/lib/bitmaps:$PCEHOME/bitmaps:" /* concat */
1215 "/usr/include/X11/bitmaps\"",
1216 "Search path for loading images")
1217 };
1218
1219 /* Class Declaration */
1220
1221 static Name image_termnames[] = { NAME_name };
1222
1223 ClassDecl(image_decls,
1224 var_image, send_image, get_image, rc_image,
1225 1, image_termnames,
1226 "$Rev$");
1227
1228
1229 status
makeClassImage(Class class)1230 makeClassImage(Class class)
1231 { declareClass(class, &image_decls);
1232
1233 saveStyleClass(class, NAME_external);
1234 setLoadStoreFunctionClass(class, loadFdImage, storeImage);
1235 cloneStyleClass(class, NAME_none); /* just copy reference */
1236
1237 ImageTable = globalObject(NAME_images, ClassHashTable, toInt(32), EAV);
1238 standardImages();
1239
1240 succeed;
1241 }
1242
1243