libgeda: fix memory leak introduced with the last commit.
[geda-gaf/werner.git] / libgeda / src / o_picture.c
blobc404dfb5dddbdd6ca17de2c86476e5b51337b23f
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
20 #include <config.h>
22 #include <stdio.h>
23 #ifdef HAVE_STRING_H
24 #include <string.h>
25 #endif
26 #include <math.h>
28 /* for basename(3) */
29 #ifdef HAVE_LIBGEN_H
30 #include <libgen.h>
31 #endif
33 #include <gtk/gtk.h>
34 #include <guile/gh.h>
36 #include <gdk/gdk.h>
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,
61 TextBuffer *tb,
62 unsigned int release_ver,
63 unsigned int fileformat_ver)
65 int x1, y1;
66 int width, height, angle;
67 gchar mirrored, embedded;
68 int num_conv;
69 gchar type;
70 gchar *line = NULL;
71 gchar *filename;
72 GdkPixbuf *pixbuf = NULL;
73 gchar *file_content = NULL;
74 guint file_length = 0;
75 GError *err = NULL;
76 static char gdk_initialized=0;
78 /* Initialize GDK first in case this isn't a graphic app */
79 if (gdk_initialized == 0) {
80 gdk_init(NULL, NULL);
81 gdk_initialized = 1;
84 num_conv = sscanf(first_line, "%c %d %d %d %d %d %c %c\n",
85 &type, &x1, &y1, &width, &height, &angle, &mirrored, &embedded);
87 if (num_conv != 8) {
88 s_log_message (_("Error reading picture definition line: %s.\n"),
89 first_line);
92 /* Convert from ascii character to number */
93 if (g_ascii_isdigit(mirrored)) {
94 mirrored -= 0x30;
97 if (g_ascii_isdigit(embedded)) {
98 embedded -= 0x30;
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"),
108 mirrored);
109 s_log_message(_("Setting mirrored to 0\n"));
110 mirrored = 0;
113 if ( (embedded > 1) || (embedded < 0)) {
114 s_log_message(_("Found a picture with a wrong 'embedded' parameter: %c.\n"),
115 embedded);
116 s_log_message(_("Setting embedded to 0\n"));
117 embedded = 0;
119 switch(angle) {
121 case(0):
122 case(90):
123 case(180):
124 case(270):
125 break;
127 default:
128 s_log_message(_("Found an unsupported picture angle [ %d ]\n"), angle);
129 s_log_message(_("Setting angle to 0\n"));
130 angle=0;
131 break;
135 filename = g_strdup(s_textbuffer_next_line(tb));
136 filename = remove_last_nl(filename);
138 if (embedded == 1) {
139 GString *encoded_picture=g_string_new("");
140 char finished = 0;
142 /* Read the encoded picture */
143 do {
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);
150 } else {
151 finished = 1;
153 } while (finished == 0);
155 /* Decode the picture */
156 file_content = s_encoding_base64_decode(encoded_picture->str,
157 encoded_picture->len,
158 &file_length);
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"));
167 embedded = 0;
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);
174 if (err != NULL) {
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"));
178 g_error_free (err);
179 err = NULL;
180 embedded = 0;
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);
187 if (err != NULL) {
188 s_log_message (_("Failed to load image from file [%s]: %s\n"),
189 filename, err->message);
190 g_error_free (err);
191 err = NULL;
195 /* If the pixbuf couldn't be loaded, then try to load a warning picture */
196 if (pixbuf == NULL) {
197 char *temp_filename;
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"),
206 temp_filename);
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,
216 type,
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 */
222 return(object_list);
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.
234 * \note
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;
242 gchar *out=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*/
253 #if DEBUG
254 printf("picture: %d %d %d %d\n", x1, y1, width, height);
255 #endif
257 /* Encode the picture if it's embedded */
258 if (object->picture->embedded == 1) {
259 encoded_picture =
260 s_encoding_base64_encode( (char *)object->picture->file_content,
261 object->picture->file_length,
262 &encoded_picture_length,
263 TRUE);
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",
272 object->type,
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,
279 encoded_picture,
280 ".");
282 else {
283 out = g_strdup_printf("%c %d %d %d %d %d %c %c\n%s",
284 object->type,
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);
296 return(out);
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
304 * object belongs to.
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
312 * function.
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,
343 char embedded)
345 OBJECT *new_node;
346 PICTURE *picture;
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);
380 return(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) {
396 return;
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:
448 * <DL>
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
453 * </DL>
455 * \par Author's note
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)
461 int tmp;
463 /* change the position of the selected corner */
464 switch(whichone) {
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) {
470 tmp = -tmp;
472 object->picture->upper_y = object->picture->lower_y + tmp;
473 break;
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) {
480 tmp = -tmp;
482 object->picture->lower_y = object->picture->upper_y - tmp;
483 break;
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) {
490 tmp = -tmp;
492 object->picture->upper_y = object->picture->lower_y + tmp;
493 break;
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) {
500 tmp = -tmp;
502 object->picture->lower_y = object->picture->upper_y - tmp;
503 break;
505 default:
506 return;
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>
530 * degrees.
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
535 * WORLD units.
536 * \param [in] world_centery Rotation center y coordinate in
537 * WORLD units.
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,
543 OBJECT *object)
545 int newx1, newy1;
546 int newx2, newy2;
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,
569 &newx1, &newy1);
571 /* rotate the lower left corner of the picture */
572 rotate_point_90(object->picture->lower_x, object->picture->lower_y, angle,
573 &newx2, &newy2);
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,
607 OBJECT *object)
609 int newx1, newy1;
610 int newx2, newy2;
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,
682 OBJECT *object)
684 OBJECT *new_node;
685 PICTURE *picture;
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;
696 } else {
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);
710 } else {
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 */
738 return(list_tail);
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.
751 * \note
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);
764 int i, j;
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];
772 return rgb_pixels;
773 } else {
774 guint8 *pixels = gdk_pixbuf_get_pixels(image);
776 g_memmove(rgb_pixels, pixels, height*rowstride);
777 return rgb_pixels;
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.
790 * \note
791 * Caller must g_free returned guint8 array.
793 guint8 *o_picture_mask_data(GdkPixbuf *image)
795 guint8 *pixels;
796 guint8 *mask;
797 int i, size;
799 if (!gdk_pixbuf_get_has_alpha(image)) {
800 return NULL;
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];
814 return mask;
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)
837 int x1, y1, x, y;
838 int height, width;
839 GdkPixbuf* image = o_current->picture->original_picture;
840 int img_width, img_height, img_rowstride;
841 double ratio;
842 guint8 *rgb_data;
843 guint8 *mask_data;
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");
873 fprintf(fp, "\n");
875 if (mask_data) {
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));
884 fprintf(fp, "\n");
886 } else {
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]));
894 fprintf(fp, "\n");
897 fprintf(fp, "grestore\n");
898 fprintf(fp, "\n");
900 g_free(rgb_data);
901 g_free(mask_data);
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)
917 GError *err = NULL;
918 GdkPixbuf *pixbuf;
919 gchar *filename;
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,
928 &err);
929 if (err != NULL) {
930 s_log_message (_("Failed to load image from file [%s]: %s\n"),
931 object->picture->filename, err->message);
932 g_error_free (err);
933 return;
936 object->picture->embedded = 1;
938 pixbuf = o_picture_pixbuf_from_buffer (object->picture->file_content,
939 object->picture->file_length,
940 &err);
941 if (err != NULL) {
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"));
945 g_error_free (err);
946 object->picture->embedded = 0;
947 return;
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);
958 g_free(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)
973 GError *err = NULL;
974 GdkPixbuf *pixbuf;
975 gchar *filename;
977 pixbuf = gdk_pixbuf_new_from_file (object->picture->filename, &err);
978 if (err != NULL) {
979 s_log_message (_("Failed to load image from file [%s]: %s\n"),
980 object->picture->filename, err->message);
981 g_error_free (err);
982 return;
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);
998 g_free(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,
1015 gsize file_length,
1016 GError **err)
1018 GdkPixbufLoader *loader;
1019 GdkPixbuf *pixbuf;
1021 loader = gdk_pixbuf_loader_new();
1023 gdk_pixbuf_loader_write (loader, (guchar *)file_content,
1024 file_length, err);
1025 if (err != NULL && *err != NULL)
1026 return NULL;
1028 gdk_pixbuf_loader_close (loader, err);
1029 if (err != NULL && *err != NULL)
1030 return NULL;
1032 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
1034 if (pixbuf != NULL)
1035 g_object_ref (pixbuf);
1037 g_object_unref (loader);
1039 return pixbuf;