libgeda

o_picture.c

Go to the documentation of this file.
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 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines