1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
3 * Copyright (C) 1998-2007 Ales Hvezda
4 * Copyright (C) 1998-2007 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
37 #include <gdk-pixbuf/gdk-pixbuf.h>
38 #include <gdk-pixbuf/gdk-pixdata.h>
41 #include "libgeda_priv.h"
43 /*! \brief Create picture OBJECT from character string.
44 * \par Function Description
45 * This function will get the description of a picture from the
46 * character string <B>*first_line</B>. The new picture is then added
47 * to the list of object of which <B>*object_list</B> is the last
48 * element before the call. The function returns the new last
49 * element, that is the added picture object.
51 * \param [in] toplevel The TOPLEVEL object.
52 * \param [out] object_list OBJECT list to create picture in.
53 * \param [in] first_line Character string with picture description.
54 * \param [in] tb Text buffer to load embedded data from.
55 * \param [in] release_ver libgeda release version number.
56 * \param [in] fileformat_ver libgeda file format version number.
57 * \return A pointer to the new picture object.
59 OBJECT
*o_picture_read(TOPLEVEL
*toplevel
, OBJECT
*object_list
,
60 const char *first_line
,
62 unsigned int release_ver
,
63 unsigned int fileformat_ver
)
66 int width
, height
, angle
;
67 gchar mirrored
, embedded
;
72 GdkPixbuf
*pixbuf
= NULL
;
73 gchar
*file_content
= NULL
;
74 guint file_length
= 0;
76 static char gdk_initialized
=0;
78 /* Initialize GDK first in case this isn't a graphic app */
79 if (gdk_initialized
== 0) {
84 num_conv
= sscanf(first_line
, "%c %d %d %d %d %d %c %c\n",
85 &type
, &x1
, &y1
, &width
, &height
, &angle
, &mirrored
, &embedded
);
88 s_log_message (_("Error reading picture definition line: %s.\n"),
92 /* Convert from ascii character to number */
93 if (g_ascii_isdigit(mirrored
)) {
97 if (g_ascii_isdigit(embedded
)) {
101 if (width
== 0 || height
== 0) {
102 s_log_message(_("Found a zero width/height picture [ %c %d %d %d %d ]\n"),
103 type
, x1
, y1
, width
, height
);
106 if ( (mirrored
> 1) || (mirrored
< 0)) {
107 s_log_message(_("Found a picture with a wrong 'mirrored' parameter: %c.\n"),
109 s_log_message(_("Setting mirrored to 0\n"));
113 if ( (embedded
> 1) || (embedded
< 0)) {
114 s_log_message(_("Found a picture with a wrong 'embedded' parameter: %c.\n"),
116 s_log_message(_("Setting embedded to 0\n"));
128 s_log_message(_("Found an unsupported picture angle [ %d ]\n"), angle
);
129 s_log_message(_("Setting angle to 0\n"));
135 filename
= g_strdup(s_textbuffer_next_line(tb
));
136 filename
= remove_last_nl(filename
);
139 GString
*encoded_picture
=g_string_new("");
142 /* Read the encoded picture */
145 line
= s_textbuffer_next_line(tb
);
146 if (line
== NULL
) break;
148 if (g_strcasecmp(line
, ".\n") != 0) {
149 encoded_picture
= g_string_append (encoded_picture
, line
);
153 } while (finished
== 0);
155 /* Decode the picture */
156 file_content
= s_encoding_base64_decode(encoded_picture
->str
,
157 encoded_picture
->len
,
159 if (encoded_picture
!= NULL
) {
160 g_string_free (encoded_picture
, TRUE
);
163 if (file_content
== NULL
) {
164 s_log_message (_("Failed to load image from embedded data [%s]: %s\n"),
165 filename
, _("Base64 decoding failed."));
166 s_log_message (_("Falling back to file loading. Picture unembedded.\n"));
171 /* If we have embedded data, try loading from the decoded buffer */
172 if (file_content
!= NULL
) {
173 pixbuf
= o_picture_pixbuf_from_buffer (file_content
, file_length
, &err
);
175 s_log_message (_("Failed to load image from embedded data [%s]: %s\n"),
176 filename
, err
->message
);
177 s_log_message (_("Falling back to file loading. Picture unembedded.\n"));
184 /* If we haven't loaded the pixbuf above, try loading from file */
185 if (pixbuf
== NULL
) {
186 pixbuf
= gdk_pixbuf_new_from_file (filename
, &err
);
188 s_log_message (_("Failed to load image from file [%s]: %s\n"),
189 filename
, err
->message
);
195 /* If the pixbuf couldn't be loaded, then try to load a warning picture */
196 if (pixbuf
== NULL
) {
199 s_log_message (_("Loading warning picture.\n"));
201 temp_filename
= g_strconcat(toplevel
->bitmap_directory
,
202 G_DIR_SEPARATOR_S
, "gschem-warning.png", NULL
);
203 pixbuf
= gdk_pixbuf_new_from_file (temp_filename
, NULL
);
204 if (pixbuf
== NULL
) {
205 s_log_message( _("Error loading picture from file: %s.\n"),
208 g_free (temp_filename
);
211 /* create and add the picture to the list */
212 /* The picture is described by its upper left and lower right corner */
213 object_list
= o_picture_add(toplevel
, object_list
, pixbuf
,
214 file_content
, file_length
, filename
,
215 (double)height
/ width
,
217 x1
, y1
+height
, x1
+width
, y1
,
218 angle
, mirrored
, embedded
);
220 /* Don't free file_content, it is now owned by the picture object */
226 /*! \brief Create a character string representation of a picture OBJECT.
227 * \par Function Description
228 * This function formats a string in the buffer <B>*buff</B> to describe
229 * the picture object <B>*object</B>.
231 * \param [in] object Picture OBJECT to create string from.
232 * \return A pointer to the picture OBJECT character string.
235 * Caller must g_free returned character string.
238 char *o_picture_save(OBJECT
*object
)
240 int width
, height
, x1
, y1
;
241 gchar
*encoded_picture
=NULL
;
243 guint encoded_picture_length
;
245 /* calculate the width and height of the box */
246 width
= abs(object
->picture
->lower_x
- object
->picture
->upper_x
);
247 height
= abs(object
->picture
->upper_y
- object
->picture
->lower_y
);
249 /* calculate the lower left corner of the box */
250 x1
= object
->picture
->upper_x
;
251 y1
= object
->picture
->upper_y
- height
; /* move the origin to 0, 0*/
254 printf("picture: %d %d %d %d\n", x1
, y1
, width
, height
);
257 /* Encode the picture if it's embedded */
258 if (object
->picture
->embedded
== 1) {
260 s_encoding_base64_encode( (char *)object
->picture
->file_content
,
261 object
->picture
->file_length
,
262 &encoded_picture_length
,
264 if (encoded_picture
== NULL
) {
265 s_log_message(_("ERROR: o_picture_save: unable to encode the picture.\n"));
269 if (object
->picture
->embedded
==1 &&
270 encoded_picture
!= NULL
) {
271 out
= g_strdup_printf("%c %d %d %d %d %d %c %c\n%s\n%s\n%s",
273 x1
, y1
, width
, height
,
274 object
->picture
->angle
,
275 /* Convert the (0,1) chars to ASCII */
276 (object
->picture
->mirrored
)+0x30,
277 object
->picture
->embedded
+0x30,
278 object
->picture
->filename
,
283 out
= g_strdup_printf("%c %d %d %d %d %d %c %c\n%s",
285 x1
, y1
, width
, height
,
286 object
->picture
->angle
,
287 /* Convert the (0,1) chars to ASCII */
288 (object
->picture
->mirrored
)+0x30,
289 object
->picture
->embedded
+0x30,
290 object
->picture
->filename
);
292 if (encoded_picture
!= NULL
) {
293 g_free(encoded_picture
);
300 /*! \brief Create and add picture OBJECT to list.
301 * \par Function Description
302 * This function creates a new object representing a picture.
303 * This object is added to the end of the list <B>list_tail</B> pointed
305 * The picture is described by its upper left corner - <B>x1</B>, <B>y1</B> -
306 * and its lower right corner - <B>x2</B>, <B>y2</B>.
307 * The <B>type</B> parameter must be equal to #OBJ_PICTURE.
309 * The #OBJECT structure is allocated with the
310 * #s_basic_init_object() function. The structure describing the
311 * picture is allocated and initialized with the parameters given to the
314 * The object is added to the end of the list described by the
315 * <B>object_list</B> parameter by the #s_basic_link_object().
317 * \param [in] toplevel The TOPLEVEL object.
318 * \param [in,out] list_tail OBJECT list to add line to.
319 * \param [in] pixbuf The GdkPixbuf picture to add.
320 * A copy of this pixbuf is made.
321 * \param [in] file_content Raw data of the image file.
322 * NULL for non embedded loading. The object
323 * object takes ownership of this buffer, and it
324 * should not be free'd by the caller.
325 * \param [in] file_length Length of raw data buffer
326 * \param [in] filename File name backing this picture.
327 * A copy of this string is made.
328 * \param [in] ratio Picture height to width ratio.
329 * \param [in] type Must be OBJ_PICTURE.
330 * \param [in] x1 Upper x coordinate.
331 * \param [in] y1 Upper y coordinate.
332 * \param [in] x2 Lower x coordinate.
333 * \param [in] y2 Lower y coordinate.
334 * \param [in] angle Picture rotation angle.
335 * \param [in] mirrored Whether the image should be mirrored or not.
336 * \param [in] embedded Whether the embedded flag should be set or not.
337 * \return A pointer to the new end of the object list.
339 OBJECT
*o_picture_add(TOPLEVEL
*toplevel
, OBJECT
*list_tail
, GdkPixbuf
*pixbuf
,
340 gchar
*file_content
, gsize file_length
, char *filename
,
341 double ratio
, char type
,
342 int x1
, int y1
, int x2
, int y2
, int angle
, char mirrored
,
348 /* create the object */
349 new_node
= s_basic_init_object("picture");
350 new_node
->type
= type
;
352 picture
= (PICTURE
*) g_malloc(sizeof(PICTURE
));
353 new_node
->picture
= picture
;
355 /* describe the picture with its upper left and lower right corner */
356 picture
->upper_x
= x1
;
357 picture
->upper_y
= y1
;
358 picture
->lower_x
= x2
;
359 picture
->lower_y
= y2
;
361 picture
->file_content
= file_content
;
362 picture
->file_length
= file_length
;
363 picture
->filename
= g_strdup (filename
);
364 picture
->ratio
= ratio
;
365 picture
->original_picture
= gdk_pixbuf_copy(pixbuf
);
366 picture
->displayed_picture
= NULL
;
367 picture
->angle
= angle
;
368 picture
->mirrored
= mirrored
;
369 picture
->embedded
= embedded
;
371 new_node
->draw_func
= picture_draw_func
;
372 new_node
->sel_func
= select_func
;
374 /* compute the bounding picture */
375 o_picture_recalc(toplevel
, new_node
);
377 /* add the object to the list */
378 list_tail
= (OBJECT
*) s_basic_link_object(new_node
, list_tail
);
383 /*! \brief Recalculate picture bounding box.
384 * \par Function Description
385 * This function recalculates the bounding box of the <B>o_current</B>
386 * parameter picture object.
388 * \param [in] toplevel The TOPLEVEL object.
389 * \param [in,out] o_current Picture OBJECT to be recalculated.
391 void o_picture_recalc(TOPLEVEL
*toplevel
, OBJECT
*o_current
)
393 int left
, top
, right
, bottom
;
395 if (o_current
->picture
== NULL
) {
399 /* update the bounding picture - world units */
400 world_get_picture_bounds(toplevel
, o_current
,
401 &left
, &top
, &right
, &bottom
);
402 o_current
->w_left
= left
;
403 o_current
->w_top
= top
;
404 o_current
->w_right
= right
;
405 o_current
->w_bottom
= bottom
;
409 /*! \brief Get picture bounding rectangle in WORLD coordinates.
410 * \par Function Description
411 * This function sets the <B>left</B>, <B>top</B>, <B>right</B> and
412 * <B>bottom</B> parameters to the boundings of the picture object
413 * described in <B>*picture</B> in WORLD units.
415 * \param [in] toplevel The TOPLEVEL object.
416 * \param [in] object Picture OBJECT to read coordinates from.
417 * \param [out] left Left picture coordinate in WORLD units.
418 * \param [out] top Top picture coordinate in WORLD units.
419 * \param [out] right Right picture coordinate in WORLD units.
420 * \param [out] bottom Bottom picture coordinate in WORLD units.
422 void world_get_picture_bounds(TOPLEVEL
*toplevel
, OBJECT
*object
,
423 int *left
, int *top
, int *right
, int *bottom
)
425 *left
= min(object
->picture
->upper_x
, object
->picture
->lower_x
);
426 *top
= min(object
->picture
->upper_y
, object
->picture
->lower_y
);
427 *right
= max(object
->picture
->upper_x
, object
->picture
->lower_x
);
428 *bottom
= max(object
->picture
->upper_y
, object
->picture
->lower_y
);
432 /*! \brief Modify the description of a picture OBJECT.
433 * \par Function Description
434 * This function modifies the coordinates of one of the four corner of
435 * the picture. The new coordinates of the corner identified by
436 * <B>whichone</B> are given by <B>x</B> and <B>y</B> in world unit.
438 * The coordinates of the corner is modified in the world coordinate system.
439 * Screen coordinates and boundings are then updated.
441 * \param [in] toplevel The TOPLEVEL object.
442 * \param [in,out] object Picture OBJECT to modify.
443 * \param [in] x New x coordinate.
444 * \param [in] y New y coordinate.
445 * \param [in] whichone Which picture parameter to modify.
447 * <B>whichone</B> can have the following values:
449 * <DT>*</DT><DD>PICTURE_UPPER_LEFT
450 * <DT>*</DT><DD>PICTURE_LOWER_LEFT
451 * <DT>*</DT><DD>PICTURE_UPPER_RIGHT
452 * <DT>*</DT><DD>PICTURE_LOWER_RIGHT
456 * pb20011002 - rewritten : old one did not used x, y and whichone
458 void o_picture_modify(TOPLEVEL
*toplevel
, OBJECT
*object
,
459 int x
, int y
, int whichone
)
463 /* change the position of the selected corner */
465 case PICTURE_UPPER_LEFT
:
466 object
->picture
->upper_x
= x
;
467 tmp
= abs(object
->picture
->upper_x
- object
->picture
->lower_x
) /
468 object
->picture
->ratio
;
469 if (y
< object
->picture
->lower_y
) {
472 object
->picture
->upper_y
= object
->picture
->lower_y
+ tmp
;
475 case PICTURE_LOWER_LEFT
:
476 object
->picture
->upper_x
= x
;
477 tmp
= abs(object
->picture
->upper_x
- object
->picture
->lower_x
) /
478 object
->picture
->ratio
;
479 if (y
> object
->picture
->upper_y
) {
482 object
->picture
->lower_y
= object
->picture
->upper_y
- tmp
;
485 case PICTURE_UPPER_RIGHT
:
486 object
->picture
->lower_x
= x
;
487 tmp
= abs(object
->picture
->upper_x
- object
->picture
->lower_x
) /
488 object
->picture
->ratio
;
489 if (y
< object
->picture
->lower_y
) {
492 object
->picture
->upper_y
= object
->picture
->lower_y
+ tmp
;
495 case PICTURE_LOWER_RIGHT
:
496 object
->picture
->lower_x
= x
;
497 tmp
= abs(object
->picture
->upper_x
- object
->picture
->lower_x
) /
498 object
->picture
->ratio
;
499 if (y
> object
->picture
->upper_y
) {
502 object
->picture
->lower_y
= object
->picture
->upper_y
- tmp
;
509 /* need to update the upper left and lower right corners */
510 if(object
->picture
->upper_x
> object
->picture
->lower_x
) {
511 tmp
= object
->picture
->upper_x
;
512 object
->picture
->upper_x
= object
->picture
->lower_x
;
513 object
->picture
->lower_x
= tmp
;
516 if(object
->picture
->upper_y
< object
->picture
->lower_y
) {
517 tmp
= object
->picture
->upper_y
;
518 object
->picture
->upper_y
= object
->picture
->lower_y
;
519 object
->picture
->lower_y
= tmp
;
522 /* recalculate the screen coords and the boundings */
523 o_picture_recalc(toplevel
, object
);
526 /*! \brief Rotate picture OBJECT using WORLD coordinates.
527 * \par Function Description
528 * This function rotates the picture described by <B>*object</B> around
529 * the (<B>world_centerx</B>, <B>world_centery</B>) point by <B>angle</B>
531 * The center of rotation is in world units.
533 * \param [in] toplevel The TOPLEVEL object.
534 * \param [in] world_centerx Rotation center x coordinate in
536 * \param [in] world_centery Rotation center y coordinate in
538 * \param [in] angle Rotation angle in degrees (See note below).
539 * \param [in,out] object Picture OBJECT to rotate.
541 void o_picture_rotate_world(TOPLEVEL
*toplevel
,
542 int world_centerx
, int world_centery
, int angle
,
548 /* Only 90 degree multiple and positive angles are allowed. */
549 /* angle must be positive */
550 if(angle
< 0) angle
= -angle
;
551 /* angle must be a 90 multiple or no rotation performed */
552 if((angle
% 90) != 0) return;
554 object
->picture
->angle
= ( object
->picture
->angle
+ angle
) % 360;
556 /* The center of rotation (<B>world_centerx</B>, <B>world_centery</B>) is
557 * translated to the origin. The rotation of the upper left and lower
558 * right corner are then performed. Finally, the rotated picture is
559 * translated back to its previous location.
561 /* translate object to origin */
562 object
->picture
->upper_x
-= world_centerx
;
563 object
->picture
->upper_y
-= world_centery
;
564 object
->picture
->lower_x
-= world_centerx
;
565 object
->picture
->lower_y
-= world_centery
;
567 /* rotate the upper left corner of the picture */
568 rotate_point_90(object
->picture
->upper_x
, object
->picture
->upper_y
, angle
,
571 /* rotate the lower left corner of the picture */
572 rotate_point_90(object
->picture
->lower_x
, object
->picture
->lower_y
, angle
,
575 /* reorder the corners after rotation */
576 object
->picture
->upper_x
= min(newx1
,newx2
);
577 object
->picture
->upper_y
= max(newy1
,newy2
);
578 object
->picture
->lower_x
= max(newx1
,newx2
);
579 object
->picture
->lower_y
= min(newy1
,newy2
);
581 /* translate object back to normal position */
582 object
->picture
->upper_x
+= world_centerx
;
583 object
->picture
->upper_y
+= world_centery
;
584 object
->picture
->lower_x
+= world_centerx
;
585 object
->picture
->lower_y
+= world_centery
;
587 /* recalc boundings and screen coords */
588 o_picture_recalc(toplevel
, object
);
592 /*! \brief Mirror a picture using WORLD coordinates.
593 * \par Function Description
594 * This function mirrors the picture from the point
595 * (<B>world_centerx</B>,<B>world_centery</B>) in world unit.
597 * The picture is first translated to the origin, then mirrored and
598 * finally translated back at its previous position.
600 * \param [in] toplevel The TOPLEVEL object.
601 * \param [in] world_centerx Origin x coordinate in WORLD units.
602 * \param [in] world_centery Origin y coordinate in WORLD units.
603 * \param [in,out] object Picture OBJECT to mirror.
605 void o_picture_mirror_world(TOPLEVEL
*toplevel
,
606 int world_centerx
, int world_centery
,
613 /* Set info in object */
614 object
->picture
->mirrored
= (object
->picture
->mirrored
^ 1) & 1;
616 /* translate object to origin */
617 object
->picture
->upper_x
-= world_centerx
;
618 object
->picture
->upper_y
-= world_centery
;
619 object
->picture
->lower_x
-= world_centerx
;
620 object
->picture
->lower_y
-= world_centery
;
622 /* mirror the corners */
623 newx1
= -object
->picture
->upper_x
;
624 newy1
= object
->picture
->upper_y
;
625 newx2
= -object
->picture
->lower_x
;
626 newy2
= object
->picture
->lower_y
;
628 /* reorder the corners */
629 object
->picture
->upper_x
= min(newx1
,newx2
);
630 object
->picture
->upper_y
= max(newy1
,newy2
);
631 object
->picture
->lower_x
= max(newx1
,newx2
);
632 object
->picture
->lower_y
= min(newy1
,newy2
);
634 /* translate back in position */
635 object
->picture
->upper_x
+= world_centerx
;
636 object
->picture
->upper_y
+= world_centery
;
637 object
->picture
->lower_x
+= world_centerx
;
638 object
->picture
->lower_y
+= world_centery
;
640 /* recalc boundings and screen coords */
641 o_picture_recalc(toplevel
, object
);
645 /*! \brief Translate a picture position in WORLD coordinates by a delta.
646 * \par Function Description
647 * This function applies a translation of (<B>x1</B>,<B>y1</B>) to the picture
648 * described by <B>*object</B>. <B>x1</B> and <B>y1</B> are in world units.
650 * \param [in] toplevel The TOPLEVEL object.
651 * \param [in] x1 x distance to move.
652 * \param [in] y1 y distance to move.
653 * \param [in,out] object Picture OBJECT to translate.
655 void o_picture_translate_world(TOPLEVEL
*toplevel
,
656 int x1
, int y1
, OBJECT
*object
)
658 if (object
== NULL
) printf("btw NO!\n");
660 /* Do world coords */
661 object
->picture
->upper_x
= object
->picture
->upper_x
+ x1
;
662 object
->picture
->upper_y
= object
->picture
->upper_y
+ y1
;
663 object
->picture
->lower_x
= object
->picture
->lower_x
+ x1
;
664 object
->picture
->lower_y
= object
->picture
->lower_y
+ y1
;
666 /* recalc the screen coords and the bounding picture */
667 o_picture_recalc(toplevel
, object
);
670 /*! \brief Create a copy of a picture.
671 * \par Function Description
672 * This function creates a verbatim copy of the object pointed by
673 * <B>o_current</B> describing a picture. The new object is added at the
674 * end of the list, following the <B>list_tail</B> pointed object.
676 * \param [in] toplevel The TOPLEVEL object.
677 * \param [out] list_tail OBJECT list to copy to.
678 * \param [in] objcet Picture OBJECT to copy.
679 * \return A new pointer to the end of the object list.
681 OBJECT
*o_picture_copy(TOPLEVEL
*toplevel
, OBJECT
*list_tail
,
687 /* create the object */
688 new_node
= s_basic_init_object("picture");
689 new_node
->type
= object
->type
;
691 picture
= g_malloc(sizeof(PICTURE
));
692 new_node
->picture
= picture
;
694 if (object
->saved_color
== -1) {
695 new_node
->color
= object
->color
;
697 new_node
->color
= object
->saved_color
;
700 /* describe the picture with its upper left and lower right corner */
701 picture
->upper_x
= object
->picture
->upper_x
;
702 picture
->upper_y
= object
->picture
->upper_y
;
703 picture
->lower_x
= object
->picture
->lower_x
;
704 picture
->lower_y
= object
->picture
->lower_y
;
706 if (object
->picture
->file_content
!= NULL
) {
707 picture
->file_content
= g_malloc (object
->picture
->file_length
);
708 memcpy (picture
->file_content
, object
->picture
->file_content
,
709 object
->picture
->file_length
);
711 picture
->file_content
= NULL
;
714 picture
->file_length
= object
->picture
->file_length
;
715 picture
->filename
= g_strdup (object
->picture
->filename
);
716 picture
->ratio
= object
->picture
->ratio
;
717 picture
->angle
= object
->picture
->angle
;
718 picture
->mirrored
= object
->picture
->mirrored
;
719 picture
->embedded
= object
->picture
->embedded
;
721 /* Copy the picture data */
722 picture
->original_picture
=
723 gdk_pixbuf_copy(object
->picture
->original_picture
);
725 picture
->displayed_picture
=
726 gdk_pixbuf_copy(object
->picture
->displayed_picture
);
728 new_node
->draw_func
= object
->draw_func
;
729 new_node
->sel_func
= object
->sel_func
;
731 /* compute the bounding picture */
732 o_picture_recalc(toplevel
, new_node
);
734 /* add the object to the list */
735 list_tail
= (OBJECT
*) s_basic_link_object(new_node
, list_tail
);
737 /* return the new tail of the object list */
742 /*! \brief Get RGB data from image.
743 * \par Function Description
744 * This function returns the RGB data of the given image.
745 * Function taken from the DIA source code (http://www.gnome.org/projects/dia)
746 * and licensed under the GNU GPL version 2.
748 * \param [in] image GdkPixbuf image to read RGB data from.
749 * \return Array of rgb data from image.
752 * Caller must g_free returned guint8 array.
754 guint8
*o_picture_rgb_data(GdkPixbuf
*image
)
756 int width
= gdk_pixbuf_get_width(image
);
757 int height
= gdk_pixbuf_get_height(image
);
758 int rowstride
= gdk_pixbuf_get_rowstride(image
);
759 int size
= height
*rowstride
;
760 guint8
*rgb_pixels
= g_malloc(size
);
762 if (gdk_pixbuf_get_has_alpha(image
)) {
763 guint8
*pixels
= gdk_pixbuf_get_pixels(image
);
765 for (i
= 0; i
< height
; i
++) {
766 for (j
= 0; j
< width
; j
++) {
767 rgb_pixels
[i
*rowstride
+j
*3] = pixels
[i
*rowstride
+j
*4];
768 rgb_pixels
[i
*rowstride
+j
*3+1] = pixels
[i
*rowstride
+j
*4+1];
769 rgb_pixels
[i
*rowstride
+j
*3+2] = pixels
[i
*rowstride
+j
*4+2];
774 guint8
*pixels
= gdk_pixbuf_get_pixels(image
);
776 g_memmove(rgb_pixels
, pixels
, height
*rowstride
);
781 /*! \brief Get mask data from image.
782 * \par Function Description
783 * This function returns the mask data of the given image.
784 * Function taken from the DIA source code (http://www.gnome.org/projects/dia)
785 * and licensed under the GNU GPL version 2.
787 * \param [in] image GdkPixbuf image to get mask data from.
788 * \return Array of mask data from image.
791 * Caller must g_free returned guint8 array.
793 guint8
*o_picture_mask_data(GdkPixbuf
*image
)
799 if (!gdk_pixbuf_get_has_alpha(image
)) {
803 pixels
= gdk_pixbuf_get_pixels(image
);
805 size
= gdk_pixbuf_get_width(image
)*
806 gdk_pixbuf_get_height(image
);
808 mask
= g_malloc(size
);
810 /* Pick every fourth byte (the alpha channel) into mask */
811 for (i
= 0; i
< size
; i
++)
812 mask
[i
] = pixels
[i
*4+3];
817 /*! \brief Print picture to Postscript document.
818 * \par Function Description
819 * This function prints a picture object. The picture is defined by the
820 * coordinates of its upper left corner in (<B>x</B>,<B>y</B>) and its width
821 * and height given by the <B>width</B> and <B>height</B> parameters.
822 * The Postscript document is defined by the file pointer <B>fp</B>.
823 * Function based on the DIA source code (http://www.gnome.org/projects/dia)
824 * and licensed under the GNU GPL version 2.
826 * All dimensions are in mils.
828 * \param [in] toplevel The TOPLEVEL object.
829 * \param [in] fp FILE pointer to Postscript document.
830 * \param [in] o_current Picture OBJECT to write to document.
831 * \param [in] origin_x Page x coordinate to place picture OBJECT.
832 * \param [in] origin_y Page y coordinate to place picture OBJECT.
834 void o_picture_print(TOPLEVEL
*toplevel
, FILE *fp
, OBJECT
*o_current
,
835 int origin_x
, int origin_y
)
839 GdkPixbuf
* image
= o_current
->picture
->original_picture
;
840 int img_width
, img_height
, img_rowstride
;
845 /* calculate the width and height of the box */
846 width
= abs(o_current
->picture
->lower_x
- o_current
->picture
->upper_x
);
847 height
= abs(o_current
->picture
->upper_y
- o_current
->picture
->lower_y
);
849 /* calculate the origin of the box */
850 x1
= o_current
->picture
->upper_x
;
851 y1
= o_current
->picture
->upper_y
;
853 img_width
= gdk_pixbuf_get_width(image
);
854 img_rowstride
= gdk_pixbuf_get_rowstride(image
);
855 img_height
= gdk_pixbuf_get_height(image
);
857 rgb_data
= o_picture_rgb_data(image
);
858 mask_data
= o_picture_mask_data(image
);
860 ratio
= height
/width
;
862 fprintf(fp
, "gsave\n");
864 /* color output only */
865 fprintf(fp
, "/pix %i string def\n", img_width
* 3);
866 fprintf(fp
, "%i %i 8\n", img_width
, img_height
);
867 fprintf(fp
, "%i %i translate\n", x1
, y1
);
868 fprintf(fp
, "%i %i scale\n", width
, height
);
869 fprintf(fp
, "[%i 0 0 -%i 0 0]\n", img_width
, img_height
);
871 fprintf(fp
, "{currentfile pix readhexstring pop}\n");
872 fprintf(fp
, "false 3 colorimage\n");
876 for (y
= 0; y
< img_height
; y
++) {
877 for (x
= 0; x
< img_width
; x
++) {
878 int i
= y
*img_rowstride
+x
*3;
879 int m
= y
*img_width
+x
;
880 fprintf(fp
, "%02x", 255-(mask_data
[m
]*(255-rgb_data
[i
])/255));
881 fprintf(fp
, "%02x", 255-(mask_data
[m
]*(255-rgb_data
[i
+1])/255));
882 fprintf(fp
, "%02x", 255-(mask_data
[m
]*(255-rgb_data
[i
+2])/255));
887 for (y
= 0; y
< img_height
; y
++) {
888 for (x
= 0; x
< img_width
; x
++) {
889 int i
= y
*img_rowstride
+x
*3;
890 fprintf(fp
, "%02x", (int)(rgb_data
[i
]));
891 fprintf(fp
, "%02x", (int)(rgb_data
[i
+1]));
892 fprintf(fp
, "%02x", (int)(rgb_data
[i
+2]));
897 fprintf(fp
, "grestore\n");
907 /*! \brief Embed the image file associated with a picture
909 * \par Function Description
910 * This function reads and embeds image file associated with the picture.
912 * \param [in] toplevel The TOPLEVEL object.
913 * \param [in] object The picture OBJECT to embed
915 void o_picture_embed (TOPLEVEL
*toplevel
, OBJECT
*object
)
921 /* Free any existing embedded data */
922 g_free (object
->picture
->file_content
);
923 object
->picture
->file_content
= NULL
;
925 g_file_get_contents (object
->picture
->filename
,
926 &object
->picture
->file_content
,
927 &object
->picture
->file_length
,
930 s_log_message (_("Failed to load image from file [%s]: %s\n"),
931 object
->picture
->filename
, err
->message
);
936 object
->picture
->embedded
= 1;
938 pixbuf
= o_picture_pixbuf_from_buffer (object
->picture
->file_content
,
939 object
->picture
->file_length
,
942 s_log_message (_("Failed to load image from embedded data [%s]: %s\n"),
943 object
->picture
->filename
, err
->message
);
944 s_log_message (_("Falling back to file loading. Picture unembedded.\n"));
946 object
->picture
->embedded
= 0;
950 /* Change to the new pixbuf loaded before we embedded. */
951 if (object
->picture
->original_picture
!= NULL
)
952 g_object_unref(object
->picture
->original_picture
);
954 object
->picture
->original_picture
= pixbuf
;
956 filename
= g_path_get_basename(object
->picture
->filename
);
957 s_log_message (_("Picture [%s] has been embedded\n"), filename
);
962 /*! \brief Unembed a picture, reloading the image from disk
964 * \par Function Description
965 * This function re-reads the image file associated with the picture, and
966 * discards the embeded copy of the file.
968 * \param [in] toplevel The TOPLEVEL object.
969 * \param [in] object The picture OBJECT to unembed
971 void o_picture_unembed (TOPLEVEL
*toplevel
, OBJECT
*object
)
977 pixbuf
= gdk_pixbuf_new_from_file (object
->picture
->filename
, &err
);
979 s_log_message (_("Failed to load image from file [%s]: %s\n"),
980 object
->picture
->filename
, err
->message
);
985 /* Change to the new pixbuf loaded from the file. */
986 if (object
->picture
->original_picture
!= NULL
)
987 g_object_unref(object
->picture
->original_picture
);
989 object
->picture
->original_picture
= pixbuf
;
991 g_free (object
->picture
->file_content
);
992 object
->picture
->file_content
= NULL
;
993 object
->picture
->file_length
= 0;
994 object
->picture
->embedded
= 0;
996 filename
= g_path_get_basename(object
->picture
->filename
);
997 s_log_message (_("Picture [%s] has been unembedded\n"), filename
);
1002 /*! \brief Load a GdkPixbuf from a memory buffer
1004 * \par Function Description
1005 * This function loads a GdkPixbuf from a memory buffer. The pixbuf
1006 * returned already has a reference taken out on the callers behalf.
1008 * \param [in] file_content The memory buffer containing the image data.
1009 * \param [in] file_length The size of the image data
1010 * \param [out] err GError** pointer to return any error messages.
1011 * \return A GdkPixbuf loaded from the image data, or NULL on error.
1014 GdkPixbuf
*o_picture_pixbuf_from_buffer (gchar
*file_content
,
1018 GdkPixbufLoader
*loader
;
1021 loader
= gdk_pixbuf_loader_new();
1023 gdk_pixbuf_loader_write (loader
, (guchar
*)file_content
,
1025 if (err
!= NULL
&& *err
!= NULL
)
1028 gdk_pixbuf_loader_close (loader
, err
);
1029 if (err
!= NULL
&& *err
!= NULL
)
1032 pixbuf
= gdk_pixbuf_loader_get_pixbuf (loader
);
1035 g_object_ref (pixbuf
);
1037 g_object_unref (loader
);