libgeda
|
00001 /* gEDA - GPL Electronic Design Automation 00002 * libgeda - gEDA's library 00003 * Copyright (C) 1998-2010 Ales Hvezda 00004 * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details) 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00025 #include <config.h> 00026 00027 #include <stdio.h> 00028 #ifdef HAVE_STRING_H 00029 #include <string.h> 00030 #endif 00031 #include <math.h> 00032 00033 #include <gdk-pixbuf/gdk-pixbuf.h> 00034 #include <gio/gio.h> 00035 00036 #include "libgeda_priv.h" 00037 00050 OBJECT *o_picture_read (TOPLEVEL *toplevel, 00051 const char *first_line, 00052 TextBuffer *tb, 00053 unsigned int release_ver, 00054 unsigned int fileformat_ver, 00055 GError **err) 00056 { 00057 OBJECT *new_obj; 00058 int x1, y1; 00059 int width, height, angle; 00060 int mirrored, embedded; 00061 int num_conv; 00062 gchar type; 00063 const gchar *line = NULL; 00064 gchar *filename; 00065 gchar *file_content = NULL; 00066 guint file_length = 0; 00067 00068 num_conv = sscanf(first_line, "%c %d %d %d %d %d %d %d\n", 00069 &type, &x1, &y1, &width, &height, &angle, &mirrored, &embedded); 00070 00071 if (num_conv != 8) { 00072 g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse picture definition")); 00073 return NULL; 00074 } 00075 00076 if (width == 0 || height == 0) { 00077 s_log_message(_("Found a zero width/height picture [ %c %d %d %d %d ]\n"), 00078 type, x1, y1, width, height); 00079 } 00080 00081 if ( (mirrored > 1) || (mirrored < 0)) { 00082 s_log_message(_("Found a picture with a wrong 'mirrored' parameter: %d.\n"), 00083 mirrored); 00084 s_log_message(_("Setting mirrored to 0\n")); 00085 mirrored = 0; 00086 } 00087 00088 if ( (embedded > 1) || (embedded < 0)) { 00089 s_log_message(_("Found a picture with a wrong 'embedded' parameter: %d.\n"), 00090 embedded); 00091 s_log_message(_("Setting embedded to 0\n")); 00092 embedded = 0; 00093 } 00094 00095 switch(angle) { 00096 00097 case(0): 00098 case(90): 00099 case(180): 00100 case(270): 00101 break; 00102 00103 default: 00104 s_log_message(_("Found an unsupported picture angle [ %d ]\n"), angle); 00105 s_log_message(_("Setting angle to 0\n")); 00106 angle=0; 00107 break; 00108 00109 } 00110 00111 filename = g_strdup(s_textbuffer_next_line(tb)); 00112 filename = remove_last_nl(filename); 00113 00114 /* Handle empty filenames */ 00115 if (strlen (filename) == 0) { 00116 s_log_message (_("Found an image with no filename.")); 00117 g_free (filename); 00118 filename = NULL; 00119 } 00120 00121 if (embedded == 1) { 00122 GString *encoded_picture=g_string_new(""); 00123 char finished = 0; 00124 00125 /* Read the encoded picture */ 00126 do { 00127 00128 line = s_textbuffer_next_line(tb); 00129 if (line == NULL) break; 00130 00131 if (g_strcasecmp(line, ".\n") != 0) { 00132 encoded_picture = g_string_append (encoded_picture, line); 00133 } else { 00134 finished = 1; 00135 } 00136 } while (finished == 0); 00137 00138 /* Decode the picture */ 00139 if (encoded_picture != NULL) { 00140 file_content = s_encoding_base64_decode(encoded_picture->str, 00141 encoded_picture->len, 00142 &file_length); 00143 g_string_free (encoded_picture, TRUE); 00144 } 00145 00146 if (file_content == NULL) { 00147 s_log_message (_("Failed to load image from embedded data [%s]: %s\n"), 00148 filename, _("Base64 decoding failed.")); 00149 s_log_message (_("Falling back to file loading. Picture unembedded.\n")); 00150 embedded = 0; 00151 } 00152 } 00153 00154 /* create the picture */ 00155 /* The picture is described by its upper left and lower right corner */ 00156 new_obj = o_picture_new (toplevel, file_content, file_length, filename, 00157 type, 00158 x1, y1+height, x1+width, y1, 00159 angle, mirrored, embedded); 00160 00161 g_free (file_content); 00162 g_free (filename); 00163 00164 return new_obj; 00165 } 00166 00180 char *o_picture_save(TOPLEVEL *toplevel, OBJECT *object) 00181 { 00182 int width, height, x1, y1; 00183 gchar *encoded_picture=NULL; 00184 gchar *out=NULL; 00185 guint encoded_picture_length; 00186 const gchar *filename = NULL; 00187 00188 /* calculate the width and height of the box */ 00189 width = abs(object->picture->lower_x - object->picture->upper_x); 00190 height = abs(object->picture->upper_y - object->picture->lower_y); 00191 00192 /* calculate the lower left corner of the box */ 00193 x1 = object->picture->upper_x; 00194 y1 = object->picture->upper_y - height; /* move the origin to 0, 0*/ 00195 00196 #if DEBUG 00197 printf("picture: %d %d %d %d\n", x1, y1, width, height); 00198 #endif 00199 00200 /* Encode the picture if it's embedded */ 00201 if (o_picture_is_embedded (toplevel, object)) { 00202 encoded_picture = 00203 s_encoding_base64_encode( (char *)object->picture->file_content, 00204 object->picture->file_length, 00205 &encoded_picture_length, 00206 TRUE); 00207 if (encoded_picture == NULL) { 00208 s_log_message(_("ERROR: o_picture_save: unable to encode the picture.\n")); 00209 } 00210 } 00211 00212 /* Cope with null filename */ 00213 filename = o_picture_get_filename (toplevel, object); 00214 if (filename == NULL) filename = ""; 00215 00216 if (o_picture_is_embedded (toplevel, object) && 00217 encoded_picture != NULL) { 00218 out = g_strdup_printf("%c %d %d %d %d %d %c %c\n%s\n%s\n%s", 00219 object->type, 00220 x1, y1, width, height, 00221 object->picture->angle, 00222 /* Convert the (0,1) chars to ASCII */ 00223 (object->picture->mirrored)+0x30, 00224 '1', 00225 filename, 00226 encoded_picture, 00227 "."); 00228 } 00229 else { 00230 out = g_strdup_printf("%c %d %d %d %d %d %c %c\n%s", 00231 object->type, 00232 x1, y1, width, height, 00233 object->picture->angle, 00234 /* Convert the (0,1) chars to ASCII */ 00235 (object->picture->mirrored)+0x30, 00236 '0', 00237 filename); 00238 } 00239 g_free(encoded_picture); 00240 00241 return(out); 00242 } 00243 00244 00273 OBJECT *o_picture_new (TOPLEVEL *toplevel, 00274 const gchar *file_content, gsize file_length, 00275 const gchar *filename, 00276 char type, int x1, int y1, int x2, int y2, int angle, 00277 int mirrored, int embedded) 00278 { 00279 OBJECT *new_node; 00280 PICTURE *picture; 00281 00282 /* create the object */ 00283 new_node = s_basic_new_object(type, "picture"); 00284 00285 picture = (PICTURE *) g_malloc0 (sizeof(PICTURE)); 00286 new_node->picture = picture; 00287 00288 /* describe the picture with its upper left and lower right corner */ 00289 picture->upper_x = (x1 > x2) ? x2 : x1; 00290 picture->upper_y = (y1 > y2) ? y1 : y2; 00291 picture->lower_x = (x1 > x2) ? x1 : x2; 00292 picture->lower_y = (y1 > y2) ? y2 : y1; 00293 00294 picture->pixbuf = NULL; 00295 picture->file_content = NULL; 00296 picture->file_length = 0; 00297 00298 picture->ratio = abs ((double) (x1 - x2) / (y1 - y2)); 00299 picture->filename = g_strdup (filename); 00300 picture->angle = angle; 00301 picture->mirrored = mirrored; 00302 picture->embedded = embedded; 00303 00304 if (file_content != NULL) { 00305 GError *error = NULL; 00306 if (!o_picture_set_from_buffer (toplevel, new_node, filename, 00307 file_content, file_length, &error)) { 00308 s_log_message (_("Failed to load buffer image [%s]: %s\n"), 00309 filename, error->message); 00310 g_error_free (error); 00311 00312 /* Force the data into the object anyway, so as to prevent data 00313 * loss of embedded images. */ 00314 picture->file_content = g_memdup (file_content, file_length); 00315 picture->file_length = file_length; 00316 } 00317 } 00318 if (picture->pixbuf == NULL && filename != NULL) { 00319 GError *error = NULL; 00320 if (!o_picture_set_from_file (toplevel, new_node, filename, &error)) { 00321 s_log_message (_("Failed to load image from [%s]: %s\n"), 00322 filename, error->message); 00323 g_error_free (error); 00324 } 00325 } 00326 00327 /* compute the bounding picture */ 00328 o_picture_recalc(toplevel, new_node); 00329 00330 return new_node; 00331 } 00332 00341 void o_picture_recalc(TOPLEVEL *toplevel, OBJECT *o_current) 00342 { 00343 int left, top, right, bottom; 00344 00345 if (o_current->picture == NULL) { 00346 return; 00347 } 00348 00349 /* update the bounding picture - world units */ 00350 world_get_picture_bounds(toplevel, o_current, 00351 &left, &top, &right, &bottom); 00352 o_current->w_left = left; 00353 o_current->w_top = top; 00354 o_current->w_right = right; 00355 o_current->w_bottom = bottom; 00356 o_current->w_bounds_valid = TRUE; 00357 } 00358 00372 void world_get_picture_bounds(TOPLEVEL *toplevel, OBJECT *object, 00373 int *left, int *top, int *right, int *bottom) 00374 { 00375 *left = min(object->picture->upper_x, object->picture->lower_x); 00376 *top = min(object->picture->upper_y, object->picture->lower_y); 00377 *right = max(object->picture->upper_x, object->picture->lower_x); 00378 *bottom = max(object->picture->upper_y, object->picture->lower_y); 00379 00380 } 00381 00392 gboolean o_picture_get_position (TOPLEVEL *toplevel, gint *x, gint *y, 00393 OBJECT *object) 00394 { 00395 *x = min(object->picture->lower_x, object->picture->upper_x); 00396 *y = min(object->picture->lower_y, object->picture->upper_y); 00397 return TRUE; 00398 } 00399 00400 00411 double 00412 o_picture_get_ratio (TOPLEVEL *toplevel, OBJECT *object) 00413 { 00414 g_return_val_if_fail (object != NULL, 1); 00415 g_return_val_if_fail (object->picture != NULL, 1); 00416 00417 /* The effective ratio varies depending on the rotation of the 00418 * image. */ 00419 switch (object->picture->angle) { 00420 case 0: 00421 case 180: 00422 return object->picture->ratio; 00423 case 90: 00424 case 270: 00425 return 1.0 / object->picture->ratio; 00426 default: 00427 g_critical (_("Picture %p has invalid angle %i\n"), object, 00428 object->picture->angle); 00429 } 00430 return 0; 00431 } 00432 00456 void o_picture_modify(TOPLEVEL *toplevel, OBJECT *object, 00457 int x, int y, int whichone) 00458 { 00459 int tmp; 00460 double ratio = o_picture_get_ratio (toplevel, object); 00461 00462 o_emit_pre_change_notify (toplevel, object); 00463 00464 /* change the position of the selected corner */ 00465 switch(whichone) { 00466 case PICTURE_UPPER_LEFT: 00467 object->picture->upper_x = x; 00468 tmp = abs(object->picture->upper_x - object->picture->lower_x) / ratio; 00469 if (y < object->picture->lower_y) { 00470 tmp = -tmp; 00471 } 00472 object->picture->upper_y = object->picture->lower_y + tmp; 00473 break; 00474 00475 case PICTURE_LOWER_LEFT: 00476 object->picture->upper_x = x; 00477 tmp = abs(object->picture->upper_x - object->picture->lower_x) / ratio; 00478 if (y > object->picture->upper_y) { 00479 tmp = -tmp; 00480 } 00481 object->picture->lower_y = object->picture->upper_y - tmp; 00482 break; 00483 00484 case PICTURE_UPPER_RIGHT: 00485 object->picture->lower_x = x; 00486 tmp = abs(object->picture->upper_x - object->picture->lower_x) / ratio; 00487 if (y < object->picture->lower_y) { 00488 tmp = -tmp; 00489 } 00490 object->picture->upper_y = object->picture->lower_y + tmp; 00491 break; 00492 00493 case PICTURE_LOWER_RIGHT: 00494 object->picture->lower_x = x; 00495 tmp = abs(object->picture->upper_x - object->picture->lower_x) / ratio; 00496 if (y > object->picture->upper_y) { 00497 tmp = -tmp; 00498 } 00499 object->picture->lower_y = object->picture->upper_y - tmp; 00500 break; 00501 00502 default: 00503 return; 00504 } 00505 00506 /* need to update the upper left and lower right corners */ 00507 if(object->picture->upper_x > object->picture->lower_x) { 00508 tmp = object->picture->upper_x; 00509 object->picture->upper_x = object->picture->lower_x; 00510 object->picture->lower_x = tmp; 00511 } 00512 00513 if(object->picture->upper_y < object->picture->lower_y) { 00514 tmp = object->picture->upper_y; 00515 object->picture->upper_y = object->picture->lower_y; 00516 object->picture->lower_y = tmp; 00517 } 00518 00519 /* recalculate the screen coords and the boundings */ 00520 o_picture_recalc(toplevel, object); 00521 o_emit_change_notify (toplevel, object); 00522 } 00523 00538 void 00539 o_picture_modify_all (TOPLEVEL *toplevel, OBJECT *object, 00540 int x1, int y1, int x2, int y2) 00541 { 00542 o_emit_pre_change_notify (toplevel, object); 00543 00544 /* Normalise the requested rectangle. */ 00545 object->picture->lower_x = (x1 > x2) ? x1 : x2; 00546 object->picture->lower_y = (y1 > y2) ? y2 : y1; 00547 object->picture->upper_x = (x1 > x2) ? x2 : x1; 00548 object->picture->upper_y = (y1 > y2) ? y1 : y2; 00549 00550 /* recalculate the world coords and bounds */ 00551 o_box_recalc(toplevel, object); 00552 o_emit_change_notify (toplevel, object); 00553 } 00554 00570 void o_picture_rotate_world(TOPLEVEL *toplevel, 00571 int world_centerx, int world_centery, int angle, 00572 OBJECT *object) 00573 { 00574 int newx1, newy1; 00575 int newx2, newy2; 00576 00577 /* Only 90 degree multiple and positive angles are allowed. */ 00578 /* angle must be positive */ 00579 if(angle < 0) angle = -angle; 00580 /* angle must be a 90 multiple or no rotation performed */ 00581 if((angle % 90) != 0) return; 00582 00583 object->picture->angle = ( object->picture->angle + angle ) % 360; 00584 00585 /* The center of rotation (<B>world_centerx</B>, <B>world_centery</B>) is 00586 * translated to the origin. The rotation of the upper left and lower 00587 * right corner are then performed. Finally, the rotated picture is 00588 * translated back to its previous location. 00589 */ 00590 /* translate object to origin */ 00591 object->picture->upper_x -= world_centerx; 00592 object->picture->upper_y -= world_centery; 00593 object->picture->lower_x -= world_centerx; 00594 object->picture->lower_y -= world_centery; 00595 00596 /* rotate the upper left corner of the picture */ 00597 rotate_point_90(object->picture->upper_x, object->picture->upper_y, angle, 00598 &newx1, &newy1); 00599 00600 /* rotate the lower left corner of the picture */ 00601 rotate_point_90(object->picture->lower_x, object->picture->lower_y, angle, 00602 &newx2, &newy2); 00603 00604 /* reorder the corners after rotation */ 00605 object->picture->upper_x = min(newx1,newx2); 00606 object->picture->upper_y = max(newy1,newy2); 00607 object->picture->lower_x = max(newx1,newx2); 00608 object->picture->lower_y = min(newy1,newy2); 00609 00610 /* translate object back to normal position */ 00611 object->picture->upper_x += world_centerx; 00612 object->picture->upper_y += world_centery; 00613 object->picture->lower_x += world_centerx; 00614 object->picture->lower_y += world_centery; 00615 00616 /* recalc boundings and screen coords */ 00617 o_picture_recalc(toplevel, object); 00618 00619 } 00620 00634 void o_picture_mirror_world(TOPLEVEL *toplevel, 00635 int world_centerx, int world_centery, 00636 OBJECT *object) 00637 { 00638 int newx1, newy1; 00639 int newx2, newy2; 00640 00641 /* Set info in object. Sometimes it's necessary to change the 00642 * rotation angle as well as the mirror flag. */ 00643 object->picture->mirrored = !object->picture->mirrored; 00644 switch (object->picture->angle) { 00645 case 90: 00646 object->picture->angle = 270; 00647 break; 00648 case 270: 00649 object->picture->angle = 90; 00650 break; 00651 } 00652 00653 /* translate object to origin */ 00654 object->picture->upper_x -= world_centerx; 00655 object->picture->upper_y -= world_centery; 00656 object->picture->lower_x -= world_centerx; 00657 object->picture->lower_y -= world_centery; 00658 00659 /* mirror the corners */ 00660 newx1 = -object->picture->upper_x; 00661 newy1 = object->picture->upper_y; 00662 newx2 = -object->picture->lower_x; 00663 newy2 = object->picture->lower_y; 00664 00665 /* reorder the corners */ 00666 object->picture->upper_x = min(newx1,newx2); 00667 object->picture->upper_y = max(newy1,newy2); 00668 object->picture->lower_x = max(newx1,newx2); 00669 object->picture->lower_y = min(newy1,newy2); 00670 00671 /* translate back in position */ 00672 object->picture->upper_x += world_centerx; 00673 object->picture->upper_y += world_centery; 00674 object->picture->lower_x += world_centerx; 00675 object->picture->lower_y += world_centery; 00676 00677 /* recalc boundings and screen coords */ 00678 o_picture_recalc(toplevel, object); 00679 00680 } 00681 00692 void o_picture_translate_world(TOPLEVEL *toplevel, 00693 int dx, int dy, OBJECT *object) 00694 { 00695 /* Do world coords */ 00696 object->picture->upper_x = object->picture->upper_x + dx; 00697 object->picture->upper_y = object->picture->upper_y + dy; 00698 object->picture->lower_x = object->picture->lower_x + dx; 00699 object->picture->lower_y = object->picture->lower_y + dy; 00700 00701 /* recalc the screen coords and the bounding picture */ 00702 o_picture_recalc(toplevel, object); 00703 } 00704 00714 OBJECT *o_picture_copy(TOPLEVEL *toplevel, OBJECT *object) 00715 { 00716 OBJECT *new_node; 00717 PICTURE *picture; 00718 00719 /* create the object */ 00720 new_node = s_basic_new_object(object->type, "picture"); 00721 00722 picture = g_malloc(sizeof(PICTURE)); 00723 new_node->picture = picture; 00724 00725 new_node->color = object->color; 00726 new_node->selectable = object->selectable; 00727 00728 /* describe the picture with its upper left and lower right corner */ 00729 picture->upper_x = object->picture->upper_x; 00730 picture->upper_y = object->picture->upper_y; 00731 picture->lower_x = object->picture->lower_x; 00732 picture->lower_y = object->picture->lower_y; 00733 00734 if (object->picture->file_content != NULL) { 00735 picture->file_content = g_memdup (object->picture->file_content, 00736 object->picture->file_length); 00737 } else { 00738 picture->file_content = NULL; 00739 } 00740 00741 picture->file_length = object->picture->file_length; 00742 picture->filename = g_strdup (object->picture->filename); 00743 picture->ratio = object->picture->ratio; 00744 picture->angle = object->picture->angle; 00745 picture->mirrored = object->picture->mirrored; 00746 picture->embedded = object->picture->embedded; 00747 00748 /* Get the picture data */ 00749 picture->pixbuf = o_picture_get_pixbuf (toplevel, object); 00750 00751 /* compute the bounding picture */ 00752 o_picture_recalc(toplevel, new_node); 00753 00754 return new_node; 00755 } 00756 00757 00770 static guint8 * 00771 o_picture_rgb_data(GdkPixbuf *image) 00772 { 00773 int width = gdk_pixbuf_get_width(image); 00774 int height = gdk_pixbuf_get_height(image); 00775 int rowstride = gdk_pixbuf_get_rowstride(image); 00776 int size = height*rowstride; 00777 guint8 *rgb_pixels = g_malloc(size); 00778 00779 if (gdk_pixbuf_get_has_alpha(image)) { 00780 guint8 *pixels = gdk_pixbuf_get_pixels(image); 00781 int i, j; 00782 for (i = 0; i < height; i++) { 00783 for (j = 0; j < width; j++) { 00784 rgb_pixels[i*rowstride+j*3] = pixels[i*rowstride+j*4]; 00785 rgb_pixels[i*rowstride+j*3+1] = pixels[i*rowstride+j*4+1]; 00786 rgb_pixels[i*rowstride+j*3+2] = pixels[i*rowstride+j*4+2]; 00787 } 00788 } 00789 return rgb_pixels; 00790 } else { 00791 guint8 *pixels = gdk_pixbuf_get_pixels(image); 00792 00793 g_memmove(rgb_pixels, pixels, height*rowstride); 00794 return rgb_pixels; 00795 } 00796 } 00797 00810 static guint8 * 00811 o_picture_mask_data(GdkPixbuf *image) 00812 { 00813 guint8 *pixels; 00814 guint8 *mask; 00815 int i, size; 00816 00817 if (!gdk_pixbuf_get_has_alpha(image)) { 00818 return NULL; 00819 } 00820 00821 pixels = gdk_pixbuf_get_pixels(image); 00822 00823 size = gdk_pixbuf_get_width(image)* 00824 gdk_pixbuf_get_height(image); 00825 00826 mask = g_malloc(size); 00827 00828 /* Pick every fourth byte (the alpha channel) into mask */ 00829 for (i = 0; i < size; i++) 00830 mask[i] = pixels[i*4+3]; 00831 00832 return mask; 00833 } 00834 00856 void o_picture_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current, 00857 int origin_x, int origin_y) 00858 { 00859 int x1, y1, x, y; 00860 int height, width; 00861 GdkPixbuf* image = o_picture_get_pixbuf (toplevel, o_current); 00862 int img_width, img_height, img_rowstride; 00863 guint8 *rgb_data; 00864 guint8 *mask_data; 00865 00866 /* calculate the width and height of the box */ 00867 width = abs(o_current->picture->lower_x - o_current->picture->upper_x); 00868 height = abs(o_current->picture->upper_y - o_current->picture->lower_y); 00869 00870 /* calculate the origin of the box */ 00871 x1 = o_current->picture->upper_x; 00872 y1 = o_current->picture->upper_y; 00873 00874 /* If the image failed to load, try to get hold of the fallback 00875 * pixbuf. */ 00876 if (image == NULL) image = o_picture_get_fallback_pixbuf (toplevel); 00877 /* If the image failed to load, draw a box in the default color with a 00878 * cross in it. */ 00879 if (image == NULL) { 00880 int line_width = (toplevel->line_style == THICK) ? LINE_WIDTH : 2; 00881 o_box_print_solid (toplevel, fp, x1, y1, width, height, 00882 DEFAULT_COLOR, line_width, -1, -1, -1, -1); 00883 o_line_print_solid (toplevel, fp, x1, y1, x1+width, y1-height, 00884 DEFAULT_COLOR, line_width, -1, -1, -1, -1); 00885 o_line_print_solid (toplevel, fp, x1+width, y1, x1, y1-height, 00886 DEFAULT_COLOR, line_width, -1, -1, -1, -1); 00887 return; 00888 } 00889 00890 img_width = gdk_pixbuf_get_width(image); 00891 img_rowstride = gdk_pixbuf_get_rowstride(image); 00892 img_height = gdk_pixbuf_get_height(image); 00893 00894 rgb_data = o_picture_rgb_data(image); 00895 mask_data = o_picture_mask_data(image); 00896 00897 fprintf(fp, "gsave\n"); 00898 00899 /* color output only */ 00900 fprintf(fp, "/pix %i string def\n", img_width * 3); 00901 fprintf(fp, "%i %i 8\n", img_width, img_height); 00902 fprintf(fp, "%i %i translate\n", x1, y1); 00903 fprintf(fp, "%i %i scale\n", width, height); 00904 fprintf(fp, "[%i 0 0 -%i 0 0]\n", img_width, img_height); 00905 00906 fprintf(fp, "{currentfile pix readhexstring pop}\n"); 00907 fprintf(fp, "false 3 colorimage\n"); 00908 fprintf(fp, "\n"); 00909 00910 if (mask_data) { 00911 for (y = 0; y < img_height; y++) { 00912 for (x = 0; x < img_width; x++) { 00913 int i = y*img_rowstride+x*3; 00914 int m = y*img_width+x; 00915 fprintf(fp, "%02x", 255-(mask_data[m]*(255-rgb_data[i])/255)); 00916 fprintf(fp, "%02x", 255-(mask_data[m]*(255-rgb_data[i+1])/255)); 00917 fprintf(fp, "%02x", 255-(mask_data[m]*(255-rgb_data[i+2])/255)); 00918 } 00919 fprintf(fp, "\n"); 00920 } 00921 } else { 00922 for (y = 0; y < img_height; y++) { 00923 for (x = 0; x < img_width; x++) { 00924 int i = y*img_rowstride+x*3; 00925 fprintf(fp, "%02x", (int)(rgb_data[i])); 00926 fprintf(fp, "%02x", (int)(rgb_data[i+1])); 00927 fprintf(fp, "%02x", (int)(rgb_data[i+2])); 00928 } 00929 fprintf(fp, "\n"); 00930 } 00931 } 00932 fprintf(fp, "grestore\n"); 00933 fprintf(fp, "\n"); 00934 00935 g_object_unref (image); 00936 g_free(rgb_data); 00937 g_free(mask_data); 00938 } 00939 00940 00949 void o_picture_embed (TOPLEVEL *toplevel, OBJECT *object) 00950 { 00951 const gchar *filename = o_picture_get_filename (toplevel, object); 00952 gchar *basename; 00953 00954 if (o_picture_is_embedded (toplevel, object)) return; 00955 00956 if (object->picture->file_content == NULL) { 00957 s_log_message (_("Picture [%s] has no image data.\n"), filename); 00958 s_log_message (_("Falling back to file loading. Picture is still unembedded.\n")); 00959 object->picture->embedded = 0; 00960 return; 00961 } 00962 00963 object->picture->embedded = 1; 00964 00965 basename = g_path_get_basename (filename); 00966 s_log_message (_("Picture [%s] has been embedded\n"), basename); 00967 g_free (basename); 00968 } 00969 00970 00979 void o_picture_unembed (TOPLEVEL *toplevel, OBJECT *object) 00980 { 00981 GError *err = NULL; 00982 const gchar *filename = o_picture_get_filename (toplevel, object); 00983 gchar *basename; 00984 00985 if (!o_picture_is_embedded (toplevel, object)) return; 00986 00987 o_picture_set_from_file (toplevel, object, filename, &err); 00988 00989 if (err != NULL) { 00990 s_log_message (_("Failed to load image from file [%s]: %s\n"), 00991 filename, err->message); 00992 s_log_message (_("Picture is still embedded.\n")); 00993 g_error_free (err); 00994 return; 00995 } 00996 00997 object->picture->embedded = 0; 00998 00999 basename = g_path_get_basename(filename); 01000 s_log_message (_("Picture [%s] has been unembedded\n"), basename); 01001 g_free(basename); 01002 } 01003 01016 double o_picture_shortest_distance (OBJECT *object, int x, int y, 01017 int force_solid) 01018 { 01019 double dx, dy; 01020 double x1, y1, x2, y2; 01021 01022 g_return_val_if_fail (object->picture != NULL, G_MAXDOUBLE); 01023 01024 x1 = (double)min (object->picture->upper_x, object->picture->lower_x); 01025 y1 = (double)min (object->picture->upper_y, object->picture->lower_y); 01026 x2 = (double)max (object->picture->upper_x, object->picture->lower_x); 01027 y2 = (double)max (object->picture->upper_y, object->picture->lower_y); 01028 01029 dx = min (((double)x) - x1, x2 - ((double)x)); 01030 dy = min (((double)y) - y1, y2 - ((double)y)); 01031 01032 dx = min (dx, 0); 01033 dy = min (dy, 0); 01034 01035 return sqrt ((dx * dx) + (dy * dy)); 01036 } 01037 01048 gboolean 01049 o_picture_is_embedded (TOPLEVEL *toplevel, OBJECT *object) 01050 { 01051 g_return_val_if_fail (object != NULL, FALSE); 01052 g_return_val_if_fail (object->picture != NULL, FALSE); 01053 01054 return object->picture->embedded; 01055 } 01056 01069 GdkPixbuf * 01070 o_picture_get_pixbuf (TOPLEVEL *toplevel, OBJECT *object) 01071 { 01072 g_return_val_if_fail (object != NULL, NULL); 01073 g_return_val_if_fail (object->picture != NULL, NULL); 01074 01075 if (object->picture->pixbuf != NULL) { 01076 return g_object_ref (object->picture->pixbuf); 01077 } else { 01078 return NULL; 01079 } 01080 } 01081 01092 const char * 01093 o_picture_get_data (TOPLEVEL *toplevel, OBJECT *object, 01094 size_t *len) 01095 { 01096 g_return_val_if_fail (object != NULL, NULL); 01097 g_return_val_if_fail (object->picture != NULL, NULL); 01098 01099 *len = object->picture->file_length; 01100 return object->picture->file_content; 01101 } 01102 01116 gboolean 01117 o_picture_set_from_buffer (TOPLEVEL *toplevel, OBJECT *object, 01118 const gchar *filename, 01119 const gchar *data, size_t len, 01120 GError **error) 01121 { 01122 GdkPixbuf *pixbuf; 01123 GInputStream *stream; 01124 gchar *tmp; 01125 01126 g_return_val_if_fail (toplevel != NULL, FALSE); 01127 g_return_val_if_fail (object != NULL, FALSE); 01128 g_return_val_if_fail (object->picture != NULL, FALSE); 01129 g_return_val_if_fail (data != NULL, FALSE); 01130 01131 /* Check that we can actually load the data before making any 01132 * changes to the object. */ 01133 stream = G_INPUT_STREAM (g_memory_input_stream_new_from_data (data, len, NULL)); 01134 pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, error); 01135 g_object_unref (stream); 01136 if (pixbuf == NULL) return FALSE; 01137 01138 o_emit_pre_change_notify (toplevel, object); 01139 01140 if (object->picture->pixbuf != NULL) { 01141 g_object_unref (object->picture->pixbuf); 01142 } 01143 object->picture->pixbuf = pixbuf; 01144 01145 object->picture->ratio = ((double) gdk_pixbuf_get_width(pixbuf) / 01146 gdk_pixbuf_get_height(pixbuf)); 01147 01148 tmp = g_strdup (filename); 01149 g_free (object->picture->filename); 01150 object->picture->filename = tmp; 01151 01152 gchar *buf = g_realloc (object->picture->file_content, 01153 len); 01154 /* It's possible that these buffers might overlap, because the 01155 * library user hates us. */ 01156 memmove (buf, data, len); 01157 object->picture->file_content = buf; 01158 object->picture->file_length = len; 01159 01160 o_emit_change_notify (toplevel, object); 01161 return TRUE; 01162 } 01163 01175 gboolean 01176 o_picture_set_from_file (TOPLEVEL *toplevel, OBJECT *object, 01177 const gchar *filename, 01178 GError **error) 01179 { 01180 gchar *buf; 01181 size_t len; 01182 gboolean status; 01183 01184 g_return_val_if_fail (filename != NULL, FALSE); 01185 01186 if (!g_file_get_contents (filename, &buf, &len, error)) { 01187 return FALSE; 01188 } 01189 01190 status = o_picture_set_from_buffer (toplevel, object, filename, 01191 buf, len, error); 01192 g_free (buf); 01193 return status; 01194 } 01195 01204 const gchar * 01205 o_picture_get_filename (TOPLEVEL *toplevel, OBJECT *object) 01206 { 01207 g_return_val_if_fail (object != NULL, NULL); 01208 g_return_val_if_fail (object->picture != NULL, NULL); 01209 01210 return object->picture->filename; 01211 } 01212 01221 GdkPixbuf * 01222 o_picture_get_fallback_pixbuf (TOPLEVEL *toplevel) 01223 { 01224 static GdkPixbuf *pixbuf = NULL; 01225 static gboolean failed = FALSE; 01226 01227 if (pixbuf == NULL && !failed) { 01228 gchar *filename; 01229 GError *error = NULL; 01230 01231 filename = g_build_filename (toplevel->bitmap_directory, 01232 "gschem-warning.png", NULL); 01233 pixbuf = gdk_pixbuf_new_from_file (filename, &error); 01234 01235 if (pixbuf == NULL) { 01236 g_warning ( _("Failed to load fallback image %s: %s.\n"), 01237 filename, error->message); 01238 g_error_free (error); 01239 failed = TRUE; 01240 } 01241 g_free (filename); 01242 } 01243 01244 if (failed) return NULL; 01245 01246 g_assert (GDK_IS_PIXBUF (pixbuf)); 01247 return g_object_ref (pixbuf); 01248 }