1 /** pixBuf.c
2 \brief pixBufs are offscreen drawables.
3 \author William J Giddings email: wjgiddings@blueyonder.co.uk
4 \date 17-Jan-2010
5 \version 0.9.95
6 \note Module generated by gnocl_template_assistant.
7 \bugs SVG rotation and composition produce errors.
8 \history
9 2013-07: added commands, options, commands
10 02/06/11 implemented PixbufParams, create pixbuf with
11 assocated Cairo surface
12 06/09/10 composite -completed implementation of all options
13 17/08/10 pixbuf commands
14 snapshot
15 screenshot
16 09/04/10 pixbuf command
17 duplicate
18 15/03/10 pixbuf command
19 info
20 05/03/10
21 pixbuf command
22 setPixel
23 02/03/10 pixbuf command
24 get drawable | image
25 render
26 26/02/10 pixbuf command
27 subpixbuf
28 20/02/10 pixbuf command
29 copy
30 16/02/10 pixbuf command
31 draw
32 15/02/10 pixbuf commands
33 composite
34 resize
35 scale
36 14/02/10 pixbuf commands
37 turn
38 flip
39 rotate
40 commands
41 load
42
43 13/02/10 pixbuf commands
44 save
45 fill
46 class
47 12/02/10 commands
48 new
49 11/02/10 commands
50 types
51 description <type>
52 license | licence <type>
53 extension <type>
54 scaleble <type>
55 writable <type>
56 fileInfo <fileName>
57 \todo
58 1) Resolve what acolor actually does.
59 2) Perform alpha channel operations.
60 set, erase, get
61 **/
62
63 /**
64 \page page_pixbuf gnocl::pixBuf
65 \htmlinclude pixbuf.html
66 **/
67
68 #include "gnocl.h"
69 #include "gnoclparams.h"
70 #include "gnocl_logo.h"
71 #include "gnocl_pointer.h"
72
73
74 /*****************
75 * relocated from cairo.c
76 * used to draw splash screen
77 ******************************/
78
79 static gchar *dash;
80
81 /* Key for automated pixbuf updating and destruction */
82 static const cairo_user_data_key_t pixbuf_key;
83
84 cairo_t *gnoclPixbufCairoCreate ( GdkPixbuf *pixbuf );
85 GdkPixbuf *gnoclPixbufCairoDestroy ( cairo_t *cr, gboolean create_new_pixbuf );
86
87 /* Key for automated pixbuf updating and destruction */
88 static const cairo_user_data_key_t pixbuf_key;
89
90 void gdk_pixbuf_get_pixel ( GdkPixbuf * pixbuf, guint x, guint y , guchar * r, guchar * g, guchar * b, guchar * a );
91 void gdk_pixbuf_set_pixel ( GdkPixbuf * pixbuf, guint32 pixel, guint x, guint y );
92
93
94 /**
95 \brief This function will initialize new cairo context with contents of
96 @pixbuf. You can then draw using returned context. When finished
97 drawing, you must call gnoclPixbufCairoDestroy() or your pixbuf
98 will not be updated with new contents!
99
100 Return value: New cairo_t context. When you're done with it, call
101 gnoclPixbufCairoDestroy() to update your pixbuf and free memory.
102 **/
gnoclPixbufCairoCreate(GdkPixbuf * pixbuf)103 cairo_t * gnoclPixbufCairoCreate ( GdkPixbuf *pixbuf )
104 {
105
106 gint width; /* Width of both pixbuf and surface */
107 gint height; /* Height of both pixbuf and surface */
108 gint p_stride; /* Pixbuf stride value */
109 gint p_n_channels; /* RGB -> 3, RGBA -> 4 */
110 gint s_stride; /* Surface stride value */
111 guchar *p_pixels; /* Pixbuf's pixel data */
112 guchar *s_pixels; /* Surface's pixel data */
113 cairo_surface_t *surface; /* Temporary image surface */
114 cairo_t *cr; /* Final context */
115
116 g_object_ref ( G_OBJECT ( pixbuf ) );
117
118 /* Inspect input pixbuf and create compatible cairo surface */
119 g_object_get ( G_OBJECT ( pixbuf ),
120 "width", &width,
121 "height", &height,
122 "rowstride", &p_stride,
123 "n-channels", &p_n_channels,
124 "pixels", &p_pixels,
125 NULL );
126 surface = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32, width, height );
127 s_stride = cairo_image_surface_get_stride ( surface );
128 s_pixels = cairo_image_surface_get_data ( surface );
129
130 /* Copy pixel data from pixbuf to surface */
131 while ( height-- )
132 {
133 gint i;
134 guchar *p_iter = p_pixels, *s_iter = s_pixels;
135
136 for ( i = 0; i < width; i++ )
137 {
138 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
139
140 /* Pixbuf: RGB(A)
141 * Surface: BGRA */
142 if ( p_n_channels == 3 )
143 {
144 s_iter[0] = p_iter[2];
145 s_iter[1] = p_iter[1];
146 s_iter[2] = p_iter[0];
147 s_iter[3] = 0xff;
148 }
149
150 else /* p_n_channels == 4 */
151 {
152 gdouble alpha_factor = p_iter[3] / ( gdouble ) 0xff;
153
154 s_iter[0] = ( guchar ) ( p_iter[2] * alpha_factor + .5 );
155 s_iter[1] = ( guchar ) ( p_iter[1] * alpha_factor + .5 );
156 s_iter[2] = ( guchar ) ( p_iter[0] * alpha_factor + .5 );
157 s_iter[3] = p_iter[3];
158 }
159
160 #elif G_BYTE_ORDER == G_BIG_ENDIAN
161
162 /* Pixbuf: RGB(A)
163 * Surface: ARGB */
164 if ( p_n_channels == 3 )
165 {
166 s_iter[3] = p_iter[2];
167 s_iter[2] = p_iter[1];
168 s_iter[1] = p_iter[0];
169 s_iter[0] = 0xff;
170 }
171
172 else /* p_n_channels == 4 */
173 {
174 gdouble alpha_factor = p_iter[3] / ( gdouble ) 0xff;
175
176 s_iter[3] = ( guchar ) ( p_iter[2] * alpha_factor + .5 );
177 s_iter[2] = ( guchar ) ( p_iter[1] * alpha_factor + .5 );
178 s_iter[1] = ( guchar ) ( p_iter[0] * alpha_factor + .5 );
179 s_iter[0] = p_iter[3];
180 }
181
182 #else /* PDP endianness */
183
184 /* Pixbuf: RGB(A)
185 * Surface: RABG */
186 if ( p_n_channels == 3 )
187 {
188 s_iter[0] = p_iter[0];
189 s_iter[1] = 0xff;
190 s_iter[2] = p_iter[2];
191 s_iter[3] = p_iter[1];
192 }
193
194 else /* p_n_channels == 4 */
195 {
196 gdouble alpha_factor = p_iter[3] / ( gdouble ) 0xff;
197
198 s_iter[0] = ( guchar ) ( p_iter[0] * alpha_factor + .5 );
199 s_iter[1] = p_iter[3];
200 s_iter[1] = ( guchar ) ( p_iter[2] * alpha_factor + .5 );
201 s_iter[2] = ( guchar ) ( p_iter[1] * alpha_factor + .5 );
202 }
203
204 #endif
205 s_iter += 4;
206 p_iter += p_n_channels;
207 }
208
209 s_pixels += s_stride;
210 p_pixels += p_stride;
211 }
212
213 /* Create context and set user data */
214 cr = cairo_create ( surface );
215 cairo_surface_destroy ( surface );
216 cairo_set_user_data ( cr, &pixbuf_key, pixbuf, g_object_unref );
217
218 /* Return context */
219 return ( cr );
220 }
221
222 /**
223
224 \note If TRUE, new pixbuf will be created and returned.
225 If FALSE, input pixbuf will be updated in place.
226 \brief This function will destroy cairo context, created with gnoclPixbufCairoCreate().
227
228 Return value: New or updated GdkPixbuf. You own a new reference on return
229 value, so you need to call g_object_unref() on returned pixbuf when you don't
230 need it anymore.
231 **/
gnoclPixbufCairoDestroy(cairo_t * cr,gboolean create_new_pixbuf)232 GdkPixbuf *gnoclPixbufCairoDestroy ( cairo_t *cr, gboolean create_new_pixbuf )
233 {
234 gint width; /* Width of both pixbuf and surface */
235 gint height; /* Height of both pixbuf and surface */
236 gint p_stride; /* Pixbuf stride value */
237 gint p_n_channels; /* RGB -> 3, RGBA -> 4 */
238 gint s_stride; /* Surface stride value */
239 guchar *p_pixels; /* Pixbuf's pixel data */
240 guchar *s_pixels; /* Surface's pixel data */
241 cairo_surface_t *surface; /* Temporary image surface */
242 GdkPixbuf *pixbuf; /* Pixbuf to be returned */
243 GdkPixbuf *tmp_pix; /* Temporary storage */
244
245 /* Obtain pixbuf to be returned */
246 tmp_pix = cairo_get_user_data ( cr, &pixbuf_key );
247
248 if ( create_new_pixbuf )
249 {
250 pixbuf = gdk_pixbuf_copy ( tmp_pix );
251 }
252
253 else
254 {
255 pixbuf = g_object_ref ( G_OBJECT ( tmp_pix ) );
256 }
257
258 /* Obtain surface from where pixel values will be copied */
259 surface = cairo_get_target ( cr );
260
261 /* Inspect pixbuf and surface */
262 g_object_get ( G_OBJECT ( pixbuf ), "width", &width, "height", &height, "rowstride", &p_stride,
263 "n-channels", &p_n_channels, "pixels", &p_pixels, NULL );
264 s_stride = cairo_image_surface_get_stride ( surface );
265 s_pixels = cairo_image_surface_get_data ( surface );
266
267 /* Copy pixel data from surface to pixbuf */
268 while ( height-- )
269 {
270 gint i;
271 guchar *p_iter = p_pixels,
272 *s_iter = s_pixels;
273
274 for ( i = 0; i < width; i++ )
275 {
276 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
277 /* Pixbuf: RGB(A)
278 * Surface: BGRA */
279 gdouble alpha_factor = ( gdouble ) 0xff / s_iter[3];
280
281 p_iter[0] = ( guchar ) ( s_iter[2] * alpha_factor + .5 );
282 p_iter[1] = ( guchar ) ( s_iter[1] * alpha_factor + .5 );
283 p_iter[2] = ( guchar ) ( s_iter[0] * alpha_factor + .5 );
284
285 if ( p_n_channels == 4 )
286 p_iter[3] = s_iter[3];
287
288 #elif G_BYTE_ORDER == G_BIG_ENDIAN
289 /* Pixbuf: RGB(A)
290 * Surface: ARGB */
291 gdouble alpha_factor = ( gdouble ) 0xff / s_iter[0];
292
293 p_iter[0] = ( guchar ) ( s_iter[1] * alpha_factor + .5 );
294 p_iter[1] = ( guchar ) ( s_iter[2] * alpha_factor + .5 );
295 p_iter[2] = ( guchar ) ( s_iter[3] * alpha_factor + .5 );
296
297 if ( p_n_channels == 4 )
298 p_iter[3] = s_iter[0];
299
300 #else /* PDP endianness */
301 /* Pixbuf: RGB(A)
302 * Surface: RABG */
303 gdouble alpha_factor = ( gdouble ) 0xff / s_iter[1];
304
305 p_iter[0] = ( guchar ) ( s_iter[0] * alpha_factor + .5 );
306 p_iter[1] = ( guchar ) ( s_iter[3] * alpha_factor + .5 );
307 p_iter[2] = ( guchar ) ( s_iter[2] * alpha_factor + .5 );
308
309 if ( p_n_channels == 4 )
310 p_iter[3] = s_iter[1];
311
312 #endif
313 s_iter += 4;
314 p_iter += p_n_channels;
315 }
316
317 s_pixels += s_stride;
318 p_pixels += p_stride;
319 }
320
321 /* Destroy context */
322 cairo_destroy ( cr );
323
324 /* Return pixbuf */
325 return ( pixbuf );
326 }
327
328
329 /**********************************************************************/
330
331
332 PixbufParams *gnoclGetPixBufFromName ( const char *id, Tcl_Interp *interp );
333 const char *gnoclGetNameFromPixBuf ( GdkPixbuf *pixbuf );
334 guint32 convertRGBtoPixel ( gchar *clr );
335 static void set_pixel_color ( GdkPixbuf *pixbuf, int x, int y, guchar red, guchar green, guchar blue, guchar alpha );
336 //static guchar * create_gradient ( const GdkColor *primary, const GdkColor *secondary, int n_pixels );
337
338
339 /* needs to be public to be accessed by gnocl::inventory */
340 static GHashTable *name2pixbufList;
341 static const char idPrefix[] = "::gnocl::_PBUF";
342
343 int gnoclOptOrientatePixBuf ( Tcl_Interp *interp, GnoclOption *opt, GObject *obj, Tcl_Obj **ret );
344
345 /*
346 canpixbufs be created and modified using standard properties?
347 */
348 static GnoclOption pixBufOptions[] =
349 {
350 { "-width", GNOCL_OBJ, "width"}, /* 0 */
351 { "-height", GNOCL_OBJ, "height"}, /* 1 */
352 { "-bitsPerSample", GNOCL_OBJ, "bits-per-sample"}, /* 2 */
353 { "-alpha", GNOCL_OBJ, "has-alpha"}, /* 3 */
354 { "-colorspace", GNOCL_OBJ, "colorspace"}, /* 4 */
355 { "-nChannels", GNOCL_OBJ, "n-channels"}, /* 5*/
356 { "-orientate", GNOCL_OBJ, gnoclOptOrientatePixBuf},
357
358 /* GtkObject Properties */
359 { "-data", GNOCL_OBJ, "", gnoclOptData },
360
361 { NULL }
362 };
363
364 static const int aIdx = 0;
365 static const int bIdx = 1;
366 static const int cIdx = 2;
367 static const int dIdx = 3;
368 static const int eIdx = 4;
369 static const int fIdx = 5;
370
371
372 /**
373 \note Code taken from gnome-bg.c
374 **/
create_gradient(const GdkColor * primary,const GdkColor * secondary,int n_pixels)375 guchar * create_gradient ( const GdkColor *primary, const GdkColor *secondary, int n_pixels )
376 {
377 guchar *result = g_malloc ( n_pixels * 3 );
378 int i;
379
380 for ( i = 0; i < n_pixels; ++i )
381 {
382 double ratio = ( i + 0.5 ) / n_pixels;
383
384 result[3 * i + 0] = ( ( guint16 ) ( primary->red * ( 1 - ratio ) + secondary->red * ratio ) ) >> 8;
385 result[3 * i + 1] = ( ( guint16 ) ( primary->green * ( 1 - ratio ) + secondary->green * ratio ) ) >> 8;
386 result[3 * i + 2] = ( ( guint16 ) ( primary->blue * ( 1 - ratio ) + secondary->blue * ratio ) ) >> 8;
387 }
388
389 return result;
390 }
391
392 /**
393 \note Code taken from gnome-bg.c
394 **/
pixbuf_draw_gradient(GdkPixbuf * pixbuf,gboolean horizontal,GdkColor * primary,GdkColor * secondary,GdkRectangle * rect)395 static void pixbuf_draw_gradient ( GdkPixbuf *pixbuf, gboolean horizontal, GdkColor *primary, GdkColor *secondary, GdkRectangle *rect )
396 {
397 int width;
398 int height;
399 int rowstride;
400 guchar *dst;
401 guchar *dst_limit;
402 int n_channels = 3;
403
404 rowstride = gdk_pixbuf_get_rowstride ( pixbuf );
405 width = rect->width;
406 height = rect->height;
407 dst = gdk_pixbuf_get_pixels ( pixbuf ) + rect->x * n_channels + rowstride * rect->y;
408 dst_limit = dst + height * rowstride;
409
410 if ( horizontal )
411 {
412 guchar *gradient = create_gradient ( primary, secondary, width );
413 int copy_bytes_per_row = width * n_channels;
414 int i;
415
416 for ( i = 0; i < height; i++ )
417 {
418 guchar *d;
419 d = dst + rowstride * i;
420 memcpy ( d, gradient, copy_bytes_per_row );
421 }
422
423 g_free ( gradient );
424 }
425
426 else
427 {
428 guchar *gb, *gradient;
429 int i;
430
431 gradient = create_gradient ( primary, secondary, height );
432
433 for ( i = 0; i < height; i++ )
434 {
435 int j;
436 guchar *d;
437
438 d = dst + rowstride * i;
439 gb = gradient + n_channels * i;
440
441 for ( j = width; j > 0; j-- )
442 {
443 int k;
444
445 for ( k = 0; k < n_channels; k++ )
446 {
447 * ( d++ ) = gb[k];
448 }
449 }
450 }
451
452 g_free ( gradient );
453 }
454 }
455
456 /**
457 \note Code taken from gnome-bg.c
458 **/
pixbuf_blend(GdkPixbuf * src,GdkPixbuf * dest,int src_x,int src_y,int src_width,int src_height,int dest_x,int dest_y,double alpha)459 static void pixbuf_blend ( GdkPixbuf *src, GdkPixbuf *dest, int src_x, int src_y, int src_width, int src_height, int dest_x, int dest_y, double alpha )
460 {
461 int dest_width = gdk_pixbuf_get_width ( dest );
462 int dest_height = gdk_pixbuf_get_height ( dest );
463 int offset_x = dest_x - src_x;
464 int offset_y = dest_y - src_y;
465
466 if ( src_width < 0 )
467 src_width = gdk_pixbuf_get_width ( src );
468
469 if ( src_height < 0 )
470 src_height = gdk_pixbuf_get_height ( src );
471
472 if ( dest_x < 0 )
473 dest_x = 0;
474
475 if ( dest_y < 0 )
476 dest_y = 0;
477
478 if ( dest_x + src_width > dest_width )
479 {
480 src_width = dest_width - dest_x;
481 }
482
483 if ( dest_y + src_height > dest_height )
484 {
485 src_height = dest_height - dest_y;
486 }
487
488 gdk_pixbuf_composite ( src, dest,
489 dest_x, dest_y,
490 src_width, src_height,
491 offset_x, offset_y,
492 1, 1, GDK_INTERP_NEAREST,
493 alpha * 0xFF + 0.5 );
494 }
495
496 /**
497 \note Code taken from gnome-bg.c
498 **/
pixbuf_tile(GdkPixbuf * src,GdkPixbuf * dest)499 static void pixbuf_tile ( GdkPixbuf *src, GdkPixbuf *dest )
500 {
501 int x, y;
502 int tile_width, tile_height;
503 int dest_width = gdk_pixbuf_get_width ( dest );
504 int dest_height = gdk_pixbuf_get_height ( dest );
505
506 tile_width = gdk_pixbuf_get_width ( src );
507 tile_height = gdk_pixbuf_get_height ( src );
508
509 for ( y = 0; y < dest_height; y += tile_height )
510 {
511 for ( x = 0; x < dest_width; x += tile_width )
512 {
513 pixbuf_blend ( src, dest, 0, 0,
514 tile_width, tile_height, x, y, 1.0 );
515 }
516 }
517 }
518
519 /**
520 \note Code taken from gnome-bg.c
521 **/
pixbuf_clip_to_fit(GdkPixbuf * src,int max_width,int max_height)522 static GdkPixbuf * pixbuf_clip_to_fit ( GdkPixbuf *src, int max_width, int max_height )
523 {
524 int src_width, src_height;
525 int w, h;
526 int src_x, src_y;
527 GdkPixbuf *pixbuf;
528
529 src_width = gdk_pixbuf_get_width ( src );
530 src_height = gdk_pixbuf_get_height ( src );
531
532 if ( src_width < max_width && src_height < max_height )
533 return g_object_ref ( src );
534
535 w = MIN ( src_width, max_width );
536 h = MIN ( src_height, max_height );
537
538 pixbuf = gdk_pixbuf_new ( GDK_COLORSPACE_RGB,
539 gdk_pixbuf_get_has_alpha ( src ),
540 8, w, h );
541
542 src_x = ( src_width - w ) / 2;
543 src_y = ( src_height - h ) / 2;
544 gdk_pixbuf_copy_area ( src,
545 src_x, src_y,
546 w, h,
547 pixbuf,
548 0, 0 );
549 return pixbuf;
550 }
551
552
553 /**
554 \brief Takes an existing pixbuf and checks for the presence of an
555 associated "orientation" option, which may be provided by the
556 jpeg loader (which reads the exif orientation tag) or the tiff
557 loader (which reads the tiff orientation tag, and compensates it
558 for the partial transforms performed by libtiff). If an
559 orientation option/tag is present, the appropriate transform
560 will be performed so that the pixbuf is oriented correctly.
561
562 **/
gnoclOptOrientatePixBuf(Tcl_Interp * interp,GnoclOption * opt,GObject * obj,Tcl_Obj ** ret)563 int gnoclOptOrientatePixBuf ( Tcl_Interp *interp, GnoclOption *opt, GObject *obj, Tcl_Obj **ret )
564 {
565
566 //GdkPixbuf * gdk_pixbuf_apply_embedded_orientation (GdkPixbuf *src);
567 }
568
569 /**
570 \brief
571 **/
gnoclGetPixBufList(GList ** list)572 void gnoclGetPixBufList ( GList **list )
573 {
574 g_hash_table_foreach ( name2pixbufList, hash_to_list, list );
575 }
576
577 /**
578 \brief Rotate a pixbuf through an arbitrary angle (degrees).
579 \author
580 \date 15/Feb/2010
581 \since 0.9.94
582 \note Adaption of:
583 GdkPixbuf * gdk_pixbuf_rotate(GdkPixbuf *pixbuf, double angle, int acolor)
584
585 The returned image has the same size as the original, but the
586 pixbuf envelope is increased to accomodate the rotated original
587 (e.g. a 100x100 pixbuf rotated 45 deg. needs a 142x142 pixbuf).
588
589 Pixels added around the rotated image have all RGB values = acolor. // v.2.17
590
591 Angle is in degrees. Positive direction is clockwise.
592 Pixbuf must have 8 bits per channel and 3 or 4 channels.
593 Loss of resolution is about 1/2 pixel.
594 Speed is about 18 million pixels/sec. on my 2.67 GHz CPU. // v.3.2
595
596 NULL is returned if the function fails for one of the following:
597 - pixbuf not 8 bits/channel or < 3 channels
598 - unable to create output pixbuf (lack of memory?)
599
600 Algorithm:
601 create output pixbuf big enough for rotated input pixbuf
602 compute coefficients for affine transform
603 loop all output pixels
604 get next output pixel (px2,py2)
605 convert to input pixel (px1,py1) using affine transform // v.3.2
606 if outside of pixmap
607 output pixel = black
608 continue
609 for 4 input pixels based at (px0,py0) = (int(px1),int(py1))
610 compute overlap (0 to 1) with (px1,py1)
611 sum RGB values * overlap
612 output aggregate RGB to pixel (px2,py2)
613 \see http://kornelix.squarespace.com
614
615 Note: Not really certain what the acolor variable actually does.
616
617 **/
pixbufRotate(GdkPixbuf * pixbuf1,double angle,int acolor)618 GdkPixbuf * pixbufRotate ( GdkPixbuf *pixbuf1, double angle, int acolor )
619 {
620
621 g_print ( "%s 1 %f\n", __FUNCTION__, angle );
622
623 /* 3 RGB values, 0-255 each */
624 typedef unsigned char *pixel;
625
626 GdkPixbuf *pixbuf2;
627 GdkColorspace color;
628
629 int nch, nbits, alpha;
630 int ww1, hh1, rs1, ww2, hh2, rs2;
631 int px2, py2, px0, py0;
632 pixel ppix1, ppix2, pix0, pix1, pix2, pix3;
633 double px1, py1;
634 double f0, f1, f2, f3, red, green, blue;
635 double a, b, d, e, ww15, hh15, ww25, hh25;
636 double pi = 3.141593;
637
638 nch = gdk_pixbuf_get_n_channels ( pixbuf1 );
639 nbits = gdk_pixbuf_get_bits_per_sample ( pixbuf1 );
640
641 /* must have 3+ channels (colors) */
642 if ( nch < 3 ) return 0;
643
644 /* must be 8 bits per channel */
645 if ( nbits != 8 ) return 0;
646
647
648 g_print ( "%s 2\n", __FUNCTION__ );
649
650
651 /* get input pixbuf1 attributes */
652 color = gdk_pixbuf_get_colorspace ( pixbuf1 );
653 alpha = gdk_pixbuf_get_has_alpha ( pixbuf1 );
654 ww1 = gdk_pixbuf_get_width ( pixbuf1 );
655 hh1 = gdk_pixbuf_get_height ( pixbuf1 );
656 rs1 = gdk_pixbuf_get_rowstride ( pixbuf1 );
657
658 /* normalize, -180 to +180 */
659 while ( angle < -180 ) angle += 360;
660
661 while ( angle > 180 ) angle -= 360;
662
663 /* radians, -pi to +pi */
664 angle = angle * pi / 180;
665
666 /* bugfix 0.01 >> 0.001 v.2.1 */
667 if ( fabs ( angle ) < 0.001 )
668 {
669 /* angle is zero within my precision */
670 pixbuf2 = gdk_pixbuf_copy ( pixbuf1 );
671 return pixbuf2;
672 }
673
674 /* rectangle containing rotated image */
675 ww2 = ww1 * fabs ( cos ( angle ) ) + hh1 * fabs ( sin ( angle ) );
676 hh2 = ww1 * fabs ( sin ( angle ) ) + hh1 * fabs ( cos ( angle ) );
677
678 /* create output pixbuf2 */
679 pixbuf2 = gdk_pixbuf_new ( color, alpha, nbits, ww2, hh2 );
680
681
682
683
684 if ( ! pixbuf2 ) return 0;
685
686 rs2 = gdk_pixbuf_get_rowstride ( pixbuf2 );
687
688 /* input pixel array */
689 ppix1 = gdk_pixbuf_get_pixels ( pixbuf1 );
690
691 /* output pixel array */
692 ppix2 = gdk_pixbuf_get_pixels ( pixbuf2 );
693
694 ww15 = 0.5 * ww1;
695 hh15 = 0.5 * hh1;
696 ww25 = 0.5 * ww2;
697 hh25 = 0.5 * hh2;
698
699 /* affine transform coefficients v.3.2 */
700 a = cos ( angle );
701 b = sin ( angle );
702 d = - sin ( angle );
703 e = cos ( angle );
704
705 /* loop through output pixels */
706 for ( py2 = 0; py2 < hh2; py2++ )
707 for ( px2 = 0; px2 < ww2; px2++ )
708 {
709 /* (px1,py1) = corresponding v.3.2 */
710 px1 = a * ( px2 - ww25 ) + b * ( py2 - hh25 ) + ww15;
711
712 /* point within input pixels */
713 py1 = d * ( px2 - ww25 ) + e * ( py2 - hh25 ) + hh15;
714
715 /* pixel containing (px1,py1) */
716 px0 = px1;
717 py0 = py1;
718
719 /* if outside input pixel array */
720 if ( px1 < 0 || px0 >= ww1 - 1 || py1 < 0 || py0 >= hh1 - 1 )
721 {
722 /* output is acolor v.2.17 */
723 pix2 = ppix2 + py2 * rs2 + px2 * nch;
724 pix2[0] = pix2[1] = pix2[2] = acolor;
725 continue;
726 }
727
728 /* 4 input pixels based at (px0,py0) */
729 pix0 = ppix1 + py0 * rs1 + px0 * nch;
730 pix1 = pix0 + rs1;
731 pix2 = pix0 + nch;
732 pix3 = pix0 + rs1 + nch;
733
734 /* overlap of (px1,py1) */
735 f0 = ( px0 + 1 - px1 ) * ( py0 + 1 - py1 );
736
737 /* in each of the 4 pixels */
738 f1 = ( px0 + 1 - px1 ) * ( py1 - py0 );
739 f2 = ( px1 - px0 ) * ( py0 + 1 - py1 );
740 f3 = ( px1 - px0 ) * ( py1 - py0 );
741
742 /* sum the weighted inputs */
743 red = f0 * pix0[0] + f1 * pix1[0] + f2 * pix2[0] + f3 * pix3[0];
744 green = f0 * pix0[1] + f1 * pix1[1] + f2 * pix2[1] + f3 * pix3[1];
745 blue = f0 * pix0[2] + f1 * pix1[2] + f2 * pix2[2] + f3 * pix3[2];
746
747 /* avoid acolor in image v.2.17 */
748 if ( red == acolor && green == acolor && blue == acolor )
749 {
750 if ( blue == 0 ) blue = 1;
751 else blue--;
752 }
753
754 /* output pixel */
755 pix2 = ppix2 + py2 * rs2 + px2 * nch;
756 pix2[0] = red;
757 pix2[1] = green;
758 pix2[2] = blue;
759 }
760
761 return pixbuf2;
762 }
763
764 /**
765 \brief
766 \note From module parseoptions.c
767 **/
getShortValue(Tcl_Interp * interp,Tcl_Obj * list,int idx,int * p)768 static int getShortValue ( Tcl_Interp *interp, Tcl_Obj *list, int idx, int *p )
769 {
770 int val;
771 Tcl_Obj *tp;
772
773 if ( Tcl_ListObjIndex ( interp, list, idx, &tp ) != TCL_OK )
774 return TCL_ERROR;
775
776 if ( Tcl_GetIntFromObj ( NULL, tp, &val ) != TCL_OK )
777 {
778 double d;
779
780 if ( Tcl_GetDoubleFromObj ( NULL, tp, &d ) != TCL_OK )
781 {
782 Tcl_AppendResult ( interp,
783 "expected integer or double, but got \"",
784 Tcl_GetString ( tp ), "\"", NULL );
785 return TCL_ERROR;
786 }
787
788 val = d * 0xFFFF;
789 }
790
791 if ( val < .0 || val > 0xFFFF )
792 {
793 Tcl_SetResult ( interp, "color value must be between 0 and 65535",
794 TCL_STATIC );
795 return TCL_ERROR;
796 }
797
798 *p = val;
799
800 return TCL_OK;
801 }
802
803 /**
804 \brief
805 \author Tadej Borovšak
806 \date 14/Feb/2010
807 \note gdk_color_parse() will only fill red, green and blue elements
808 of GdkColor. In order to fill pixel value, you'll need to
809 allocate your color using gdk_colormap_alloc_color().
810 But event if you do this, pixel value is not what you want
811 in this case, since pixel value is only meaningful in context
812 of your underlying windowing system.
813
814 **/
convertRGBtoPixel(gchar * clr)815 guint32 convertRGBtoPixel ( gchar *clr )
816 {
817
818 GdkColor color;
819 guint32 pixel;
820
821 /* Conversion factor from 16-bit color to 8-bit color (0xff / 0xffff) */
822 const gdouble f = 0.00389105;
823
824 /* create the colour from the supplied string, added by WJG */
825 gdk_color_parse ( clr, &color );
826
827 /* fill with colour */
828 pixel = ( ( ( guint ) ( color.red * f + 0.5 ) ) << 24 ) | /* R */
829 ( ( ( guint ) ( color.green * f + 0.5 ) ) << 16 ) | /* G */
830 ( ( ( guint ) ( color.blue * f + 0.5 ) ) << 8 ) | /* B */
831 ( 0xff << 0 ); /* A */
832
833 #ifdef DEBUG_PIXBUF
834 printf ( "pixel = %d\n", pixel );
835 #endif
836 return pixel;
837 }
838
839
840 /**
841 \brief
842 \note From module parseoptions.c
843 **/
getRGBA(Tcl_Interp * interp,Tcl_Obj * obj,int * r,int * g,int * b,int * a)844 static int getRGBA ( Tcl_Interp *interp, Tcl_Obj *obj, int *r, int *g, int *b, int *a )
845 {
846 int no;
847
848 if ( Tcl_ListObjLength ( interp, obj, &no ) != TCL_OK || no < 0 || no > 4 )
849 {
850 Tcl_SetResult ( interp, "color must be either \"name\" or a list "
851 "consisting of \"name alpha\", \"r g b\", or \"r g b alpha\"",
852 TCL_STATIC );
853 return TCL_ERROR;
854 }
855
856 if ( no == 0 ) /* transparent */
857 {
858 *r = *g = *b = *a = 0;
859 }
860
861 else if ( no < 3 )
862 {
863 Tcl_Obj *tp = obj;
864 GdkColor color;
865
866 if ( no == 2 )
867 {
868 if ( Tcl_ListObjIndex ( interp, obj, 0, &tp ) != TCL_OK )
869 return TCL_ERROR;
870 }
871
872 /* take as string and reformat as a GdkColor structure */
873
874 if ( gdk_color_parse ( Tcl_GetString ( tp ), &color ) == 0 )
875 {
876 Tcl_AppendResult ( interp, "unknown color \"", Tcl_GetString ( obj ), "\".", ( char * ) NULL );
877 return TCL_ERROR;
878 }
879
880 *r = color.red;
881 *g = color.green;
882 *b = color.blue;
883
884 if ( no == 2 )
885 {
886 if ( getShortValue ( interp, obj, 1, a ) != TCL_OK )
887 return TCL_ERROR;
888 }
889
890 else
891 *a = 0xFFFF;
892 }
893
894 else
895 {
896 if ( getShortValue ( interp, obj, 0, r ) != TCL_OK
897 || getShortValue ( interp, obj, 1, g ) != TCL_OK
898 || getShortValue ( interp, obj, 2, b ) != TCL_OK )
899 return TCL_ERROR;
900
901 if ( no == 4 )
902 {
903 if ( getShortValue ( interp, obj, 3, a ) != TCL_OK )
904 return TCL_ERROR;
905 }
906
907 else
908 *a = 0xFFFF;
909 }
910
911 return TCL_OK;
912 }
913
914 /**
915 \brief Take colour values from a string format and assign them to
916 location addressed by pointer *color.
917 **/
getGdkColor(Tcl_Interp * interp,Tcl_Obj * obj,GdkColor * color)918 static int getGdkColor ( Tcl_Interp *interp, Tcl_Obj *obj, GdkColor *color )
919 {
920 int r, g, b, a;
921
922 if ( getRGBA ( interp, obj, &r, &g, &b, &a ) != TCL_OK )
923 {
924 return TCL_ERROR;
925 }
926
927 /* TODO? if a != 0xFFFF: alpha not supported? */
928 color->red = r;
929
930 color->green = g;
931
932 color->blue = b;
933
934 return TCL_OK;
935 }
936
937 /**
938 \brief Function associated with the pixbufs.
939 **/
pixBufFunc(ClientData data,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])940 int pixBufFunc ( ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj * const objv[] )
941 {
942
943 #ifdef DEBUG_PIXBUF
944 listParameters ( objc, objv, "pixBufFunc" );
945 #endif
946
947 //GdkPixbuf *pixbuf;
948 //GdkPixbuf *dest->pixbuf;
949
950 PixbufParams *para, *dest;
951
952 para = ( PixbufParams * ) data;
953 dest = g_new ( PixbufParams, 1 );
954
955
956 //pixbuf = GDK_PIXBUF ( data );
957
958 static const char *cmds[] =
959 {
960 "copy", "delete", "configure", "duplicate",
961 "cget", "draw", "class",
962 "fill", "flood", "save", "turn",
963 "flip", "rotate", "composite",
964 "subpixbuf",
965 "saturation", "pixelate", "colorize",
966 "getPixel", "setPixel", "info", "filter",
967 "scale", "resize", "addAlpha", "options", "commands",
968 NULL
969 };
970
971 enum cmdIdx
972 {
973 CopyIdx, DeleteIdx, ConfigureIdx, DuplicateIdx,
974 CgetIdx, DrawIdx, ClassIdx,
975 FillIdx, FloodIdx, SaveIdx, TurnIdx,
976 FlipIdx, RotateIdx, CompositeIdx,
977 SubPixBufIdx,
978 SaturationIdx, PixelateIdx, ColorizeIdx,
979 GetPixelIdx, SetPixelIdx, InfoIdx, FilterIdx,
980 ScaleIdx, ResizeIdx, AddAlphaIdx, OptionsIdx, CommandsIdx
981 };
982
983 int idx;
984
985 if ( objc < 2 )
986 {
987 Tcl_WrongNumArgs ( interp, 1, objv, "command" );
988 return TCL_ERROR;
989 }
990
991 if ( Tcl_GetIndexFromObj ( interp, objv[1], cmds, "command", TCL_EXACT, &idx ) != TCL_OK )
992 {
993 return TCL_ERROR;
994 }
995
996 switch ( idx )
997 {
998 case CommandsIdx:
999 {
1000 gnoclGetOptions ( interp, cmds );
1001 }
1002 break;
1003 case OptionsIdx:
1004 {
1005 gnoclGetOptions ( interp, pixBufOptions );
1006 }
1007 break;
1008 case FloodIdx:
1009 {
1010
1011 g_print ( "FloodIdx\n" );
1012
1013 guint x, y;
1014
1015 sscanf ( Tcl_GetString ( objv[2] ), "%u", &x );
1016 sscanf ( Tcl_GetString ( objv[3] ), "%u", &x );
1017
1018
1019 //void gdk_pixbuf_flood_fill ( GdkPixbuf *pixbuf, guint fill_color, guint x, guint y )
1020 //gdk_pixbuf_flood_fill ( para->pixbuf, convertRGBtoPixel (Tcl_GetString ( objv[4] )) , x, y );
1021 gdk_pixbuf_flood_fill ( para->pixbuf, 0x0000ff00 , x, y );
1022 }
1023 break;
1024 case AddAlphaIdx:
1025 {
1026 /*
1027 GdkPixbuf * gdk_pixbuf_add_alpha (const GdkPixbuf *pixbuf, gboolean substitute_color, guchar r, guchar g, guchar b);
1028 */
1029 }
1030 break;
1031 case ScaleIdx:
1032 {
1033
1034 GdkInterpType interp_type;
1035 interp_type = GDK_INTERP_BILINEAR;
1036 float xScale, yScale;
1037 gint w, h, i, resizeIdx;
1038 float dest_width, dest_height;
1039
1040 static char *resizeOptions[] =
1041 {
1042 "-height", "-width",
1043 NULL
1044 };
1045
1046 static enum optsIdx
1047 {
1048 heightIdx, widthIdx
1049 };
1050
1051 xScale = -1;
1052 yScale = -1;
1053
1054 if ( objc == 3 )
1055 {
1056
1057 sscanf ( Tcl_GetString ( objv[2] ), "%f", &xScale );
1058 yScale = xScale;
1059
1060 }
1061
1062 /* parse all the options */
1063 i = 2;
1064
1065 while ( i < objc )
1066 {
1067 getIdx ( resizeOptions, Tcl_GetString ( objv[i] ), &resizeIdx );
1068
1069 switch ( resizeIdx )
1070 {
1071 case heightIdx:
1072 {
1073 #ifdef DEBUG_PIXBUF
1074 g_print ( "height\n" );
1075 #endif
1076
1077 sscanf ( Tcl_GetString ( objv[i+1] ), "%f", &yScale );
1078
1079 } break;
1080 case widthIdx:
1081 {
1082 #ifdef DEBUG_PIXBUF
1083 g_print ( "width\n" );
1084 #endif
1085 sscanf ( Tcl_GetString ( objv[i+1] ), "%f", &xScale );
1086 } break;
1087 default:
1088 {
1089 }
1090 }
1091
1092 i += 2;
1093 }
1094
1095 if ( xScale == -1 )
1096 {
1097 xScale = yScale;
1098
1099 }
1100
1101 if ( yScale == -1 )
1102 {
1103 yScale = xScale;
1104 }
1105
1106
1107 if ( xScale == -1 && yScale == -1 )
1108 {
1109 xScale = 1;
1110 yScale = 1;
1111 }
1112
1113 w = gdk_pixbuf_get_width ( para->pixbuf );
1114 h = gdk_pixbuf_get_height ( para->pixbuf );
1115
1116 dest_width = ( float ) w * xScale;
1117 dest_height = ( float ) h * yScale;
1118
1119 #ifdef DEBUG_PIXBUF
1120 g_print ( "i = %d dest_width, dest_height = %f %f\n", i, dest_width, dest_height );
1121 #endif
1122 dest->pixbuf = gdk_pixbuf_scale_simple ( para->pixbuf, ( int ) dest_width, ( int ) dest_height, interp_type );
1123
1124 para->pixbuf = dest->pixbuf;
1125 return gnoclRegisterPixBuf_ ( interp, para, pixBufFunc );
1126 return gnoclRegisterPixBuf ( interp, dest->pixbuf, pixBufFunc );
1127 }
1128 break;
1129 case ResizeIdx:
1130 {
1131
1132 GdkInterpType interp_type;
1133 interp_type = GDK_INTERP_BILINEAR;
1134 gint dest_width, dest_height;
1135 gint i, w, h;
1136 gint resizeIdx;
1137
1138 dest_width = -1 ;
1139 dest_height = -1;
1140
1141 static char *resizeOptions[] =
1142 {
1143 "-height", "-width",
1144 NULL
1145 };
1146
1147 static enum optsIdx
1148 {
1149 heightIdx, widthIdx
1150 };
1151
1152 /* parse all the options */
1153 i = 2;
1154
1155 while ( i < objc )
1156 {
1157
1158 getIdx ( resizeOptions, Tcl_GetString ( objv[i] ), &resizeIdx );
1159
1160 switch ( resizeIdx )
1161 {
1162 case heightIdx:
1163 {
1164 #ifdef DEBUG_PIXBUF
1165 g_print ( "height\n" );
1166 #endif
1167
1168 sscanf ( Tcl_GetString ( objv[i+1] ), "%d", &dest_height );
1169
1170 } break;
1171 case widthIdx:
1172 {
1173 #ifdef DEBUG_PIXBUF
1174 g_print ( "width\n" );
1175 #endif
1176 sscanf ( Tcl_GetString ( objv[i+1] ), "%d", &dest_width );
1177 } break;
1178 default:
1179 {
1180 }
1181 }
1182
1183 i += 2;
1184 }
1185
1186 //return TCL_OK;
1187
1188 //i = sscanf ( Tcl_GetString ( objv[2] ), "%d %d", &dest_width, &dest_height );
1189
1190 if ( dest_width == -1 && dest_height == -1 )
1191 {
1192
1193 #ifdef DEBUG_PIXBUF
1194 g_print ( "plain copy\n" );
1195 #endif
1196
1197 dest->pixbuf = gdk_pixbuf_copy ( para->pixbuf );
1198
1199 /* need to create a new para here */
1200
1201 para->pixbuf = dest->pixbuf;
1202 return gnoclRegisterPixBuf_ ( interp, para, pixBufFunc );
1203 return gnoclRegisterPixBuf ( interp, dest->pixbuf, pixBufFunc );
1204 }
1205
1206 if ( dest_height == -1 )
1207 {
1208 /* scale height in proportion to width */
1209 w = gdk_pixbuf_get_width ( para->pixbuf );
1210 h = gdk_pixbuf_get_height ( para->pixbuf );
1211
1212 dest_height = dest_width * h / w;
1213 }
1214
1215 if ( dest_width == -1 )
1216 {
1217 /* scale height in proportion to width */
1218 w = gdk_pixbuf_get_width ( para->pixbuf );
1219 h = gdk_pixbuf_get_height ( para->pixbuf );
1220
1221 dest_width = dest_height * w / h;
1222 }
1223
1224 dest->pixbuf = gdk_pixbuf_scale_simple ( para->pixbuf, dest_width, dest_height, interp_type );
1225
1226 para->pixbuf = dest->pixbuf;
1227
1228 return gnoclRegisterPixBuf_ ( interp, para, pixBufFunc );
1229 return gnoclRegisterPixBuf ( interp, dest->pixbuf, pixBufFunc );
1230 }
1231 case DuplicateIdx:
1232 {
1233
1234 dest->pixbuf = gdk_pixbuf_copy ( para->pixbuf );
1235
1236 para->pixbuf = dest->pixbuf;
1237
1238 return gnoclRegisterPixBuf_ ( interp, para, pixBufFunc );
1239 return gnoclRegisterPixBuf ( interp, dest->pixbuf, pixBufFunc );
1240 }
1241 break;
1242 case FilterIdx:
1243 {
1244 gnoclPixBufFilters ( interp, para->pixbuf , objc, objv );
1245 }
1246 break;
1247 case InfoIdx:
1248 {
1249 gchar str[32];
1250 gint w, h, a, bps, n;
1251 w = gdk_pixbuf_get_width ( para->pixbuf );
1252 h = gdk_pixbuf_get_height ( para->pixbuf );
1253 a = gdk_pixbuf_get_has_alpha ( para->pixbuf );
1254 bps = gdk_pixbuf_get_bits_per_sample ( para->pixbuf );
1255 n = gdk_pixbuf_get_n_channels ( para->pixbuf );
1256
1257 sprintf ( str, "%d %d %d %d %d", w, h, a, bps, n );
1258
1259 Tcl_SetResult ( interp, str, TCL_STATIC );
1260
1261 }
1262 break;
1263 case SetPixelIdx:
1264 {
1265
1266 gint x, y, w, h;
1267 guchar r, g, b, a;
1268
1269 /* set pixel location */
1270 sscanf ( Tcl_GetString ( objv[2] ), "%d %d", &x, &y );
1271 sscanf ( Tcl_GetString ( objv[3] ), "%d %d %d %d", &r, &g, &b , &a );
1272
1273 w = gdk_pixbuf_get_width ( para->pixbuf );
1274 h = gdk_pixbuf_get_height ( para->pixbuf );
1275
1276 if ( 0 )
1277 {
1278 GdkColor color;
1279
1280 if ( getGdkColor ( interp, Tcl_GetString ( objv[3] ), &color ) != TCL_OK )
1281 {
1282 return TCL_ERROR;
1283 }
1284 }
1285
1286 //set_pixel_color ( pixbuf, x, y , r, g, b, a );
1287 #ifdef DEBUG_PIXBUF
1288 g_printf ( "x =%d y =%d w =%d h =%d\n", x, y, w, h );
1289 g_printf ( "r =%d g =%d b =%d a =%d\n", r, g, b, a );
1290 #endif
1291
1292 /* error checking */
1293 if ( x < 0 || x > gdk_pixbuf_get_width ( para->pixbuf ) )
1294 {
1295 // return FALSE;
1296 }
1297
1298 if ( y < 0 || y > gdk_pixbuf_get_height ( para->pixbuf ) )
1299 {
1300 // return FALSE;
1301 }
1302
1303 gdk_pixbuf_set_pixel ( para->pixbuf, convertRGBtoPixel ( Tcl_GetString ( objv[3] ) ), x, y );
1304
1305 }
1306 break;
1307
1308 case GetPixelIdx:
1309 {
1310
1311 gint x, y;
1312 guchar r, g, b, a;
1313 double R, G, B, A;
1314
1315 gchar str[24];
1316
1317 /* get pixel location */
1318 sscanf ( Tcl_GetString ( objv[2] ), "%d %d", &x, &y );
1319 #ifdef DEBUG_PIXBUF
1320 g_printf ( "pos = %d %d\n", x, y );
1321 #endif
1322 gdk_pixbuf_get_pixel ( para->pixbuf, x, y , &r, &g, &b, &a );
1323
1324
1325 /* convert int to decimal float */
1326
1327 R = ( double ) r / 255;
1328 G = ( double ) g / 255;
1329 B = ( double ) b / 255;
1330 A = ( double ) a / 255;
1331
1332 sprintf ( str, "%f %f %f %f", R, G, B, A );
1333
1334 Tcl_SetResult ( interp, str, TCL_STATIC );
1335
1336 }
1337 break;
1338 case PixelateIdx:
1339 {
1340
1341 double saturation;
1342
1343 /* simplest way to get the a duplicate buffer to paste into */
1344 dest->pixbuf = gdk_pixbuf_copy ( para->pixbuf );
1345
1346 if ( 0 )
1347 {
1348 if ( Tcl_GetDoubleFromObj ( interp, objv[2], &saturation ) != TCL_OK )
1349 {
1350 Tcl_SetResult ( interp, "Invalid value set for saturation, must be a float.\n", TCL_STATIC );
1351 return TCL_ERROR;
1352 }
1353 }
1354
1355 gdk_pixbuf_saturate_and_pixelate ( para->pixbuf, dest->pixbuf, 1.0, TRUE );
1356
1357 para->pixbuf = dest->pixbuf;
1358 return gnoclRegisterPixBuf_ ( interp, para, pixBufFunc );
1359 return gnoclRegisterPixBuf ( interp, dest->pixbuf, pixBufFunc );
1360
1361 }
1362 break;
1363 case SaturationIdx:
1364 {
1365
1366 double saturation;
1367
1368 /* simplest way to get the a duplicate buffer to paste into */
1369 dest->pixbuf = gdk_pixbuf_copy ( para->pixbuf );
1370
1371 if ( Tcl_GetDoubleFromObj ( interp, objv[2], &saturation ) != TCL_OK )
1372 {
1373 Tcl_SetResult ( interp, "Invalid value set for saturation, must be a float.\n", TCL_STATIC );
1374 return TCL_ERROR;
1375 }
1376
1377 gdk_pixbuf_saturate_and_pixelate ( para->pixbuf, dest->pixbuf, saturation, FALSE );
1378
1379 para->pixbuf = dest->pixbuf;
1380 return gnoclRegisterPixBuf_ ( interp, para, pixBufFunc );
1381 return gnoclRegisterPixBuf ( interp, dest->pixbuf, pixBufFunc );
1382
1383 }
1384 break;
1385 case CopyIdx:
1386 {
1387 #ifdef DEBUG_PIXBUF
1388 g_print ( "CopyIdx %s\n", Tcl_GetString ( objv[2] ) );
1389 #endif
1390
1391 int src_x;
1392 int src_y;
1393 int width;
1394 int height;
1395
1396 dest->pixbuf = gdk_pixbuf_new ( GDK_COLORSPACE_RGB, FALSE, 8, width, height );
1397
1398 /* if no string is passed make a simple duplicate */
1399 if ( objc == 2 )
1400 {
1401 #ifdef DEBUG_PIXBUF
1402 g_print ( "total args %d\n", objc );
1403 #endif
1404 dest->pixbuf = gdk_pixbuf_copy ( para->pixbuf );
1405 }
1406
1407 /* copy as specific region of the pixbuf */
1408 else
1409 {
1410
1411 sscanf ( Tcl_GetString ( objv[2] ), "%d %d %d %d", &src_x, &src_y, &width, &height );
1412 #ifdef DEBUG_PIXBUF
1413 g_print ( "CopyIdx %d %d %d %d\n", src_x, src_y, width, height );
1414 #endif
1415
1416 dest->pixbuf = gdk_pixbuf_new ( GDK_COLORSPACE_RGB, FALSE, 8, width, height );
1417
1418 gdk_pixbuf_copy_area ( para->pixbuf, src_x, src_y, width, height, dest->pixbuf, 0, 0 );
1419 }
1420
1421 para->pixbuf = dest->pixbuf;
1422 return gnoclRegisterPixBuf_ ( interp, para, pixBufFunc );
1423 return gnoclRegisterPixBuf ( interp, dest->pixbuf, pixBufFunc );
1424
1425 }
1426 break;
1427 case SubPixBufIdx :
1428 {
1429
1430 int src_x;
1431 int src_y;
1432 int width;
1433 int height;
1434
1435 gint i;
1436
1437 if ( sscanf ( Tcl_GetString ( objv[2] ), "%d %d %d %d", &src_x, &src_y, &width, &height ) != 4 )
1438 {
1439 Tcl_SetResult ( interp, "Should be: pixBuf-id subpixBuf {x y w h}./n", TCL_STATIC );
1440
1441 return TCL_ERROR;
1442 }
1443
1444 dest->pixbuf = gdk_pixbuf_new_subpixbuf ( para->pixbuf, src_x, src_y, width, height );
1445
1446 para->pixbuf = dest->pixbuf;
1447 return gnoclRegisterPixBuf_ ( interp, para, pixBufFunc );
1448 return gnoclRegisterPixBuf ( interp, dest->pixbuf, pixBufFunc );
1449 }
1450 break;
1451 case DeleteIdx:
1452 {
1453 }
1454 break;
1455 case ConfigureIdx:
1456 {
1457 }
1458 break;
1459 case CgetIdx:
1460 {
1461
1462 static char *cgetOptions[] =
1463 {
1464 "-colorSpace", "-nChannels", "-hasAlpha",
1465 "-bitsPerSample", "-pixels", "-width",
1466 "-height", "-rowstride", "-key",
1467 NULL
1468 };
1469
1470 static enum optsIdx
1471 {
1472 ColorSpaceIdx, NChannelsIdx, HasAlphaIdx,
1473 BitsPerSampleIdx, PixelsIdx, WidthIdx,
1474 HeightIdx, RowStrideIdx, KeyIdx
1475 };
1476
1477 int Idx;
1478
1479 if ( Tcl_GetIndexFromObj ( interp, objv[2], cgetOptions, "option", TCL_EXACT, &Idx ) != TCL_OK )
1480 {
1481 return TCL_ERROR;
1482 }
1483
1484 switch ( Idx )
1485 {
1486 case ColorSpaceIdx:
1487 {
1488
1489 /* 05/03/10 only RGB supported */
1490 gchar *str;
1491
1492 switch ( gdk_pixbuf_get_colorspace ( para->pixbuf ) )
1493 {
1494 case GDK_COLORSPACE_RGB:
1495 {
1496 str = "RGB";
1497 }
1498 break;
1499 }
1500
1501 Tcl_SetObjResult ( interp, Tcl_NewStringObj ( str, -1 ) );
1502
1503 } break;
1504 case NChannelsIdx:
1505 {
1506 Tcl_SetObjResult ( interp, Tcl_NewIntObj ( gdk_pixbuf_get_bits_per_sample ( para->pixbuf ) ) );
1507 } break;
1508 case HasAlphaIdx:
1509 {
1510 Tcl_SetObjResult ( interp, Tcl_NewIntObj ( gdk_pixbuf_get_has_alpha ( para->pixbuf ) ) );
1511 } break;
1512 case BitsPerSampleIdx:
1513 {
1514 Tcl_SetObjResult ( interp, Tcl_NewIntObj ( gdk_pixbuf_get_bits_per_sample ( para->pixbuf ) ) );
1515 } break;
1516 case PixelsIdx:
1517 {
1518 /* Not terribly certain what this function implies */
1519 guchar *str;
1520 str = gdk_pixbuf_get_pixels ( para->pixbuf );
1521
1522 Tcl_SetObjResult ( interp, Tcl_NewStringObj ( str, -1 ) );
1523 } break;
1524 case WidthIdx:
1525 {
1526 Tcl_SetObjResult ( interp, Tcl_NewIntObj ( gdk_pixbuf_get_width ( para->pixbuf ) ) );
1527 } break;
1528 case HeightIdx:
1529 {
1530 Tcl_SetObjResult ( interp, Tcl_NewIntObj ( gdk_pixbuf_get_height ( para->pixbuf ) ) );
1531 } break;
1532 case RowStrideIdx:
1533 {
1534 Tcl_SetObjResult ( interp, Tcl_NewIntObj ( gdk_pixbuf_get_rowstride ( para->pixbuf ) ) );
1535 } break;
1536 case KeyIdx:
1537 {
1538 //const gchar * gdk_pixbuf_get_option (GdkPixbuf *pixbuf,const gchar *key);
1539 }
1540 break;
1541 }
1542 }
1543 break;
1544 case ClassIdx:
1545 {
1546 Tcl_SetObjResult ( interp, Tcl_NewStringObj ( "pixbuf", -1 ) );
1547 }
1548 break;
1549 case FillIdx:
1550 {
1551 gdk_pixbuf_fill ( para->pixbuf, convertRGBtoPixel ( Tcl_GetString ( objv[2] ) ) );
1552 }
1553 break;
1554 case SaveIdx:
1555 {
1556 GError *err;
1557 gchar *opt, *val;
1558 gchar *fileType;
1559 gchar *fileName;
1560 gchar *parameters;
1561
1562 /* set a default filetype */
1563 fileType = NULL;
1564 fileName = NULL;
1565 parameters = NULL;
1566
1567 static char *newOptions[] =
1568 {
1569 "-fileName", "-fileType", "-parameters",
1570 NULL
1571 };
1572
1573 static enum optsIdx
1574 {
1575 FileNameIdx, FileTypeIdx, ParametersIdx
1576 };
1577
1578 gint i, j;
1579 int idx;
1580
1581 for ( i = 2; i < objc; i += 2 )
1582 {
1583 j = i + 1;
1584
1585 opt = Tcl_GetString ( objv[i] );
1586 val = Tcl_GetString ( objv[j] );
1587
1588 if ( Tcl_GetIndexFromObj ( interp, objv[i], newOptions, "command", TCL_EXACT, &idx ) != TCL_OK )
1589 {
1590 return TCL_ERROR;
1591 }
1592
1593 switch ( idx )
1594 {
1595 case FileNameIdx:
1596 {
1597 //g_printf ( "save file = %s val = %s\n", opt, val );
1598 err = NULL;
1599 fileName = val;
1600
1601 if ( err != NULL )
1602 {
1603 g_warning ( err->message );
1604 g_error_free ( err );
1605 }
1606 }
1607 break;
1608 case FileTypeIdx:
1609 {
1610
1611 GSList *p;
1612
1613 //g_printf ( "file type = %s val = %s\n", opt, val );
1614
1615 for ( p = gdk_pixbuf_get_formats (); p != NULL; p = p->next )
1616 {
1617 //g_printf ( "p = %s\n", gdk_pixbuf_format_get_name ( p->data ) );
1618
1619 if ( !strcmp ( val, gdk_pixbuf_format_get_name ( p->data ) ) )
1620 {
1621 //g_printf ( "ok an acceptable format!\n" );
1622 fileType = val;
1623 break;
1624
1625 }
1626 }
1627
1628 if ( fileType == NULL )
1629 {
1630 gchar str[64];
1631 sprintf ( str, "GNOCL ERROR: \"%s\" is not a supported file format.\n", val );
1632 Tcl_SetResult ( interp, str, TCL_STATIC );
1633 return TCL_ERROR;
1634 }
1635
1636 }
1637 break;
1638 case ParametersIdx:
1639 {
1640 parameters = val;
1641
1642 }
1643 break;
1644 default:
1645 {
1646 }
1647 }
1648 }
1649
1650 //g_printf ( "parameters = %s\n", parameters );
1651
1652
1653 if ( parameters == NULL )
1654 {
1655 gdk_pixbuf_save ( para->pixbuf, fileName, fileType, &err, NULL ) ;
1656 break;
1657 }
1658
1659 /* handle any received parameters */
1660 if ( parameters != NULL )
1661 {
1662 gchar **tmp_array, **iterator;
1663 gchar *props[10], *vals[10];
1664 gint k;
1665
1666 tmp_array = g_strsplit_set ( parameters, "= ", 0 );
1667 iterator = tmp_array;
1668 i = 0;
1669
1670 /* do the actual split */
1671 while ( i < g_strv_length ( tmp_array ) / 2 )
1672 {
1673 props[i] = *iterator;
1674 iterator++;
1675
1676 vals[i] = *iterator;
1677 iterator++;
1678
1679 i++;
1680 }
1681
1682 props[i] = NULL; /* First array needs to be NULL terminated */
1683
1684 gdk_pixbuf_savev ( para->pixbuf, fileName, fileType, props, vals, NULL );
1685 g_strfreev ( tmp_array );
1686
1687 }
1688
1689 else
1690 {
1691 /* "plain" save if no parameters set */
1692 gdk_pixbuf_save ( para->pixbuf, fileName, fileType, &err, NULL );
1693 }
1694
1695 } break;
1696 case TurnIdx:
1697 {
1698 /*
1699 typedef enum {
1700 GDK_PIXBUF_ROTATE_NONE = 0,
1701 GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE = 90,
1702 GDK_PIXBUF_ROTATE_UPSIDEDOWN = 180,
1703 GDK_PIXBUF_ROTATE_CLOCKWISE = 270
1704 } GdkPixbufRotation;
1705 */
1706
1707 int idx;
1708 int angle;
1709
1710 angle = 0;
1711
1712 static char *turnOptions[] =
1713 {
1714 "clockwise", "90",
1715 "counterClockwise", "antiClockwise", "270", "-90",
1716 "upsideDown", "180", "-180",
1717 NULL
1718 };
1719
1720 static enum optsIdx
1721 {
1722 ClockWiseIdx, _90Idx,
1723 CounterClockwiseIdx, AntiClockwiseIdx, _270Idx, _minus90Idx,
1724 UpsideDownIdx, _180Idx, _minus180Idx
1725 };
1726
1727 if ( Tcl_GetIndexFromObj ( interp, objv[2], turnOptions, "command", TCL_EXACT, &idx ) != TCL_OK )
1728 {
1729 return TCL_ERROR;
1730 }
1731
1732 switch ( idx )
1733 {
1734 case ClockWiseIdx:
1735 case _90Idx:
1736 {
1737 angle = 90;
1738 }
1739 break;
1740
1741 case CounterClockwiseIdx:
1742 case AntiClockwiseIdx:
1743 case _270Idx:
1744 case _minus90Idx:
1745 {
1746 angle = 270;
1747 }
1748
1749 case UpsideDownIdx:
1750 case _180Idx:
1751 case _minus180Idx:
1752 {
1753 angle = 180;
1754 }
1755 break;
1756 }
1757
1758
1759 /* get rotated copy of the buffer */
1760 GdkPixbuf *pb;
1761 pb = gdk_pixbuf_rotate_simple ( para->pixbuf, angle );
1762
1763 /* clear the parent buffer, then copy accross with composite */
1764 gdk_pixbuf_fill ( para->pixbuf, 0x000000000000 );
1765 gdk_pixbuf_composite ( pb, para->pixbuf, 0, 0,
1766 gdk_pixbuf_get_width ( para->pixbuf ),
1767 gdk_pixbuf_get_height ( para->pixbuf ),
1768 0, 0, 1, 1,
1769 GDK_INTERP_BILINEAR, 255 );
1770 /* free the intermediary pixbuf*/
1771 g_object_unref ( pb );
1772 }
1773 break;
1774 case FlipIdx:
1775 {
1776 GdkPixbuf *pb;
1777
1778 /* horizontal */
1779 pb = gdk_pixbuf_flip ( para->pixbuf, TRUE );
1780 /* vertical */
1781 pb = gdk_pixbuf_flip ( para->pixbuf, FALSE );
1782
1783 /* clear the parent buffer, then copy accross with composite */
1784 gdk_pixbuf_fill ( para->pixbuf, 0x000000000000 );
1785 gdk_pixbuf_composite ( pb, para->pixbuf, 0, 0,
1786 gdk_pixbuf_get_width ( para->pixbuf ),
1787 gdk_pixbuf_get_height ( para->pixbuf ),
1788 0, 0, 1, 1,
1789 GDK_INTERP_BILINEAR, 255 );
1790 /* free the intermediary pixbuf*/
1791 g_object_unref ( pb );
1792
1793 }
1794 break;
1795 case RotateIdx:
1796 {
1797 /* todo:
1798 associate the named object with the new buffer which will be enlarged.
1799 error check, this will not work on svg files
1800 */
1801 g_print ( "RotateIdx 1\n" );
1802 GdkPixbuf *pb;
1803 gdouble angle;
1804 int acolor;
1805 gchar *name;
1806
1807 acolor = 255 ; /* default is black */
1808
1809 //name = gnoclGetNameFromPixBuf ( data );
1810
1811 g_print ( "RotateIdx 2\n" );
1812
1813 Tcl_GetDoubleFromObj ( NULL, objv[2], &angle );
1814
1815 /* only one option */
1816
1817 if ( !strcmp ( Tcl_GetString ( objv[3] ), "-backgroundColor" ) )
1818 {
1819 acolor = Tcl_GetIntFromObj ( NULL, objv[4], &acolor ) ;
1820 }
1821
1822 else
1823 {
1824 Tcl_SetResult ( interp, "Unknown option. M\n", TCL_STATIC );
1825 return TCL_ERROR;
1826 }
1827
1828
1829 g_print ( "RotateIdx 3\n" );
1830
1831 #ifdef DEBUG_PIXBUF
1832 g_print ( "Rotate 2 %s %f %s %d\n",
1833 name ,
1834 angle,
1835 Tcl_GetString ( objv[4] ),
1836 acolor ); // works ok!
1837 #endif
1838 /* replace the current buffer with the new buffer */
1839 pb = pixbufRotate ( para->pixbuf, angle, acolor );
1840
1841 g_print ( "RotateIdx 4\n" );
1842
1843 if ( pb == NULL )
1844 {
1845 Tcl_SetResult ( interp, "Unable to create pixBuff\n", TCL_STATIC );
1846 return TCL_ERROR;
1847 }
1848
1849 g_print ( "RotateIdx 5\n" );
1850
1851 para->pixbuf = pb;
1852
1853 return gnoclRegisterPixBuf_ ( interp, para, pixBufFunc );
1854 //return gnoclRegisterPixBuf ( interp, pb, pixBufFunc );
1855 g_print ( "RotateIdx 6\n" );
1856
1857 }
1858 break;
1859 case CompositeIdx:
1860 {
1861 /* this will clearly need parameters sorted from outset */
1862 #ifdef DEBUG_PIXBUF
1863 g_print ( "CompositeIdx 1\n" );
1864 g_printf ( "objc = %d\n", objc );
1865 listParameters ( objc, objv );
1866 #endif
1867 int compositeIdx;
1868 static const char *compositeOpts[] =
1869 {
1870 "-destX", "-destY",
1871 "-destWidth", "-destHeight",
1872 "-offsetX", "-offsetY",
1873 "-scaleX", "-scaleY",
1874 "-interpType",
1875 "-alpha",
1876 NULL
1877 };
1878
1879 enum compIdx
1880 {
1881 DestXIdx, DestYIdx,
1882 DestWidthIdx, DestHeightIdx,
1883 OffsetXIdx, OffsetYIdx,
1884 ScaleXIdx, ScaleYIdx,
1885 InterpTypeIdx,
1886 AlphaIdx
1887 };
1888
1889 /* check the number of arguments */
1890 if ( objc < 2 )
1891 {
1892 Tcl_SetObjResult ( interp, Tcl_NewStringObj ( "ERROR: Wrong number of arguments.", -1 ) );
1893 return TCL_ERROR;
1894 }
1895
1896 GdkPixbuf *src_, *dest;
1897 PixbufParams *src;
1898
1899
1900 /* composite options */
1901 gint dest_x, dest_y;
1902 gint dest_width, dest_height;
1903 gdouble offset_x, offset_y;
1904 gdouble scale_x, scale_y;
1905 GdkInterpType interp_type;
1906 gint overall_alpha;
1907
1908
1909 src = gnoclGetPixBufFromName ( Tcl_GetString ( objv[2] ), interp );
1910 dest = para->pixbuf;
1911
1912 /* set some defaults */
1913 dest_x = 0;
1914 dest_y = 0;
1915 dest_width = gdk_pixbuf_get_width ( src->pixbuf );
1916 dest_height = gdk_pixbuf_get_height ( src->pixbuf );
1917
1918 offset_x = 0;
1919 offset_y = 0;
1920 scale_x = 1;
1921 scale_y = 1;
1922 interp_type = GDK_INTERP_BILINEAR;
1923 overall_alpha = 255;
1924
1925 gint i; /* counter */
1926
1927 /* parse all the options */
1928 i = 3;
1929
1930 while ( i < objc )
1931 {
1932
1933 getIdx ( compositeOpts, Tcl_GetString ( objv[i] ), &compositeIdx );
1934
1935 switch ( compositeIdx )
1936 {
1937 case DestXIdx:
1938 {
1939 Tcl_GetIntFromObj ( NULL, objv[i+1], &dest_x );
1940 }
1941 break;
1942 case DestYIdx:
1943 {
1944 Tcl_GetIntFromObj ( NULL, objv[i+1], &dest_y );
1945 }
1946 break;
1947 case DestWidthIdx:
1948 {
1949 Tcl_GetIntFromObj ( NULL, objv[i+1], &dest_width );
1950 }
1951 break;
1952 case DestHeightIdx:
1953 {
1954 Tcl_GetIntFromObj ( NULL, objv[i+1], &dest_height );
1955 }
1956 break;
1957 case OffsetXIdx:
1958 {
1959 Tcl_GetDoubleFromObj ( NULL, objv[i+1], &offset_x );
1960 }
1961 break;
1962 case OffsetYIdx:
1963 {
1964 Tcl_GetDoubleFromObj ( NULL, objv[i+1], &offset_y );
1965 }
1966 break;
1967 case ScaleXIdx:
1968 {
1969 Tcl_GetDoubleFromObj ( NULL, objv[i+1], &scale_x );
1970 }
1971 break;
1972 case ScaleYIdx:
1973 {
1974 Tcl_GetDoubleFromObj ( NULL, objv[i+1], &offset_y );
1975 }
1976 break;
1977 case InterpTypeIdx:
1978 {
1979 interp_type = GDK_INTERP_BILINEAR;
1980 }
1981 break;
1982 case AlphaIdx:
1983 {
1984 Tcl_GetIntFromObj ( NULL, objv[i+1], &overall_alpha );
1985 }
1986 break;
1987 default: {}
1988 }
1989
1990 i += 2;
1991 }
1992
1993 /* reset values based upon received switches */
1994
1995 gdk_pixbuf_composite ( src->pixbuf, dest,
1996 dest_x, dest_y,
1997 dest_width, dest_height,
1998 offset_x, offset_y,
1999 scale_x, scale_y,
2000 interp_type, overall_alpha );
2001 }
2002 break;
2003 case DrawIdx:
2004 {
2005 /* draw the pixbuf to a GdkDrawable: ie. a drawing area */
2006 GtkWidget *widget;
2007 GdkDrawable *dest;
2008 gint src_x, src_y;
2009 gint dest_x, dest_y;
2010 gint width, height;
2011 gint x_dither, y_dither;
2012
2013 /* initialize the values with defaults */
2014 src_x = 0;
2015 src_y = 0;
2016 dest_x = 10;
2017 dest_y = 10;
2018
2019 x_dither = 0;
2020 y_dither = 0;
2021
2022 /* what size of the buffer has to be drawn */
2023 width = gdk_pixbuf_get_width ( para->pixbuf );
2024 height = gdk_pixbuf_get_height ( para->pixbuf );
2025
2026 widget = gnoclGetWidgetFromName ( Tcl_GetString ( objv[2] ), interp );
2027
2028 if ( widget == NULL )
2029 {
2030 return TCL_ERROR;
2031 }
2032
2033 dest = GDK_DRAWABLE ( widget->window );
2034
2035 /* change values based upon switches passed */
2036 gdk_draw_pixbuf (
2037 dest,
2038 gdk_gc_new ( widget->window ),
2039 para->pixbuf,
2040 src_x, src_y,
2041 dest_x, dest_y,
2042 width,
2043 height,
2044 GDK_RGB_DITHER_NONE,
2045 x_dither, y_dither );
2046
2047 }
2048 break;
2049 }
2050
2051 return TCL_OK;
2052 }
2053
2054 /**
2055 \brief
2056 \note "char *" and not "const char *" because of a not very strict
2057 handling of "const char *" in Tcl e.g. Tcl_CreateObjCommand
2058 */
gnoclGetAutoPixBufId(void)2059 char *gnoclGetAutoPixBufId ( void )
2060 {
2061 static int no = 0;
2062 /*
2063 static char buffer[30];
2064 */
2065
2066 char *buffer = g_new ( char, sizeof ( idPrefix ) + 15 );
2067 strcpy ( buffer, idPrefix );
2068
2069 /* with namespace, since the Id is also the widget command */
2070 sprintf ( buffer + sizeof ( idPrefix ) - 1, "%d", ++no );
2071
2072 return buffer;
2073 }
2074
2075 /**
2076 \brief Returns pointer to the pixbuf
2077 **/
2078 /* -----------------
2079 handle widget <-> name mapping
2080 -------------------- */
gnoclGetPixBufFromName(const char * id,Tcl_Interp * interp)2081 PixbufParams *gnoclGetPixBufFromName ( const char * id, Tcl_Interp * interp )
2082 {
2083 #ifdef DEBUG_PIXBUF
2084 g_print ( "%s\n", __FUNCTION__ );
2085 #endif
2086
2087 PixbufParams *para = NULL;
2088
2089 //GdkPixbuf *pixbuf = NULL;
2090 int n;
2091
2092 if ( strncmp ( id, idPrefix, sizeof ( idPrefix ) - 1 ) == 0
2093 && ( n = atoi ( id + sizeof ( idPrefix ) - 1 ) ) > 0 )
2094 {
2095 para = g_hash_table_lookup ( name2pixbufList, GINT_TO_POINTER ( n ) );
2096 }
2097
2098 if ( para == NULL && interp != NULL )
2099 {
2100 Tcl_AppendResult ( interp, "Unknown pixbuf \"", id, "\".", ( char * ) NULL );
2101 }
2102
2103 return para;
2104 }
2105
2106 /**
2107 \brief Returns the widget name associated with pointer
2108 **/
gnoclGetNameFromPixBuf(GdkPixbuf * pixbuf)2109 const char *gnoclGetNameFromPixBuf ( GdkPixbuf * pixbuf )
2110 {
2111 const char *name = g_object_get_data ( G_OBJECT ( pixbuf ), "gnocl::name" );
2112
2113 return name;
2114 }
2115
2116 /**
2117 \brief
2118 **/
gnoclForgetPixBufFromName(const char * path)2119 int gnoclForgetPixBufFromName ( const char * path )
2120 {
2121 int n = atoi ( path + sizeof ( idPrefix ) - 1 );
2122 assert ( gnoclGetPixBufFromName ( path, NULL ) );
2123 assert ( strncmp ( path, idPrefix, sizeof ( idPrefix ) - 1 ) == 0 );
2124 assert ( n > 0 );
2125
2126 g_hash_table_remove ( name2pixbufList, GINT_TO_POINTER ( n ) );
2127
2128 return 0;
2129 }
2130
2131 /**
2132 \brief
2133 **/
simpleDestroyFunc(GdkPixbuf * pixbuf,gpointer data)2134 static void simpleDestroyFunc ( GdkPixbuf * pixbuf, gpointer data )
2135 {
2136 const char *name = gnoclGetNameFromPixBuf ( pixbuf );
2137 gnoclForgetPixBufFromName ( name );
2138 Tcl_DeleteCommand ( ( Tcl_Interp * ) data, ( char * ) name );
2139 g_free ( ( char * ) name );
2140 }
2141
2142 /**
2143 \brief
2144 **/
gnoclMemNameAndPixBuf_(const char * path,PixbufParams * para)2145 int gnoclMemNameAndPixBuf_ ( const char * path, PixbufParams *para )
2146 {
2147 int n ;
2148
2149 n = atoi ( path + sizeof ( idPrefix ) - 1 );
2150
2151 assert ( n > 0 );
2152 assert ( g_hash_table_lookup ( name2pixbufList, GINT_TO_POINTER ( n ) ) == NULL );
2153 assert ( strncmp ( path, idPrefix, sizeof ( idPrefix ) - 1 ) == 0 );
2154
2155 /* memorize the name of the widget in the widget */
2156 g_object_set_data ( G_OBJECT ( para->pixbuf ), "gnocl::name", ( char * ) path );
2157 g_hash_table_insert ( name2pixbufList, GINT_TO_POINTER ( n ), para );
2158
2159 return 0;
2160 }
2161
2162 /**
2163 \brief
2164 **/
gnoclMemNameAndPixBuf(const char * path,GdkPixbuf * pixbuf)2165 int gnoclMemNameAndPixBuf ( const char * path, GdkPixbuf * pixbuf )
2166 {
2167 int n ;
2168
2169 n = atoi ( path + sizeof ( idPrefix ) - 1 );
2170
2171 assert ( n > 0 );
2172 assert ( g_hash_table_lookup ( name2pixbufList, GINT_TO_POINTER ( n ) ) == NULL );
2173 assert ( strncmp ( path, idPrefix, sizeof ( idPrefix ) - 1 ) == 0 );
2174
2175 /* memorize the name of the widget in the widget */
2176 g_object_set_data ( G_OBJECT ( pixbuf ), "gnocl::name", ( char * ) path );
2177 g_hash_table_insert ( name2pixbufList, GINT_TO_POINTER ( n ), pixbuf );
2178
2179 return 0;
2180 }
2181
2182 /**
2183 \brief Register structure for pixbuf and cairo context
2184 **/
gnoclRegisterPixBuf_(Tcl_Interp * interp,PixbufParams * para,Tcl_ObjCmdProc * proc)2185 int gnoclRegisterPixBuf_ ( Tcl_Interp * interp, PixbufParams * para, Tcl_ObjCmdProc * proc )
2186 {
2187
2188 const char *name;
2189
2190 name = gnoclGetAutoPixBufId();
2191
2192 /* create cairo context for this pixbuf */
2193 para->cr = gnoclPixbufCairoCreate ( para->pixbuf );
2194
2195 gnoclMemNameAndPixBuf_ ( name, para ); //<--- problems here
2196
2197 //g_signal_connect_after ( G_OBJECT ( pixbuf ), "destroy", G_CALLBACK ( simpleDestroyFunc ), interp );
2198
2199 if ( proc != NULL )
2200 {
2201
2202 Tcl_CreateObjCommand ( interp, ( char * ) name, proc, para, NULL );
2203 }
2204
2205 Tcl_SetObjResult ( interp, Tcl_NewStringObj ( name, -1 ) );
2206
2207 return TCL_OK;
2208 }
2209
2210
2211 /**
2212 \brief
2213 **/
gnoclRegisterPixBuf(Tcl_Interp * interp,GdkPixbuf * pixbuf,Tcl_ObjCmdProc * proc)2214 int gnoclRegisterPixBuf ( Tcl_Interp * interp, GdkPixbuf * pixbuf, Tcl_ObjCmdProc * proc )
2215 {
2216
2217 const char *name;
2218
2219 name = gnoclGetAutoPixBufId();
2220
2221 gnoclMemNameAndPixBuf ( name, pixbuf ); //<--- problems here
2222
2223 //g_signal_connect_after ( G_OBJECT ( pixbuf ), "destroy", G_CALLBACK ( simpleDestroyFunc ), interp );
2224
2225 if ( proc != NULL )
2226 {
2227
2228 Tcl_CreateObjCommand ( interp, ( char * ) name, proc, pixbuf, NULL );
2229 }
2230
2231 Tcl_SetObjResult ( interp, Tcl_NewStringObj ( name, -1 ) );
2232
2233 return TCL_OK;
2234 }
2235
2236 /**
2237 \brief Convert colour to hexadecimal.
2238 **/
gnoclRGB2HexCmd(ClientData data,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])2239 int gnoclRGB2HexCmd ( ClientData data, Tcl_Interp * interp, int objc, Tcl_Obj * const objv[] )
2240 {
2241
2242 #ifdef DEBUG_PIXBUF
2243 listParameters ( objc, objv, "gnoclRGB2HexCmd" );
2244 #endif
2245
2246 GdkColor color;
2247 gchar str[25];
2248 gint val;
2249
2250 getGdkColor ( interp, objv[1], &color );
2251 sprintf ( str, "#%.2x%.2x%.2x", color.red, color.green, color.blue );
2252
2253 /* differentiate between 8 / 16 bit colour */
2254 if ( strcmp ( Tcl_GetString ( objv[2] ), "-8bit" ) == 0 )
2255 {
2256 Tcl_GetIntFromObj ( NULL, objv[3], &val );
2257
2258 /* value of 0 means 16-bit */
2259 if ( !val )
2260 {
2261 color.red *= 257;
2262 color.green *= 257;
2263 color.blue *= 257;
2264 sprintf ( str, "#%.4x%.4x%.4x", color.red, color.green, color.blue );
2265 }
2266
2267 }
2268
2269 Tcl_SetObjResult ( interp, Tcl_NewStringObj ( &str, -1 ) ) ;
2270
2271 return TCL_OK;
2272 }
2273
2274 /**
2275 \brief Convert colour 16-bit RGB decimal.
2276 **/
gnoclClr2RGBCmd(ClientData data,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])2277 int gnoclClr2RGBCmd ( ClientData data, Tcl_Interp * interp, int objc, Tcl_Obj * const objv[] )
2278 {
2279
2280 #ifdef DEBUG_PIXBUF
2281 g_printf ( "gnoclClr2RGBCmd\n" );
2282 gint _i;
2283
2284
2285 for ( _i = 0; _i < objc; _i++ )
2286 {
2287 g_printf ( "\targ %d = %s\n", _i, Tcl_GetString ( objv[_i] ) );
2288 }
2289
2290 #endif
2291
2292 GdkColor color;
2293 gchar str[25];
2294 gint val;
2295
2296 getGdkColor ( interp, objv[1], &color );
2297
2298 /* differentiate between 8 / 16 bit colour */
2299 if ( strcmp ( Tcl_GetString ( objv[2] ), "-8bit" ) == 0 )
2300 {
2301 Tcl_GetIntFromObj ( NULL, objv[3], &val );
2302
2303 if ( !val )
2304 {
2305
2306 color.red *= 257;
2307 color.green *= 257;
2308 color.blue *= 257;
2309 }
2310
2311 }
2312
2313 sprintf ( str, "%d %d %d", color.red, color.green, color.blue );
2314 Tcl_SetObjResult ( interp, Tcl_NewStringObj ( &str, -1 ) ) ;
2315
2316 return TCL_OK;
2317 }
2318
2319
2320 static const char *cmds[] =
2321 {
2322 "get", "render", "types",
2323 "description", "license", "licence",
2324 "extensions", "scalable", "writable",
2325 "fileInfo", "new", "load",
2326 "snapshot", "screenshot",
2327 "logo",
2328 NULL
2329 };
2330
2331 /**
2332 \brief
2333 \author William J Giddings
2334 \date 17-Jan-2010
2335 \since 0.9.94
2336 **/
gnoclPixBufCmd(ClientData data,Tcl_Interp * interp,int objc,Tcl_Obj * const objv[])2337 int gnoclPixBufCmd ( ClientData data, Tcl_Interp * interp, int objc, Tcl_Obj * const objv[] )
2338 {
2339
2340 if ( gnoclGetCmdsAndOpts ( interp, cmds, pixBufOptions, objv, objc ) == TCL_OK )
2341 {
2342 return TCL_OK;
2343 }
2344
2345
2346 #ifdef DEBUG_PIXBUF
2347 listParameters ( objc, objv, "gnoclpixBufCmd" );
2348 #endif
2349
2350 GdkPixbuf *pixbuf;
2351 PixbufParams *para;
2352 para = g_new ( PixbufParams, 1 );
2353
2354 /* create new hash table if one does not exist */
2355 if ( name2pixbufList == NULL )
2356 {
2357 name2pixbufList = g_hash_table_new ( g_direct_hash, g_direct_equal );
2358 }
2359
2360
2361
2362 enum cmdIdx
2363 {
2364 GetIdx, RenderIdx, TypesIdx,
2365 DescriptionIdx, LicenseIdx, LicenceIdx,
2366 ExtensionsIdx, ScalableIdx, WritableIdx,
2367 FileInfoIdx, NewIdx, LoadIdx,
2368 SnapshotIdx, ScreenshotIdx,
2369 LogoIdx
2370 };
2371
2372 int cIdx;
2373
2374 /* set relevant options for commands / sub-commands */
2375 const int opt1Idx = 0;
2376 const int opt2Idx = 1;
2377 const int opt3Idx = 2;
2378
2379 GnoclOption cmd2Options[] =
2380 {
2381 { "-option1", GNOCL_STRING, "", NULL},
2382 { "-option2", GNOCL_STRING, "", NULL },
2383 { "-option3", GNOCL_STRING, "", NULL },
2384 { NULL }
2385 };
2386
2387 /* must have the form <command-name> action objectName <options> */
2388 /*
2389 if ( objc <= 1 )
2390 {
2391 Tcl_WrongNumArgs ( interp, 1, objv, "command option... " );
2392 return TCL_ERROR;
2393 }
2394 */
2395 if ( Tcl_GetIndexFromObj ( interp, objv[1], cmds, "option", TCL_EXACT, &cIdx ) != TCL_OK )
2396 {
2397 return TCL_ERROR;
2398 }
2399
2400 switch ( cIdx )
2401 {
2402 case ScreenshotIdx:
2403 {
2404 #ifdef DEBUG_PIXBUF
2405 g_printf ( "objc = %d\n", objc );
2406 #endif
2407 listParameters ( objc, objv );
2408
2409 GdkWindow *window_root;
2410
2411 gint x, y, x2, y2, width, height;
2412 float cx, cy;
2413 gint px, py;
2414 gint rw, rh;
2415 gint showPointer;
2416
2417 /* set some defaults */
2418 x = 0, y = 0;
2419
2420 /* get necessary values from the root window */
2421 window_root = gdk_get_default_root_window ();
2422 gdk_window_get_pointer ( window_root, &px, &py, NULL );
2423 gdk_window_get_geometry ( window_root, NULL, NULL, &rw, &rh, NULL );
2424
2425 if ( objc == 2 )
2426 {
2427 /* grab the whole screen */
2428 width = rw;
2429 height = rh;
2430
2431 }
2432
2433 else if ( objc = 4 )
2434 {
2435 /* check sub-command, region pointer -graphic */
2436 if ( strcmp ( Tcl_GetString ( objv[2] ), "region" ) == 0 )
2437 {
2438 sscanf ( Tcl_GetString ( objv[3] ), "%d %d %d %d", &x, &y, &width, &height );
2439
2440 if ( strcmp ( Tcl_GetString ( objv[4] ), "-pointer" ) == 0 )
2441 {
2442 Tcl_GetIntFromObj ( NULL, objv[5], &showPointer );
2443 }
2444 }
2445
2446 if ( strcmp ( Tcl_GetString ( objv[2] ), "pointer" ) == 0 )
2447 {
2448
2449 sscanf ( Tcl_GetString ( objv[3] ), "%d %d", &width, &height );
2450 /* ensure that pointer at the centre of the grab */
2451 x = px - width / 2;
2452 y = py - height / 2;
2453
2454 /* apply some error checks */
2455 if ( px <= width / 2 )
2456 {
2457 x = 0;
2458 }
2459
2460 if ( py <= height / 2 )
2461 {
2462 y = 0;
2463 }
2464
2465 if ( px > rw - width )
2466 {
2467 x = px - width + 1;
2468 }
2469
2470 if ( py > rh - height )
2471 {
2472 y = py - height + 1;
2473 }
2474 }
2475
2476 }
2477
2478 pixbuf = gdk_pixbuf_get_from_drawable ( NULL, window_root, NULL, x, y , 0, 0, width, height );
2479
2480 cx = ( float ) px - x;
2481 cy = ( float ) py - y;
2482
2483 cairo_t *cr;
2484
2485 cr = gnoclPixbufCairoCreate ( pixbuf );
2486
2487 cairo_set_line_width ( cr, 9 );
2488
2489 //cairo_set_source_rgb ( cr, 0.69, 0.19, 0 );
2490 cairo_set_source_rgba ( cr, 1.0, 0, 0, 0.25 );
2491
2492 /* do the drawing */
2493 cairo_arc ( cr, cx, cy, 20, 0, 2 * G_PI );
2494
2495 cairo_stroke_preserve ( cr );
2496
2497 cairo_fill ( cr );
2498
2499 pixbuf = gnoclPixbufCairoDestroy ( cr, FALSE );
2500
2501 GdkPixbuf * pointerPB = gdk_pixbuf_new_from_inline ( -1, gnocl_pointer, FALSE, NULL );
2502
2503 gdk_pixbuf_composite ( pointerPB, pixbuf, px - x, py - y,
2504 gdk_pixbuf_get_width ( pointerPB ),
2505 gdk_pixbuf_get_height ( pointerPB ),
2506 0, 0, 1, 1,
2507 GDK_INTERP_BILINEAR, 255 );
2508
2509 goto registerpixbuf;
2510
2511 }
2512
2513 break;
2514 case SnapshotIdx:
2515 {
2516 g_print ( "SS 1 %s\n", Tcl_GetString ( objv[2] ) );
2517 GtkWidget *widget;
2518 widget = gnoclGetWidgetFromName ( Tcl_GetString ( objv[2] ), interp );
2519
2520 /* must be a toplevel */
2521 widget = gtk_widget_get_toplevel ( widget );
2522
2523 if ( widget == NULL )
2524 {
2525 g_print ( "WARNING\n" );
2526 return TCL_OK;
2527 }
2528
2529 g_print ( "SS 2\n" );
2530
2531 GdkWindow *window_root;
2532 GdkRectangle rect;
2533
2534 window_root = gdk_get_default_root_window ();
2535 g_print ( "SS 3\n" );
2536
2537 gdk_window_get_frame_extents ( widget->window, &rect );
2538 g_print ( "SS 4\n" );
2539
2540 g_print ( "%d %d %d %d \n", rect.x, rect.y, rect.width, rect.height );
2541
2542 pixbuf = gdk_pixbuf_get_from_drawable ( NULL, window_root, NULL, rect.x, rect.y, 0, 0, rect.width, rect.height );
2543
2544 goto registerpixbuf;
2545
2546 }
2547
2548 break;
2549 /* create gnocl_logo from in-line data */
2550 case LogoIdx:
2551 {
2552 pixbuf = gdk_pixbuf_new_from_inline ( -1, gnocl_logo, FALSE, NULL );
2553
2554 goto registerpixbuf;
2555 }
2556 break;
2557 /* implement template with subcommands and */
2558 case GetIdx:
2559 {
2560 static const char *subCmd[] = { "drawable", "image", "pointer", NULL };
2561 enum subCmdtIdx { DrawableIdx, ImageIdx, PointerIdx };
2562 int scIdx;
2563 Tcl_Obj *tp;
2564
2565 if ( Tcl_GetIndexFromObj ( interp, objv[2], subCmd, "option", TCL_EXACT, &scIdx ) != TCL_OK )
2566 {
2567 return TCL_ERROR;
2568 }
2569
2570 /* error handling done within swith case code */
2571 /*
2572 if ( objc < 3 )
2573 {
2574 return TCL_ERROR;
2575 }
2576 */
2577
2578 switch ( scIdx )
2579 {
2580 case ImageIdx:
2581 case DrawableIdx:
2582 {
2583
2584 /* create a new buffer from the buffer associated with a specific drawable object
2585 only works for object already rendered to screen
2586 */
2587
2588 GtkWidget *widget;
2589 widget = gnoclGetWidgetFromName ( Tcl_GetString ( objv[3] ), interp );
2590
2591 if ( widget == NULL )
2592 {
2593 //widget = gnoclGetPixMapFromName ( Tcl_GetString ( objv[3] ), interp );
2594 //if (widget == NULL) {
2595 return TCL_ERROR;
2596 //}
2597 }
2598
2599 int x, y, width, height, depth;
2600
2601 gdk_window_get_geometry ( widget->window, &x, &y, &width, &height, &depth );
2602
2603
2604 pixbuf = gdk_pixbuf_get_from_drawable (
2605 NULL,
2606 GDK_DRAWABLE ( widget->window ),
2607 NULL,
2608 0, 0,
2609 0, 0,
2610 width, height );
2611
2612 goto registerpixbuf;
2613
2614 }
2615 break;
2616
2617 case PointerIdx:
2618 {
2619
2620 if ( objc != 3 )
2621 {
2622 return TCL_ERROR;
2623 }
2624
2625 g_printf ( "Create a pixbuf from the current pointer\n", Tcl_GetString ( objv[3] ) );
2626
2627 GdkCursor *cursor;
2628 GtkWidget *widget;
2629
2630 widget = gnoclGetWidgetFromName ( Tcl_GetString ( objv[3] ), interp );
2631 cursor = gdk_window_get_cursor ( widget->window );
2632 pixbuf = gdk_cursor_get_image ( cursor );
2633
2634 goto registerpixbuf;
2635 }
2636 break;
2637 }
2638 }
2639 break;
2640 case RenderIdx:
2641 {
2642 /* set relevant options for commands / sub-commands */
2643 static char *cmd2Options[] = { "-option1", "-option2", "-option3", NULL};
2644 static enum optsIdx { opt1Idx, opt2Idx, opt3Idx };
2645
2646 /* this one has the options usage:
2647 gnocl::<CmdName> command item -option val..
2648 */
2649 int ret;
2650
2651 ret = compare ( Tcl_GetString ( objv[2] ), cmd2Options );
2652
2653 switch ( ret )
2654 {
2655 case opt1Idx:
2656 {
2657 g_printf ( "\t\toption1, parameters = %s\n", Tcl_GetString ( objv[3] ) );
2658 }
2659 break;
2660 case opt2Idx:
2661 {
2662 g_printf ( "\t\toption2, parameters = %s\n", Tcl_GetString ( objv[3] ) );
2663 }
2664 break;
2665 case opt3Idx:
2666 {
2667 g_printf ( "\t\toption3, parameters = %s\n", Tcl_GetString ( objv[3] ) );
2668 }
2669 break;
2670 }
2671
2672 }
2673 break;
2674 case TypesIdx:
2675 {
2676 Tcl_Obj *resList;
2677
2678 resList = Tcl_NewListObj ( 0, NULL );
2679
2680 GSList *p;
2681
2682 for ( p = gdk_pixbuf_get_formats (); p != NULL; p = p->next )
2683 {
2684
2685 Tcl_ListObjAppendElement ( interp, resList,
2686 Tcl_NewStringObj ( gdk_pixbuf_format_get_name ( p->data ), -1 ) );
2687
2688 }
2689
2690 g_free ( p );
2691 Tcl_SetObjResult ( interp, resList );
2692 }
2693 break;
2694 case DescriptionIdx:
2695 {
2696 Tcl_Obj *resList;
2697
2698 resList = Tcl_NewListObj ( 0, NULL );
2699 GSList *p;
2700
2701 for ( p = gdk_pixbuf_get_formats (); p != NULL; p = p->next )
2702 {
2703 if ( !strcmp ( gdk_pixbuf_format_get_name ( p->data ), Tcl_GetString ( objv[2] ) ) )
2704 {
2705 Tcl_SetObjResult ( interp, Tcl_NewStringObj ( gdk_pixbuf_format_get_description ( p->data ), -1 ) );
2706 }
2707 }
2708
2709 g_free ( p );
2710
2711
2712 }
2713 break;
2714 case LicenceIdx:
2715 case LicenseIdx:
2716 {
2717 Tcl_Obj *resList;
2718
2719 resList = Tcl_NewListObj ( 0, NULL );
2720 GSList *p;
2721
2722 for ( p = gdk_pixbuf_get_formats (); p != NULL; p = p->next )
2723 {
2724 if ( !strcmp ( gdk_pixbuf_format_get_name ( p->data ), Tcl_GetString ( objv[2] ) ) )
2725 {
2726 Tcl_SetObjResult ( interp, Tcl_NewStringObj ( gdk_pixbuf_format_get_license ( p->data ), -1 ) );
2727 }
2728 }
2729
2730 g_free ( p );
2731
2732 }
2733 break;
2734 case ExtensionsIdx:
2735 {
2736 gchar * extensions;
2737 gchar **extension_list;
2738
2739 Tcl_Obj *resList;
2740
2741 resList = Tcl_NewListObj ( 0, NULL );
2742 GSList *p;
2743
2744 for ( p = gdk_pixbuf_get_formats (); p != NULL; p = p->next )
2745 {
2746 if ( !strcmp ( gdk_pixbuf_format_get_name ( p->data ), Tcl_GetString ( objv[2] ) ) )
2747 {
2748
2749 extension_list = gdk_pixbuf_format_get_extensions ( p->data );
2750 extensions = g_strjoinv ( " ", extension_list );
2751 g_strfreev ( extension_list );
2752
2753 Tcl_SetObjResult ( interp, Tcl_NewStringObj ( extensions, -1 ) );
2754 }
2755 }
2756
2757 g_free ( p );
2758
2759 }
2760 break;
2761 case ScalableIdx:
2762 {
2763 GSList *p;
2764
2765 gint res = -1;
2766
2767 for ( p = gdk_pixbuf_get_formats (); p != NULL; p = p->next )
2768 {
2769 if ( !strcmp ( gdk_pixbuf_format_get_name ( p->data ), Tcl_GetString ( objv[2] ) ) )
2770 {
2771 res = gdk_pixbuf_format_is_scalable ( p->data );
2772 }
2773 }
2774
2775 g_free ( p );
2776
2777 Tcl_SetObjResult ( interp, Tcl_NewIntObj ( res ) ) ;
2778
2779 }
2780 break;
2781 case WritableIdx:
2782 {
2783 GSList *p;
2784
2785 gint res = -1;
2786
2787 for ( p = gdk_pixbuf_get_formats (); p != NULL; p = p->next )
2788 {
2789 if ( !strcmp ( gdk_pixbuf_format_get_name ( p->data ), Tcl_GetString ( objv[2] ) ) )
2790 {
2791 res = gdk_pixbuf_format_is_writable ( p->data );
2792 }
2793 }
2794
2795 g_free ( p );
2796
2797 Tcl_SetObjResult ( interp, Tcl_NewIntObj ( res ) ) ;
2798 }
2799 break;
2800 case FileInfoIdx:
2801 {
2802
2803 GdkPixbufFormat *format;
2804 gint width;
2805 gint height;
2806 gchar str[128];
2807
2808 format = gdk_pixbuf_get_file_info ( Tcl_GetString ( objv[2] ), &width, &height );
2809
2810 sprintf ( str, "%d %d %s\n", width, height, gdk_pixbuf_format_get_name ( format ) );
2811
2812 Tcl_SetObjResult ( interp, Tcl_NewStringObj ( &str, -1 ) ) ;
2813
2814 }
2815 break;
2816 case NewIdx:
2817 {
2818
2819 gchar *name;
2820 gint width, height, bps, alpha;
2821 gchar *opt, *val;
2822 gint clrspace;
2823
2824 /* set some default values, then re-assign based upon received values */
2825 width = 640;
2826 height = 480;
2827 bps = 8;
2828 alpha = 0;
2829 clrspace = GDK_COLORSPACE_RGB;
2830
2831 static char *newOptions[] =
2832 {
2833 "-width", "-height", "-bitsPerSample", "-colorSpace",
2834 "-alpha", "-name", "-data",
2835 NULL
2836 };
2837
2838 static enum optsIdx
2839 {
2840 WidthIdx, HeightIdx,
2841 BitsPerSampleIdx, ColorSpaceIdx,
2842 AlphaIdx, NameIdx, DataIdx
2843 };
2844
2845 gint i, j;
2846 int idx;
2847
2848 /* create the buffer,note: only RGB suported */
2849 //sscanf ( Tcl_GetString ( objv[2] ), "%d %d %d", &width, &height, &bps );
2850 //pixbuf = gdk_pixbuf_new ( GDK_COLORSPACE_RGB, alpha, bps, width, height );
2851
2852 /* parse remaining the switches */
2853 /* set relevant options for commands / sub-commands */
2854
2855 for ( i = 2; i < objc; i += 2 )
2856 {
2857 j = i + 1;
2858
2859 opt = Tcl_GetString ( objv[i] );
2860 val = Tcl_GetString ( objv[j] );
2861
2862 if ( Tcl_GetIndexFromObj ( interp, objv[i], newOptions, "command", TCL_EXACT, &idx ) != TCL_OK )
2863 {
2864 return TCL_ERROR;
2865 }
2866
2867 switch ( idx )
2868 {
2869 case ColorSpaceIdx:
2870 {
2871 g_printf ( "GNOCL WARNING: Currently only GDK_COLORSPACE_RGB supported, set by default.\n" );
2872 }
2873 break;
2874 case WidthIdx:
2875 {
2876 //g_printf ( "\t\toption1, parameters = %s val = %s\n", opt, val );
2877 Tcl_GetIntFromObj ( NULL, objv[j], &width );
2878 }
2879 break;
2880 case HeightIdx:
2881 {
2882 //g_printf ( "\t\toption1, parameters = %s val = %s\n", opt, val );
2883 Tcl_GetIntFromObj ( NULL, objv[j], &height );
2884 }
2885 break;
2886 case AlphaIdx:
2887 {
2888 //g_printf ( "\t\toption1, parameters = %s val = %s\n", opt, val );
2889 Tcl_GetIntFromObj ( NULL, objv[j], &alpha );
2890
2891 if ( alpha != 0 )
2892 {
2893 alpha = 1;
2894 }
2895 }
2896 break;
2897 case BitsPerSampleIdx:
2898 {
2899 //g_printf ( "\t\toption1, parameters = %s val = %s\n", opt, val );
2900 Tcl_GetIntFromObj ( NULL, objv[j], &bps );
2901 } break;
2902 case NameIdx:
2903 {
2904 g_printf ( "%s Yet to be implemented.", val );
2905 }
2906 break;
2907 case DataIdx:
2908 {
2909 g_printf ( "%s Yet to be implemented.", val );;
2910 }
2911 break;
2912 default:
2913 {
2914 return TCL_ERROR;
2915 }
2916 }
2917
2918 } /* end of switch parsing */
2919
2920 pixbuf = gdk_pixbuf_new ( clrspace, alpha, bps, width, height );
2921
2922 if ( pixbuf == NULL )
2923 {
2924 g_print ( "Failed to create pixbuf.\n" );
2925 return TCL_ERROR;
2926 }
2927
2928
2929 para->pixbuf = pixbuf;
2930 return gnoclRegisterPixBuf_ ( interp, para, pixBufFunc );
2931
2932
2933 //goto registerpixbuf;
2934
2935 } break;
2936 case LoadIdx:
2937 {
2938 // GdkPixbuf * gdk_pixbuf_new_from_file (const char *filename, GError **error);
2939 gchar *opt, *val;
2940 gchar *filename;
2941
2942 static char *newOptions[] =
2943 {
2944 "-file", "-width", "-height", "-aspectRatio", "-inLine", NULL
2945 };
2946
2947 static enum optsIdx
2948 {
2949 FileIdx, WidthIdx, HeightIdx, AspectRatioIdx, InLineIdx
2950 };
2951
2952 gint i, j;
2953 int idx;
2954
2955 /* set some default values */
2956 gint height = 0;
2957 gint width = 0;
2958 gint aspect = 1;
2959
2960 for ( i = 2; i < objc; i += 2 )
2961 {
2962 j = i + 1;
2963
2964 opt = Tcl_GetString ( objv[i] );
2965 val = Tcl_GetString ( objv[j] );
2966
2967
2968 if ( Tcl_GetIndexFromObj ( interp, objv[i], newOptions, "command", TCL_EXACT, &idx ) != TCL_OK )
2969 {
2970 return TCL_ERROR;
2971 }
2972
2973 switch ( idx )
2974 {
2975 case InLineIdx:
2976 {
2977
2978 /* choose from a list of preset inline graphics */
2979 static char *inlinePB[] = {"logo", "pointer", NULL };
2980 static enum inlinePBIdx { LogoIdx, PointerIdx };
2981 int idx;
2982
2983 if ( Tcl_GetIndexFromObj ( interp, objv[j] , inlinePB, "command", TCL_EXACT, &idx ) != TCL_OK )
2984 {
2985 return TCL_ERROR;
2986 }
2987
2988 /* determine which built-in graphic to use */
2989 switch ( idx )
2990 {
2991 case LogoIdx:
2992 {
2993 pixbuf = gdk_pixbuf_new_from_inline ( -1, gnocl_logo, FALSE, NULL );
2994 }
2995 case PointerIdx:
2996 {
2997 pixbuf = gdk_pixbuf_new_from_inline ( -1, gnocl_pointer, FALSE, NULL );
2998 }
2999 }
3000
3001 if ( pixbuf == NULL )
3002 {
3003 /* add suitable error message */
3004 gchar *errmsg;
3005 sprintf ( errmsg, "ERROR: Cannot load inline image \"%s\".\n", Tcl_GetString ( objv[3] ) );
3006 Tcl_SetResult ( interp, errmsg , TCL_STATIC );
3007 return TCL_ERROR;
3008 }
3009
3010 //goto registerpixbuf;
3011
3012 para->pixbuf = pixbuf;
3013 para->fname = filename;
3014 return gnoclRegisterPixBuf_ ( interp, para, pixBufFunc );
3015
3016 }
3017 break;
3018
3019 case HeightIdx:
3020 {
3021 height = atoi ( val );
3022 }
3023 break;
3024 case WidthIdx:
3025 {
3026 width = atoi ( val );
3027 }
3028 break;
3029 case FileIdx:
3030 {
3031 //g_printf ( "load file = %s val = %s\n", opt, val );
3032 //pixbuf = gdk_pixbuf_new_from_file ( val, NULL );
3033 filename = val;
3034 }
3035 break;
3036 case AspectRatioIdx:
3037 {
3038 /* need error check, its a boolean! */
3039 aspect = atoi ( val );
3040 }
3041 break;
3042 default:
3043 {
3044 }
3045 }
3046 }
3047
3048
3049 if ( height != 0 && width != 0 )
3050 {
3051 //printf ( "OK!! height = %d width = %d\n", height, width );
3052 pixbuf = gdk_pixbuf_new_from_file_at_scale ( filename, width, height, aspect, NULL );
3053 }
3054
3055 else
3056 {
3057 //printf ( "NOPE!! height = %d width = %d\n", height, width );
3058 pixbuf = gdk_pixbuf_new_from_file ( val, NULL );
3059 }
3060
3061 //goto registerpixbuf;
3062 para->pixbuf = pixbuf;
3063 para->fname = filename;
3064 return gnoclRegisterPixBuf_ ( interp, para, pixBufFunc );
3065
3066 }
3067 break;
3068 }
3069
3070 return TCL_OK;
3071
3072 registerpixbuf:
3073 /* keep pointers */
3074 para->pixbuf = pixbuf;
3075 return gnoclRegisterPixBuf ( interp, para->pixbuf, pixBufFunc );
3076
3077 }
3078
3079 /**
3080 \brief Obtain colour and alpha values from an RGBA pixBuf.
3081 \author William J Giddings
3082 \date 06/03/10
3083 \since 0.9.94
3084 **/
gdk_pixbuf_get_pixel(GdkPixbuf * pixbuf,guint x,guint y,guchar * r,guchar * g,guchar * b,guchar * a)3085 void gdk_pixbuf_get_pixel ( GdkPixbuf * pixbuf, guint x, guint y , guchar * r, guchar * g, guchar * b, guchar * a )
3086 {
3087 guchar *pixels;
3088 guchar *p;
3089 guint w, h;
3090 guint rowstride, n_channels;
3091
3092 g_return_if_fail ( GDK_IS_PIXBUF ( pixbuf ) );
3093
3094 w = gdk_pixbuf_get_width ( pixbuf );
3095 h = gdk_pixbuf_get_height ( pixbuf );
3096
3097 if ( w == 0 || h == 0 )
3098 {
3099 return;
3100 }
3101
3102 if ( x > w || y > h )
3103 {
3104 return;
3105 }
3106
3107 pixels = gdk_pixbuf_get_pixels ( pixbuf );
3108 rowstride = gdk_pixbuf_get_rowstride ( pixbuf );
3109 n_channels = gdk_pixbuf_get_n_channels ( pixbuf );
3110
3111 p = pixels + x * n_channels + y * rowstride;
3112
3113 *r = p[0];
3114 *g = p[1];
3115 *b = p[2];
3116 *a = ( n_channels == 4 ) ? p[3] : 0;
3117
3118 }
3119
3120
3121 /*---------------------------------------------------------------------*/
3122
3123 /**
3124 * gdk_pixbuf_fill:
3125 * @pixbuf: a #GdkPixbuf
3126 * @pixel: RGBA pixel to clear to
3127 * (0xffffffff is opaque white, 0x00000000 transparent black)
3128 *
3129 * Clears a pixbuf to the given RGBA value, converting the RGBA value into
3130 * the pixbuf's pixel format. The alpha will be ignored if the pixbuf
3131 * doesn't have an alpha channel.
3132 *
3133 **/
3134 /**
3135 \brief Obtain colour and alpha values from an RGBA pixBuf.
3136 \author William J Giddings
3137 \date 06/03/10
3138 \since 0.9.94
3139 \note Adaptation of gdk_pixbuf_fill
3140 **/
gdk_pixbuf_set_pixel(GdkPixbuf * pixbuf,guint32 pixel,guint x,guint y)3141 void gdk_pixbuf_set_pixel ( GdkPixbuf * pixbuf, guint32 pixel, guint x, guint y )
3142 {
3143 guchar *pixels;
3144 guint r, g, b, a;
3145 guchar *p;
3146 guint w, h;
3147 guint rowstride, n_channels;
3148
3149 g_return_if_fail ( GDK_IS_PIXBUF ( pixbuf ) );
3150
3151 w = gdk_pixbuf_get_width ( pixbuf );
3152 h = gdk_pixbuf_get_height ( pixbuf );
3153
3154 if ( w == 0 || h == 0 )
3155 {
3156 return;
3157 }
3158
3159 if ( x > w || y > h )
3160 {
3161 return;
3162 }
3163
3164 pixels = gdk_pixbuf_get_pixels ( pixbuf );
3165 rowstride = gdk_pixbuf_get_rowstride ( pixbuf );
3166 n_channels = gdk_pixbuf_get_n_channels ( pixbuf );
3167
3168 r = ( pixel & 0xff000000 ) >> 24;
3169 g = ( pixel & 0x00ff0000 ) >> 16;
3170 b = ( pixel & 0x0000ff00 ) >> 8;
3171 a = ( pixel & 0x000000ff );
3172
3173 p = pixels + y * rowstride + x * n_channels;
3174
3175 switch ( n_channels )
3176 {
3177 case 3:
3178 {
3179 p[0] = r;
3180 p[1] = g;
3181 p[2] = b;
3182 }
3183 break;
3184 case 4:
3185 {
3186 p[0] = r;
3187 p[1] = g;
3188 p[2] = b;
3189 p[3] = a;
3190 }
3191 break;
3192 default:
3193 break;
3194 }
3195 }
3196
3197 /**
3198 \brief Draw line to pixbuf using Breseham's algorithm
3199 **/
gdk_pixbuf_draw_line(GdkPixbuf * pixbuf,guint32 pixel,gint x1,gint y1,gint x2,gint y2)3200 void gdk_pixbuf_draw_line ( GdkPixbuf *pixbuf, guint32 pixel, gint x1, gint y1, gint x2, gint y2 )
3201 {
3202
3203 int dx, dy, i, e;
3204 int incx, incy, inc1, inc2;
3205 int x, y;
3206
3207 dx = x2 - x1;
3208 dy = y2 - y1;
3209
3210 if ( dx < 0 ) dx = -dx;
3211
3212 if ( dy < 0 ) dy = -dy;
3213
3214 incx = 1;
3215
3216 if ( x2 < x1 ) incx = -1;
3217
3218 incy = 1;
3219
3220 if ( y2 < y1 ) incy = -1;
3221
3222 x = x1;
3223 y = y1;
3224
3225 if ( dx > dy )
3226 {
3227 gdk_pixbuf_set_pixel ( pixbuf, pixel, x, y );
3228 e = 2 * dy - dx;
3229 inc1 = 2 * ( dy - dx );
3230 inc2 = 2 * dy;
3231
3232 for ( i = 0; i < dx; i++ )
3233 {
3234 if ( e >= 0 )
3235 {
3236 y += incy;
3237 e += inc1;
3238 }
3239
3240 else e += inc2;
3241
3242 x += incx;
3243 gdk_pixbuf_set_pixel ( pixbuf, pixel, x, y );
3244 }
3245 }
3246
3247 else
3248 {
3249 gdk_pixbuf_set_pixel ( pixbuf, pixel, x, y );
3250 e = 2 * dx - dy;
3251 inc1 = 2 * ( dx - dy );
3252 inc2 = 2 * dx;
3253
3254 for ( i = 0; i < dy; i++ )
3255 {
3256 if ( e >= 0 )
3257 {
3258 x += incx;
3259 e += inc1;
3260 }
3261
3262 else e += inc2;
3263
3264 y += incy;
3265 gdk_pixbuf_set_pixel ( pixbuf, pixel, x, y );
3266 }
3267 }
3268
3269 }
3270
3271 /**
3272 \brief Draw line to pixbuf using Breseham's circle algorithm
3273 **/
gdk_pixbuf_draw_circle_1(GdkPixbuf * pixbuf,guint32 pixel,gint xc,gint yc,gint r,gint fill)3274 void gdk_pixbuf_draw_circle_1 ( GdkPixbuf *pixbuf, guint32 pixel, gint xc, gint yc, gint r, gint fill )
3275 {
3276
3277 int x, y, p;
3278
3279 x = 0;
3280 y = r;
3281
3282 gdk_pixbuf_set_pixel ( pixbuf, pixel, x, y );
3283
3284
3285 p = 3 - ( 2 * r );
3286
3287 for ( x = 0; x <= y; x++ )
3288 {
3289 if ( p < 0 )
3290 {
3291 y = y;
3292 p = ( p + ( 4 * x ) + 6 );
3293 }
3294
3295 else
3296 {
3297 y = y - 1;
3298
3299 p = p + ( ( 4 * ( x - y ) + 10 ) );
3300 }
3301
3302 gdk_pixbuf_set_pixel ( pixbuf, pixel, xc + x, yc - y );
3303 gdk_pixbuf_set_pixel ( pixbuf, pixel, xc - x, yc - y );
3304
3305 gdk_pixbuf_set_pixel ( pixbuf, pixel, xc + x, yc + y );
3306 gdk_pixbuf_set_pixel ( pixbuf, pixel, xc - x, yc + y );
3307
3308 gdk_pixbuf_set_pixel ( pixbuf, pixel, xc + y, yc - x );
3309 gdk_pixbuf_set_pixel ( pixbuf, pixel, xc - y, yc - x );
3310
3311 gdk_pixbuf_set_pixel ( pixbuf, pixel, xc + y, yc + x );
3312 gdk_pixbuf_set_pixel ( pixbuf, pixel, xc - y, yc + x );
3313
3314 if ( fill )
3315 {
3316 gdk_pixbuf_draw_line ( pixbuf, pixel, xc + x, yc - y, xc - x, yc - y );
3317 gdk_pixbuf_draw_line ( pixbuf, pixel, xc + x, yc + y, xc - x, yc + y );
3318 gdk_pixbuf_draw_line ( pixbuf, pixel, xc + y, yc - x, xc - y, yc - x );
3319 gdk_pixbuf_draw_line ( pixbuf, pixel, xc + y, yc + x, xc - y, yc + x );
3320 }
3321
3322 }
3323 }
3324
gdk_pixbuf_draw_circle_2(GdkPixbuf * pixbuf,guint32 pixel,gint xc,gint yc,gint r,gint fill)3325 void gdk_pixbuf_draw_circle_2 ( GdkPixbuf *pixbuf, guint32 pixel, gint xc, gint yc, gint r, gint fill )
3326 {
3327
3328 int y, x;
3329
3330 if ( 0 )
3331 {
3332 for ( y = -r; y <= r; y++ )
3333 {
3334 for ( x = -r; x <= r; x++ )
3335 {
3336 if ( x*x + y*y <= r * r )
3337 {
3338 //setpixel(origin.x+x, origin.y+y);
3339 gdk_pixbuf_set_pixel ( pixbuf, pixel, xc + x, yc + y );
3340 }
3341 }
3342 }
3343
3344 return;
3345 }
3346
3347
3348 /* just the outline */
3349 for ( y = -r; y <= r; y++ )
3350 {
3351 for ( x = -r; x <= r; x++ )
3352 {
3353
3354 g_print ( "y = %d x = %d\n", y, x );
3355
3356 if ( x*x + y*y == r * r )
3357 {
3358
3359 g_print ( "i= %d %d %d\n", y, x * x + y * y, r * r );
3360
3361 //setpixel(origin.x+x, origin.y+y);
3362 gdk_pixbuf_set_pixel ( pixbuf, pixel, xc + x, yc + y );
3363 }
3364 }
3365 }
3366
3367 }
3368
3369
gdk_pixbuf_draw_circle(GdkPixbuf * pixbuf,guint32 pixel,gint xc,gint yc,gint r,gint solid)3370 void gdk_pixbuf_draw_circle ( GdkPixbuf *pixbuf, guint32 pixel, gint xc, gint yc, gint r, gint solid )
3371 {
3372 int i, x, y;
3373
3374 /* solid circle */
3375 if ( solid )
3376 {
3377 for ( y = -r; y <= r; y++ )
3378 {
3379 for ( x = -r; x <= r; x++ )
3380 {
3381 if ( x*x + y*y <= r * r )
3382 {
3383 //setpixel(origin.x+x, origin.y+y);
3384 gdk_pixbuf_set_pixel ( pixbuf, pixel, xc + x, yc + y );
3385 }
3386 }
3387 }
3388
3389 return;
3390 }
3391
3392 /* outline only */
3393 i = r * r;
3394
3395 for ( y = r ; y >= 0; y-- )
3396 {
3397 x = sqrt ( i - y * y );
3398 gdk_pixbuf_set_pixel ( pixbuf, pixel, xc + x, yc + y );
3399 gdk_pixbuf_set_pixel ( pixbuf, pixel, xc - x, yc - y );
3400 gdk_pixbuf_set_pixel ( pixbuf, pixel, xc - x, yc + y );
3401 gdk_pixbuf_set_pixel ( pixbuf, pixel, xc + x, yc - y );
3402 }
3403
3404 for ( x = r ; x >= 0; x-- )
3405 {
3406 y = sqrt ( i - x * x );
3407 gdk_pixbuf_set_pixel ( pixbuf, pixel, xc + x, yc + y );
3408 gdk_pixbuf_set_pixel ( pixbuf, pixel, xc - x, yc - y );
3409 gdk_pixbuf_set_pixel ( pixbuf, pixel, xc - x, yc + y );
3410 gdk_pixbuf_set_pixel ( pixbuf, pixel, xc + x, yc - y );
3411 }
3412
3413 }
3414