[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

gEDA-cvs: gaf.git: branch: master updated (1.7.1-20110619-229-g326a4ec)



The branch, master has been updated
       via  326a4eca0d36eed80a33b201bcbed4942046f61c (commit)
       via  bccf15c104d64b33d33bb7167703469d75884a7e (commit)
       via  e85e8c5843f23432cb03d4dd8c95fb34753f7801 (commit)
       via  121bd353ac7c4e9de0f94c4b7378945cf33222c6 (commit)
       via  32ca3b25355ca4bef14ed3a2d15277367c32fead (commit)
      from  648a418f99c337a185462525bbffa66b89786007 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


=========
 Summary
=========

 docs/scheme-api/geda-scheme.texi                   |   66 ++
 gschem/examples/drawing_primitives.sch             |  223 ++------
 gschem/include/prototype.h                         |    3 +-
 gschem/scheme/gschem.scm                           |    6 +-
 gschem/src/g_keys.c                                |   63 ++-
 gschem/src/g_util.c                                |    4 +
 gschem/src/i_callbacks.c                           |    2 +-
 gschem/src/o_grips.c                               |   10 +-
 gschem/src/o_picture.c                             |  164 +++---
 libgeda/include/libgeda/prototype.h                |   30 +-
 libgeda/include/prototype_priv.h                   |    2 +
 libgeda/scheme/Makefile.am                         |    1 +
 libgeda/scheme/geda/object.scm                     |   35 +
 libgeda/scheme/unit-tests/t0112-object-picture.scm |   58 ++
 libgeda/src/o_box_basic.c                          |    2 +
 libgeda/src/o_embed.c                              |    4 +-
 libgeda/src/o_picture.c                            |  648 +++++++++++++-------
 libgeda/src/scheme_object.c                        |  202 ++++++
 18 files changed, 997 insertions(+), 526 deletions(-)
 create mode 100644 libgeda/scheme/unit-tests/t0112-object-picture.scm


=================
 Commit Messages
=================

commit 326a4eca0d36eed80a33b201bcbed4942046f61c
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    scheme-api: Create and manipulate picture objects.
    
    Closes-bug: lp-898379

:100644 100644 f383000... c451887... M	docs/scheme-api/geda-scheme.texi
:100644 100644 6c221f4... 40368c3... M	libgeda/scheme/Makefile.am
:100644 100644 6a1f09c... bb00e04... M	libgeda/scheme/geda/object.scm
:000000 100644 0000000... 2abb78e... A	libgeda/scheme/unit-tests/t0112-object-picture.scm
:100644 100644 0145a22... 1d9ce3f... M	libgeda/src/scheme_object.c

commit bccf15c104d64b33d33bb7167703469d75884a7e
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    General fixes for pictures, picture rendering and picture operations.
    
    Streamlined the API for picture objects to make it harder to leave a
    picture object in an inconsistent state.  This is a prerequisite patch
    to providing a Scheme API for working with picture objects.
    
    This patch also makes primitive transformations of pictures actually
    work, and fixes rendering of pictures in gschem, because the changes
    weren't really feasible to separate.

:100644 100644 8913eaa... c1b4aa7... M	gschem/examples/drawing_primitives.sch
:100644 100644 1ce0283... ddb6735... M	gschem/include/prototype.h
:100644 100644 fb26c7c... 1bc8e54... M	gschem/src/o_grips.c
:100644 100644 d602537... d0e7683... M	gschem/src/o_picture.c
:100644 100644 85cab06... bb69439... M	libgeda/include/libgeda/prototype.h
:100644 100644 63f411b... a6edf75... M	libgeda/include/prototype_priv.h
:100644 100644 eb833ec... 6e7933a... M	libgeda/src/o_embed.c
:100644 100644 3119c12... 82a5bac... M	libgeda/src/o_picture.c

commit e85e8c5843f23432cb03d4dd8c95fb34753f7801
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    libgeda: Add missing pre change notify to o_box_modify_all().

:100644 100644 8a0d165... 144d89c... M	libgeda/src/o_box_basic.c

commit 121bd353ac7c4e9de0f94c4b7378945cf33222c6
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    gschem: Fix a crash when cancelling out of an action.
    
    In some cases, the new keybinding code could cause a crash when
    cancelling out of an action with the right mouse button.  This was
    because there was an call to scm_c_eval_string() which could sometimes
    be called in a context where Guile exceptions weren't caught, and
    which hadn't been updated to reflect the changes to the keybinding
    system.

:100644 100644 4795ef3... 1ce0283... M	gschem/include/prototype.h
:100644 100644 ba0b587... 6593886... M	gschem/scheme/gschem.scm
:100644 100644 6338f48... 696573d... M	gschem/src/g_keys.c
:100644 100644 f37e68e... 7546b00... M	gschem/src/i_callbacks.c

commit 32ca3b25355ca4bef14ed3a2d15277367c32fead
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    scheme-api: Stop show-uri from leaking a GError on failure.

:100644 100644 f96ada3... 0eecfab... M	gschem/src/g_util.c

=========
 Changes
=========

commit 326a4eca0d36eed80a33b201bcbed4942046f61c
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    scheme-api: Create and manipulate picture objects.
    
    Closes-bug: lp-898379

diff --git a/docs/scheme-api/geda-scheme.texi b/docs/scheme-api/geda-scheme.texi
index f383000..c451887 100644
--- a/docs/scheme-api/geda-scheme.texi
+++ b/docs/scheme-api/geda-scheme.texi
@@ -1084,10 +1084,76 @@ line section to the current path:
 @node Pictures
 @subsection Pictures
 
+A picture object displays an image in the schematic, and is a purely
+graphical element.  Pictures may be in any format supported by the
+user's GdkPixbuf installation (but note that images that can't be
+loaded for some reason are preserved).  The @var{top-left},
+@var{bottom-right}, @var{angle} and @var{mirror} properties of a
+picture object indicate the transformation that was applied to the
+original image.  The transformation is applied as follows:
+
+@enumerate
+@item
+If @var{mirror} is true, the picture is reflected about its vertical
+centerline.
+@item
+The picture is rotated by @var{angle} anticlockwise about its center
+(@var{angle} may only be an integer multiple of 90 degrees).
+@item
+The picture is scaled and translated to fit within the rectangle
+defined by the points @var{top-left} and @var{bottom-right}.
+@end enumerate
+
 @defun picture? object
 Returns @samp{#t} if and only if @var{object} is a picture @code{object}.
 @end defun
 
+@defun make-picture/vector vector filename top-left bottom-right angle mirror
+Creates and returns a new picture object for @var{filename}, by
+reading image data from @var{vector} (which should be in a standard
+image file format).  If @var{vector} could not be loaded, an error is
+raised.  @var{top-left}, @var{bottom-right}, @var{angle} and
+@var{mirror} specify the picture transformation.
+
+The points @var{top-left} and @var{bottom-right} should be specified
+in the form @samp{(x . y)}.
+@end defun
+
+@defun set-picture! picture top-left bottom-right angle mirror
+Sets the picture transformation for @var{picture}.
+@end defun
+
+@defun picture-info picture
+Returns the parameters of @var{picture} as a list in the form:
+
+@example
+((top-left-x . top-left-y) (bottom-right-x . bottom-right-y) angle mirror)
+@end example
+@end defun
+
+@defun picture-filename picture
+Returns the filename associated with @var{picture} as a string.
+@end defun
+
+@defun picture-top-left picture
+Returns the position of the top left corner of @samp{picture} in the
+form @samp{(x . y)}.
+@end defun
+
+@defun picture-bottom-right picture
+Returns the position of the bottom right corner of @samp{picture} in
+the form @samp{(x . y)}.
+@end defun
+
+@defun picture-angle picture
+Returns the angle to rotate @samp{picture} by, as an integer number of
+degrees.
+@end defun
+
+@defun picture-mirror? picture
+Returns true if @samp{picture} is mirrored.
+@end defun
+
 @node Text
 @subsection Text
 
diff --git a/libgeda/scheme/Makefile.am b/libgeda/scheme/Makefile.am
index 6c221f4..40368c3 100644
--- a/libgeda/scheme/Makefile.am
+++ b/libgeda/scheme/Makefile.am
@@ -23,6 +23,7 @@ TESTS = unit-tests/t0001-geda-conf-lib.scm \
 	unit-tests/t0109-object-copy.scm \
 	unit-tests/t0110-object-transform.scm \
 	unit-tests/t0111-object-path.scm \
+	unit-tests/t0112-object-picture.scm \
 	unit-tests/t0200-page.scm \
 	unit-tests/t0201-page-dirty.scm \
 	unit-tests/t0202-page-string.scm \
diff --git a/libgeda/scheme/geda/object.scm b/libgeda/scheme/geda/object.scm
index 6a1f09c..bb00e04 100644
--- a/libgeda/scheme/geda/object.scm
+++ b/libgeda/scheme/geda/object.scm
@@ -264,6 +264,41 @@
 (define-public (picture? x)
   (object-type? x 'picture))
 
+(define-public (set-picture! p top-left bottom-right angle mirror)
+  (%set-picture! p (car top-left) (cdr top-left)
+                 (car bottom-right) (cdr bottom-right) angle mirror))
+
+(define-public (make-picture/vector vec filename . args)
+  (let ((p (%make-picture)))
+    (%set-picture-data/vector! p vec filename)
+    (apply set-picture! p args)))
+
+(define-public (picture-info p)
+  (let* ((params (%picture-info p))
+         (filename (car params))
+         (tail (cdr params)))
+    (apply list filename
+           (cons (list-ref tail 0)
+                 (list-ref tail 1))
+           (cons (list-ref tail 2)
+                 (list-ref tail 3))
+           (list-tail tail 4))))
+
+(define-public (picture-filename p)
+  (list-ref (picture-info p) 0))
+
+(define-public (picture-top-left p)
+  (list-ref (picture-info p) 1))
+
+(define-public (picture-bottom-right p)
+  (list-ref (picture-info p) 2))
+
+(define-public (picture-angle p)
+  (list-ref (picture-info p) 3))
+
+(define-public (picture-mirror? p)
+  (list-ref (picture-info p) 4))
+
 ;;;; Text
 
 (define-public (text? t)
diff --git a/libgeda/scheme/unit-tests/t0112-object-picture.scm b/libgeda/scheme/unit-tests/t0112-object-picture.scm
new file mode 100644
index 0000000..2abb78e
--- /dev/null
+++ b/libgeda/scheme/unit-tests/t0112-object-picture.scm
@@ -0,0 +1,58 @@
+;; Test Scheme procedures related to picture objects.
+
+(use-modules (unit-test) (geda object))
+
+(define test-image
+  (map char->integer (string->list
+"/* XPM */
+static char * test_image_xpm[] = {
+\"2 1 1 1\",
+\" 	c None\",
+\"  \"};
+")))
+
+(begin-test 'pictures
+  (let* ((a (make-picture/vector test-image "test_image.xpm"
+                                 '(1 . 2) '(5 . 4) 0 #f))
+         (b (copy-object a)))
+
+    (assert-equal 'picture (object-type a))
+    (assert-true (picture? a))
+
+    (assert-equal "test_image.xpm" (picture-filename a))
+    (assert-equal '(1 . 4) (picture-top-left a))
+    (assert-equal '(5 . 2) (picture-bottom-right a))
+    (assert-equal 0 (picture-angle a))
+    (assert-equal #f (picture-mirror? a))
+
+    (assert-equal (list (picture-filename a)
+                        (picture-top-left a)
+                        (picture-bottom-right a)
+                        (picture-angle a)
+                        (picture-mirror? a))
+                  (picture-info a))
+
+    (assert-equal (picture-info a) (picture-info b))
+
+    ;; Check setting some parameters. We simulate a rotation by 90
+    ;; degrees anti-clockwise about (3,2). This doesn't test the image
+    ;; dimensions snapping yet.
+    (assert-equal a (set-picture! a '(2 . 0) '(4 . 4) 90 #t))
+    (assert-equal '(2 . 4) (picture-top-left a))
+    (assert-equal '(4 . 0) (picture-bottom-right a))
+    (assert-equal 90 (picture-angle a))
+    (assert-equal #t (picture-mirror? a))
+
+    ;; Check mirroring.
+    (assert-equal (list a) (mirror-objects! 4 a))
+    (assert-equal '(4 . 4) (picture-top-left a))
+    (assert-equal '(6 . 0) (picture-bottom-right a))
+    (assert-equal 270 (picture-angle a))
+    (assert-equal #f (picture-mirror? a))
+
+    ;; Check rotating.
+    (assert-equal (list a) (rotate-objects! '(5 . 2) 90 a))
+    (assert-equal '(3 . 3) (picture-top-left a))
+    (assert-equal '(7 . 1) (picture-bottom-right a))
+    (assert-equal 0 (picture-angle a))
+    (assert-equal #f (picture-mirror? a))))
diff --git a/libgeda/src/scheme_object.c b/libgeda/src/scheme_object.c
index 0145a22..1d9ce3f 100644
--- a/libgeda/src/scheme_object.c
+++ b/libgeda/src/scheme_object.c
@@ -1841,6 +1841,206 @@ SCM_DEFINE (path_insert_x, "%path-insert", 3, 6, 0,
   return obj_s;
 }
 
+/*! \brief Create a new, empty picture object.
+ * \par Function Description
+ * Creates a new picture object with no filename, no image data and
+ * all other parameters set to default values.  It is initially set to
+ * be embedded.
+ *
+ * \note Scheme API: Implements the %make-picture procedure in the
+ * (geda core object) module.
+ *
+ * \return a newly-created picture object.
+ */
+SCM_DEFINE (make_picture, "%make-picture", 0, 0, 0, (),
+            "Create a new picture object")
+{
+  OBJECT *obj = o_picture_new (edascm_c_current_toplevel (),
+                               NULL, 0, NULL, OBJ_PICTURE,
+                               0, 0, 0, 0, 0, FALSE, TRUE);
+  SCM result = edascm_from_object (obj);
+
+  /* At the moment, the only pointer to the object is owned by the
+   * smob. */
+  edascm_c_set_gc (result, 1);
+
+  return result;
+}
+
+/*! \brief Get picture object parameters.
+ * \par Function Description
+ * Retrieves the parameters of a picture object.  The return value is
+ * a list of parameters:
+ *
+ * -# Filename of picture.
+ * -# X-coordinate of top left of picture.
+ * -# Y-coordinate of top left of picture.
+ * -# X-coordinate of bottom right of picture.
+ * -# Y-coordinate of bottom right of picture.
+ * -# Rotation angle.
+ * -# Whether object is mirrored.
+ *
+ * \note Scheme API: Implements the %picture-info procedure in the
+ * (geda core object) module.
+ *
+ * \param obj_s the picture object to inspect.
+ * \return a list of picture object parameters.
+ */
+SCM_DEFINE (picture_info, "%picture-info", 1, 0, 0,
+            (SCM obj_s), "Get picture object parameters")
+{
+  SCM_ASSERT (edascm_is_object_type (obj_s, OBJ_PICTURE), obj_s,
+              SCM_ARG1, s_picture_info);
+
+  TOPLEVEL *toplevel = edascm_c_current_toplevel ();
+  OBJECT *obj = edascm_to_object (obj_s);
+  const gchar *filename = o_picture_get_filename (toplevel, obj);
+
+  SCM filename_s = SCM_BOOL_F;
+  if (filename != NULL) {
+    filename_s = scm_from_utf8_string (filename);
+  }
+
+  return scm_list_n (filename_s,
+                     scm_from_int (obj->picture->upper_x),
+                     scm_from_int (obj->picture->upper_y),
+                     scm_from_int (obj->picture->lower_x),
+                     scm_from_int (obj->picture->lower_y),
+                     scm_from_int (obj->picture->angle),
+                     (obj->picture->mirrored ? SCM_BOOL_T : SCM_BOOL_F),
+                     SCM_UNDEFINED);
+}
+
+/* \brief Set picture object parameters.
+ * \par Function Description
+ * Sets the parameters of the picture object \a obj_s.
+ *
+ * \note Scheme API: Implements the %set-picture! procedure in the
+ * (geda core object) module.
+ *
+ * \param obj_s       the picture object to modify
+ * \param x1_s  the new x-coordinate of the top left of the picture.
+ * \param y1_s  the new y-coordinate of the top left of the picture.
+ * \param x2_s  the new x-coordinate of the bottom right of the picture.
+ * \param y2_s  the new y-coordinate of the bottom right of the picture.
+ * \param angle_s     the new rotation angle.
+ * \param mirror_s    whether the picture object should be mirrored.
+ * \return the modify \a obj_s.
+ */
+SCM_DEFINE (set_picture_x, "%set-picture!", 7, 0, 0,
+            (SCM obj_s, SCM x1_s, SCM y1_s, SCM x2_s, SCM y2_s, SCM angle_s,
+             SCM mirror_s), "Set picture object parameters")
+{
+  SCM_ASSERT (edascm_is_object_type (obj_s, OBJ_PICTURE), obj_s,
+              SCM_ARG1, s_set_picture_x);
+  SCM_ASSERT (scm_is_integer (x1_s), x1_s, SCM_ARG2, s_set_picture_x);
+  SCM_ASSERT (scm_is_integer (y1_s), x1_s, SCM_ARG3, s_set_picture_x);
+  SCM_ASSERT (scm_is_integer (x2_s), x1_s, SCM_ARG4, s_set_picture_x);
+  SCM_ASSERT (scm_is_integer (y2_s), x1_s, SCM_ARG5, s_set_picture_x);
+  SCM_ASSERT (scm_is_integer (angle_s), angle_s, SCM_ARG6, s_set_picture_x);
+
+  TOPLEVEL *toplevel = edascm_c_current_toplevel ();
+  OBJECT *obj = edascm_to_object (obj_s);
+
+  /* Angle */
+  int angle = scm_to_int (angle_s);
+  switch (angle) {
+  case 0:
+  case 90:
+  case 180:
+  case 270:
+    /* These are all fine. */
+    break;
+  default:
+    /* Otherwise, not fine. */
+    scm_misc_error (s_set_picture_x,
+                    _("Invalid picture angle ~A. Must be 0, 90, 180, or 270 degrees"),
+                    scm_list_1 (angle_s));
+  }
+
+  o_emit_pre_change_notify (toplevel, obj);
+
+  obj->picture->angle = scm_to_int (angle_s);
+  obj->picture->mirrored = scm_is_true (mirror_s);
+  o_picture_modify_all (toplevel, obj,
+                        scm_to_int (x1_s), scm_to_int (y1_s),
+                        scm_to_int (x2_s), scm_to_int (y2_s));
+
+  o_emit_change_notify (toplevel, obj);
+  return obj_s;
+}
+
+/*! \brief Set a picture object's data from a vector.
+ * \par Function Description
+ * Sets the image data for the picture object \a obj_s from the vector
+ * \a data_s, and set its \a filename.  If the contents of \a data_s
+ * could not be successfully loaded as an image, raises an error.  The
+ * contents of \a data_s should be image data encoded in on-disk
+ * format.
+ *
+ * \note Scheme API: Implements the %set-picture-data/vector!
+ * procedure in the (geda core object) module.
+ *
+ * \param obj_s       The picture object to modify.
+ * \param data_s      Vector containing encoded image data.
+ * \param filename_s  New filename for \a obj_s.
+ * \return \a obj_s.
+ */
+SCM_DEFINE (set_picture_data_vector_x, "%set-picture-data/vector!",
+            3, 0, 0, (SCM obj_s, SCM data_s, SCM filename_s),
+            "Set a picture object's data from a vector.")
+{
+  SCM vec_s = scm_any_to_s8vector (data_s);
+  /* Check argument types */
+  SCM_ASSERT (edascm_is_object_type (obj_s, OBJ_PICTURE), obj_s,
+              SCM_ARG1, s_set_picture_data_vector_x);
+  SCM_ASSERT (scm_is_true (scm_s8vector_p (vec_s)), data_s, SCM_ARG2,
+              s_set_picture_data_vector_x);
+  SCM_ASSERT (scm_is_string (filename_s), filename_s, SCM_ARG3,
+              s_set_picture_data_vector_x);
+
+  scm_dynwind_begin (0);
+
+  /* Convert vector to contiguous buffer */
+  scm_t_array_handle handle;
+  size_t len;
+  ssize_t inc;
+  const scm_t_int8 *elt = scm_s8vector_elements (vec_s, &handle, &len, &inc);
+  gchar *buf = g_malloc (len);
+  int i;
+
+  scm_dynwind_unwind_handler (g_free, buf, SCM_F_WIND_EXPLICITLY);
+
+  for (i = 0; i < len; i++, elt += inc) {
+    buf[i] = (gchar) *elt;
+  }
+  scm_array_handle_release (&handle);
+
+  gboolean status;
+  GError *error = NULL;
+  TOPLEVEL *toplevel = edascm_c_current_toplevel ();
+  OBJECT *obj = edascm_to_object (obj_s);
+  gchar *filename = scm_to_utf8_string (filename_s);
+  scm_dynwind_unwind_handler (g_free, filename, SCM_F_WIND_EXPLICITLY);
+
+  status = o_picture_set_from_buffer (toplevel, obj, filename,
+                                      buf, len, &error);
+
+  if (!status) {
+    scm_dynwind_unwind_handler ((void (*)(void *)) g_error_free, error,
+                                SCM_F_WIND_EXPLICITLY);
+    scm_misc_error (s_set_picture_data_vector_x,
+                    "Failed to set picture image data from vector: ~S",
+                    scm_list_1 (scm_from_utf8_string (error->message)));
+  }
+
+  o_page_changed (toplevel, obj);
+  scm_dynwind_end ();
+  return obj_s;
+}
+
+
+
 /*! \brief Translate an object.
  * \par Function Description
  * Translates \a obj_s by \a dx_s in the x-axis and \a dy_s in the
@@ -1989,6 +2189,8 @@ init_module_geda_core_object ()
                 s_object_connections, s_object_complex,
                 s_make_path, s_path_length, s_path_ref,
                 s_path_remove_x, s_path_insert_x,
+                s_make_picture, s_picture_info, s_set_picture_x,
+                s_set_picture_data_vector_x,
                 s_translate_object_x, s_rotate_object_x,
                 s_mirror_object_x,
                 NULL);

commit bccf15c104d64b33d33bb7167703469d75884a7e
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    General fixes for pictures, picture rendering and picture operations.
    
    Streamlined the API for picture objects to make it harder to leave a
    picture object in an inconsistent state.  This is a prerequisite patch
    to providing a Scheme API for working with picture objects.
    
    This patch also makes primitive transformations of pictures actually
    work, and fixes rendering of pictures in gschem, because the changes
    weren't really feasible to separate.

diff --git a/gschem/examples/drawing_primitives.sch b/gschem/examples/drawing_primitives.sch
index 8913eaa..c1b4aa7 100644
--- a/gschem/examples/drawing_primitives.sch
+++ b/gschem/examples/drawing_primitives.sch
@@ -1,4 +1,4 @@
-v 20070708 1
+v 20110619 2
 T 1500 11600 9 10 1 0 0 0 1
 Text Justifications:
 T 2500 11100 9 10 1 0 0 0 1
@@ -126,183 +126,8 @@ pinseq=0
 }
 T 15300 4200 9 10 1 0 0 6 1
 Pins:
-T 5400 11300 9 10 1 0 0 6 1
+T 4400 11400 9 10 1 0 0 6 1
 Picture:
-G 5500 11000 800 800 0 0 1
-/usr/home/mike/geda/mycvs/eda/geda/devel/gschem/bitmap/gschem-warning.png
-R2RrUAAAJBgBAQACAAAAwAAAADAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAA7ikTHvQqFMbGIhDHkB4SIICAgAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADsKRMe9isU49IkEf+pHQ//hRcMuAAA
-ABQAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAKcdDgH2KROt1SUR/6cdDv+hHA7/mxsO/2QSCZkAAAAWAAAAAwAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApx0OAfcpE4/gJxL/sx8P/6QcDv+kHA7/
-oRwO/4oYDP8uCAVSERERDwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAA6ygSPOwpE/+5IA//pBwO/6QcDv+xQBD/pBwO/5ocD/9jEQnSAAAAKgAAAAcAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACnHQ4C9SoT48ojEP+kHA7/pBwO/7tb
-Ef/CbxL/ox0P/6AdD/+SGg7/OwsHfQAAABcAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAKcdDgH1KROQ2yYS/6YdD/+kHA7/pBwO/+CtEf/fsRL/ox0P/6MdD/+gHQ//dxUM8gAA
-ADcAAAALAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-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
-E//cqxX/3KsV/9yrFf/cqxX/26oW/9uqFv+9kxL/MSYF/3xhDP/XqBb/2qoX/9ipGf/YqRn/
-2KkZ/9ipGf/XqBr/16ga/9eoGv/XqBr/v28W/5wfFv+ZHxb/YRMO+AAAAF8LCwsZAAAAAgAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABuFAoD
-6ioWyr8iEv+jHQ//oh0Q/6IdEP+iHRD/oh0Q/6EdEf+hHRH/oR0R/7lbE//BbxT/x34U/8uJ
-FP/aqhb/26sX/9urF//bqxf/2aoZ/9mqGf/Zqhn/2aoZ/9ipGv/YqRr/2Kka/9ipGv/YpRz/
-xX4W/6tCFv+ZHxb/eBgS/yYIBp8AAAArKysrBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCDAYFzSUT/6MdD/+gHQ//oh0Q/6IdEP+iHRD/
-oR0R/6EdEf+hHRH/oR0R/6AeEv+gHhL/oB4S/6AeEv+fHhP/nx4T/58eE/+fHhP/nh4U/54e
-FP+eHhT/nR8V/50fFf+dHxX/nR8V/5wfFv+cHxb/nB8W/5wfFv+bHxf/ixwV/0QOCtgAAABD
-AAAADAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAXBAIHeBULj1IOB9xqEwv/bxQL/3gVDP+GGA3/ihkP/5MbEP+eHRH/nR4S/6AeEv+gHhL/
-oB4S/58eE/+fHhP/nx4T/58eE/+eHhT/nh4U/54eFP+dHxX/nR8V/50fFf+dHxX/nB8W/5wf
-Fv+cHxb/nB8W/5sfF/+bHxf/mB8X/1oSDfgBAQFhAAAAGQAAAAIAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHBQUFNgICApQCAgLWDgMC8CMH
-BPguCQb7QQwH/UIMB/1XEQn/XREL/2ASC/9uFQz/cxYO/3MWDv9zFg7/gBgQ/4gaEf+IGhH/
-iBoR/4gaEf+HGxL/hxsS/4cbEv+GGxP/hhsT/4YbE/+GGxP/hRsU/4UbFP+AGhP/cxcR/00Q
-DP8CAgKEBgYGKwAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAEAAAAIQAAAF4CAgKQAgICrgICAr8CAgLKAgIC1AICAt0CAgLkAgIC7AIC
-AvINBAP2IgcF+SEHBfohBwX6IwcF+kINCP0+DAj9PgwI/T4MCP0+DAj+PgwI/j4MCP49DAn+
-PQwJ/j0MCf48DAn+PAwJ/jwMCf47DAn9LgoI/BwHBe4CAgKeAAAAOQAAAAcAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAACgAAAB4AAAAy
-AAAARAAAAFUDAwNpAwMDewICAosCAgKYAgICpwICArMCAgK5AgICwAICAsgCAgLLAgICzAIC
-AtECAgLbAgIC4AICAuACAgLhAgIC4QICAuECAgLhAgIC4QICAuECAgLhAgIC4QICAuECAgLg
-AgIC3gICAs0AAACSAQEBNgAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAMAAAAGAAAACg8PDxIKCgocAAAAJQAAAC4BAQE1
-AQEBPQQEBEQEBARKAwMDVgAAAGQDAwNrAAAAbQAAAHYCAgKHAgICkAICApECAgKSAgICkgIC
-ApICAgKSAgICkgICApICAgKSAgICkgICApICAgKRAgICjQMDA30DAwNVAAAAHgAAAAQAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAEAAAACAAAABAAAAAUAAAAGAAAABwAAAAgAAAALAAAAEQAAABkJCQkd
-CQkJHggICCMAAAAsAAAAMQAAADEAAAAyAAAAMgAAADIAAAAyAAAAMgAAADIAAAAyAAAAMgAA
-ADIAAAAxAAAALwAAACgAAAAZAAAACAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAIAAAACAAAAAwAAAAMAAAAFAAAABQAAAAUAAAAG
-AAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAFAAAABQAAAAQAAAACAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAA
-.
 T 14400 8300 9 10 1 0 0 2 3
 This is Multi-Line
 Text.  This text takes up
@@ -438,3 +263,47 @@ L 16100 3500 17400 3500 3 0 0 0 -1 -1
 N 16100 7100 16700 7100 4
 N 16400 6900 16400 7100 4
 N 16500 7300 16500 7100 4
+G 4900 11200 500 600 0 0 1
+test.png
+iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAAAAACPAi4CAAAAAXNSR0IDN8dNUwAAANNpQ0NQ
+aWNjAAB42mNgYEzISc4tZlFgYMjNKylyD3KMjIiMUmC/zcDDwMkgzqDKoJeYXFzgGBDgw4AT
+fLvGwAiiL+uCzGIgDbCkpBYnA+ktQGyRXFBUAqTfALFfeUkBkM1oA2SLZIcEOQPZAUC2QG5O
+aTJUL8hWntS80GAgLQPG6QxFDIkMlQwKDEkMpQyZDDkMJQy6QDoP6D/s+ozA+vwY8oF6koFk
+AVB3EVBHOkMGUK8OULSUoZghFUinAcVTgTAHqAIIQOGE7v+CxKJEuM+YjI0Bpr8zRfhQAY0A
+AAAJcEhZcwAAD2EAAA9hAag/p2kAAAAfelRYdGF1dGhvcgAAeNpzyi9NSS3PzMpTCErNLSgB
+AC4pBdBUK6Y8AAAAM0lEQVRYw+3QsREAMAgDMWD0LJ6MQEFH5PpPhfPEbBUAAGAJkF1wnQgA
+AAAAAAAAAPwKPFhnAgC601zyAAAAAElFTkSuQmCC
+.
+G 5500 11200 500 600 90 0 1
+test.png
+iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAAAAACPAi4CAAAAAXNSR0IDN8dNUwAAANNpQ0NQ
+aWNjAAB42mNgYEzISc4tZlFgYMjNKylyD3KMjIiMUmC/zcDDwMkgzqDKoJeYXFzgGBDgw4AT
+fLvGwAiiL+uCzGIgDbCkpBYnA+ktQGyRXFBUAqTfALFfeUkBkM1oA2SLZIcEOQPZAUC2QG5O
+aTJUL8hWntS80GAgLQPG6QxFDIkMlQwKDEkMpQyZDDkMJQy6QDoP6D/s+ozA+vwY8oF6koFk
+AVB3EVBHOkMGUK8OULSUoZghFUinAcVTgTAHqAIIQOGE7v+CxKJEuM+YjI0Bpr8zRfhQAY0A
+AAAJcEhZcwAAD2EAAA9hAag/p2kAAAAfelRYdGF1dGhvcgAAeNpzyi9NSS3PzMpTCErNLSgB
+AC4pBdBUK6Y8AAAAM0lEQVRYw+3QsREAMAgDMWD0LJ6MQEFH5PpPhfPEbBUAAGAJkF1wnQgA
+AAAAAAAAAPwKPFhnAgC601zyAAAAAElFTkSuQmCC
+.
+G 6100 11200 500 600 0 1 1
+test.png
+iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAAAAACPAi4CAAAAAXNSR0IDN8dNUwAAANNpQ0NQ
+aWNjAAB42mNgYEzISc4tZlFgYMjNKylyD3KMjIiMUmC/zcDDwMkgzqDKoJeYXFzgGBDgw4AT
+fLvGwAiiL+uCzGIgDbCkpBYnA+ktQGyRXFBUAqTfALFfeUkBkM1oA2SLZIcEOQPZAUC2QG5O
+aTJUL8hWntS80GAgLQPG6QxFDIkMlQwKDEkMpQyZDDkMJQy6QDoP6D/s+ozA+vwY8oF6koFk
+AVB3EVBHOkMGUK8OULSUoZghFUinAcVTgTAHqAIIQOGE7v+CxKJEuM+YjI0Bpr8zRfhQAY0A
+AAAJcEhZcwAAD2EAAA9hAag/p2kAAAAfelRYdGF1dGhvcgAAeNpzyi9NSS3PzMpTCErNLSgB
+AC4pBdBUK6Y8AAAAM0lEQVRYw+3QsREAMAgDMWD0LJ6MQEFH5PpPhfPEbBUAAGAJkF1wnQgA
+AAAAAAAAAPwKPFhnAgC601zyAAAAAElFTkSuQmCC
+.
+G 6700 11200 500 600 270 1 1
+test.png
+iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAAAAACPAi4CAAAAAXNSR0IDN8dNUwAAANNpQ0NQ
+aWNjAAB42mNgYEzISc4tZlFgYMjNKylyD3KMjIiMUmC/zcDDwMkgzqDKoJeYXFzgGBDgw4AT
+fLvGwAiiL+uCzGIgDbCkpBYnA+ktQGyRXFBUAqTfALFfeUkBkM1oA2SLZIcEOQPZAUC2QG5O
+aTJUL8hWntS80GAgLQPG6QxFDIkMlQwKDEkMpQyZDDkMJQy6QDoP6D/s+ozA+vwY8oF6koFk
+AVB3EVBHOkMGUK8OULSUoZghFUinAcVTgTAHqAIIQOGE7v+CxKJEuM+YjI0Bpr8zRfhQAY0A
+AAAJcEhZcwAAD2EAAA9hAag/p2kAAAAfelRYdGF1dGhvcgAAeNpzyi9NSS3PzMpTCErNLSgB
+AC4pBdBUK6Y8AAAAM0lEQVRYw+3QsREAMAgDMWD0LJ6MQEFH5PpPhfPEbBUAAGAJkF1wnQgA
+AAAAAAAAAPwKPFhnAgC601zyAAAAAElFTkSuQmCC
+.
diff --git a/gschem/include/prototype.h b/gschem/include/prototype.h
index 1ce0283..ddb6735 100644
--- a/gschem/include/prototype.h
+++ b/gschem/include/prototype.h
@@ -632,7 +632,7 @@ void o_picture_draw_rubber(GSCHEM_TOPLEVEL *w_current);
 void o_picture_draw(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current);
 void o_picture_draw_grips(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current);
 void o_picture_draw_place(GSCHEM_TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current);
-void o_picture_exchange(GSCHEM_TOPLEVEL *w_current, GdkPixbuf *pixbuf, const gchar *filename);
+gboolean o_picture_exchange(GSCHEM_TOPLEVEL *w_current, const gchar *filename, GError **error);
 void picture_change_filename_dialog (GSCHEM_TOPLEVEL *w_current);
 void o_picture_set_pixbuf(GSCHEM_TOPLEVEL *w_current, GdkPixbuf *pixbuf, char *filename);
 
diff --git a/gschem/src/o_grips.c b/gschem/src/o_grips.c
index fb26c7c..1bc8e54 100644
--- a/gschem/src/o_grips.c
+++ b/gschem/src/o_grips.c
@@ -725,11 +725,13 @@ static void o_grips_start_path(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current,
 static void o_grips_start_picture(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current,
                                   int x, int y, int whichone)
 {
+  TOPLEVEL *toplevel = w_current->toplevel;
   w_current->last_drawb_mode = LAST_DRAWB_MODE_NONE;
 
-  w_current->current_pixbuf = o_current->picture->pixbuf;
-  w_current->pixbuf_filename = o_current->picture->filename;
-  w_current->pixbuf_wh_ratio = o_current->picture->ratio;
+  w_current->current_pixbuf = o_picture_get_pixbuf (toplevel, o_current);
+  w_current->pixbuf_filename =
+    g_strdup (o_picture_get_filename (toplevel, o_current));
+  w_current->pixbuf_wh_ratio = o_picture_get_ratio (toplevel, o_current);
 
   /* (second_wx,second_wy) is the selected corner */
   /* (first_wx, first_wy) is the opposite corner */
@@ -1134,7 +1136,9 @@ static void o_grips_end_picture(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current,
   o_picture_modify(toplevel, o_current, 
 		   w_current->second_wx, w_current->second_wy, whichone);
 
+  g_object_unref (w_current->current_pixbuf);
   w_current->current_pixbuf = NULL;
+  g_free (w_current->pixbuf_filename);
   w_current->pixbuf_filename = NULL;
   w_current->pixbuf_wh_ratio = 0;
 }
diff --git a/gschem/src/o_picture.c b/gschem/src/o_picture.c
index d602537..d0e7683 100644
--- a/gschem/src/o_picture.c
+++ b/gschem/src/o_picture.c
@@ -103,9 +103,9 @@ void o_picture_end(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y)
   }
 
   /* create the object */
-  new_obj = o_picture_new(toplevel, w_current->current_pixbuf,
+  new_obj = o_picture_new(toplevel,
                           NULL, 0, w_current->pixbuf_filename,
-                          w_current->pixbuf_wh_ratio, OBJ_PICTURE,
+                          OBJ_PICTURE,
                           picture_left, picture_top,
                           picture_left + picture_width,
                           picture_top - picture_height,
@@ -302,11 +302,37 @@ void o_picture_draw_rubber (GSCHEM_TOPLEVEL *w_current)
 void o_picture_draw (GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
 {
   int s_upper_x, s_upper_y, s_lower_x, s_lower_y;
+  GdkPixbuf *pixbuf;
 
-  if (o_current->picture == NULL) {
+  g_return_if_fail (w_current != NULL);
+  g_return_if_fail (w_current->toplevel != NULL);
+  g_return_if_fail (o_current != NULL);
+  g_return_if_fail (o_current->picture != NULL);
+
+  pixbuf = o_picture_get_pixbuf (w_current->toplevel, o_current);
+
+  /* If the image failed to load, get the fallback image. */
+  if (pixbuf == NULL) pixbuf = o_picture_get_fallback_pixbuf (w_current->toplevel);
+  /* If the fallback image failed to load, draw a box with a cross in it. */
+  if (pixbuf == NULL) {
+    int line_width = (w_current->toplevel->line_style == THICK) ? LINE_WIDTH : 2;
+    gschem_cairo_set_source_color (w_current,
+                                   o_drawing_color (w_current, o_current));
+    gschem_cairo_box (w_current, line_width,
+                      o_current->picture->lower_x, o_current->picture->lower_y,
+                      o_current->picture->upper_x, o_current->picture->upper_y);
+    gschem_cairo_line (w_current, END_ROUND, line_width,
+                      o_current->picture->lower_x, o_current->picture->lower_y,
+                      o_current->picture->upper_x, o_current->picture->upper_y);
+    gschem_cairo_line (w_current, END_ROUND, line_width,
+                      o_current->picture->lower_x, o_current->picture->upper_y,
+                      o_current->picture->upper_x, o_current->picture->lower_y);
+    gschem_cairo_stroke (w_current, TYPE_SOLID, END_ROUND, line_width, -1, -1);
     return;
   }
 
+  g_assert (GDK_IS_PIXBUF (pixbuf));
+
   WORLDtoSCREEN (w_current, o_current->picture->upper_x,
                             o_current->picture->upper_y, &s_upper_x, &s_upper_y);
   WORLDtoSCREEN (w_current, o_current->picture->lower_x,
@@ -315,10 +341,10 @@ void o_picture_draw (GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
   cairo_save (w_current->cr);
 
   int swap_wh = (o_current->picture->angle == 90 || o_current->picture->angle == 270);
-  float orig_width  = swap_wh ? gdk_pixbuf_get_height (o_current->picture->pixbuf) :
-                                gdk_pixbuf_get_width  (o_current->picture->pixbuf);
-  float orig_height = swap_wh ? gdk_pixbuf_get_width  (o_current->picture->pixbuf) :
-                                gdk_pixbuf_get_height (o_current->picture->pixbuf);
+  float orig_width  = swap_wh ? gdk_pixbuf_get_height (pixbuf) :
+                                gdk_pixbuf_get_width  (pixbuf);
+  float orig_height = swap_wh ? gdk_pixbuf_get_width  (pixbuf) :
+                                gdk_pixbuf_get_height (pixbuf);
 
   cairo_translate (w_current->cr, s_upper_x, s_upper_y);
   cairo_scale (w_current->cr,
@@ -335,14 +361,16 @@ void o_picture_draw (GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
     case 270:  cairo_translate (w_current->cr, orig_width, 0          );  break;
   }
   cairo_rotate (w_current->cr, -o_current->picture->angle * M_PI / 180.);
-  if (o_current->picture->mirrored)
+  if (o_current->picture->mirrored) {
+    cairo_translate (w_current->cr, gdk_pixbuf_get_width (pixbuf), 0);
     cairo_scale (w_current->cr, -1, 1);
+  }
 
   gdk_cairo_set_source_pixbuf (w_current->cr,
-                               o_current->picture->pixbuf, 0,0);
+                               pixbuf, 0,0);
   cairo_rectangle (w_current->cr, 0, 0,
-                   gdk_pixbuf_get_width (o_current->picture->pixbuf),
-                   gdk_pixbuf_get_height (o_current->picture->pixbuf));
+                   gdk_pixbuf_get_width (pixbuf),
+                   gdk_pixbuf_get_height (pixbuf));
 
   cairo_clip (w_current->cr);
   cairo_paint (w_current->cr);
@@ -352,6 +380,8 @@ void o_picture_draw (GSCHEM_TOPLEVEL *w_current, OBJECT *o_current)
   if (o_current->selected && w_current->draw_grips) {
     o_picture_draw_grips (w_current, o_current);
   }
+
+  g_object_unref (pixbuf);
 }
 
 /*! \brief Draw grip marks on picture.
@@ -424,68 +454,42 @@ void o_picture_draw_place (GSCHEM_TOPLEVEL *w_current, int dx, int dy, OBJECT *o
 }
 
 /*! \brief Replace all selected pictures with a new picture
- *  \par Function Description
- *  This function replaces all pictures in the current selection with a 
- *  new image.
- *   
- *  \param [in] w_current  The GSCHEM_TOPLEVEL object
- *  \param [in] pixbuf     New GdkPixbuf object
- *  \param [in] filename   The filename of the new picture
- *  
+ * \par Function Description
+ * Replaces all pictures in the current selection with a new image.
+ *
+ * \param [in] w_current  The GSCHEM_TOPLEVEL object
+ * \param [in] filename   The filename of the new picture
+ * \param [out] error     The location to return error information.
+ * \return TRUE on success, FALSE on failure.
  */
-void o_picture_exchange (GSCHEM_TOPLEVEL *w_current, GdkPixbuf *pixbuf,
-			 const gchar *filename)
+gboolean
+o_picture_exchange (GSCHEM_TOPLEVEL *w_current,
+                    const gchar *filename, GError **error)
 {
   TOPLEVEL *toplevel = w_current->toplevel;
-  GList *list;  
-
-  list = geda_list_get_glist( toplevel->page_current->selection_list );
-  while (list != NULL) {
-    OBJECT *object;
+  GList *iter;
 
-    object = (OBJECT *) list->data;
+  for (iter = geda_list_get_glist (toplevel->page_current->selection_list);
+       iter != NULL;
+       iter = g_list_next (iter)) {
 
+    OBJECT *object = (OBJECT *) iter->data;
     g_assert (object != NULL);
 
-    if (!object->attached_to) {
-      /* It's selected. Then change picture if it's a picture */
-      if (object->type == OBJ_PICTURE) {
-
-        /* Erase previous picture */
-        o_invalidate (w_current, object);
-
-        g_free(object->picture->filename);
-
-        object->picture->filename = (char *) g_strdup(filename);
-
-        /* Unref the old pixmap */
-        if (object->picture->pixbuf != NULL) {
-          g_object_unref (object->picture->pixbuf);
-          object->picture->pixbuf = NULL;
-        }
-
-        if (object->picture->embedded) {
-          /* For embedded pictures, call o_picture_embed() to update the
-           * embedded picture data from the new file and reload the pixmap */
-          o_picture_embed(toplevel, object);
-        } else {
-          /* For non-embedded pictures, create a copy of the passed pixbuf
-           * and insert it manually */
-          object->picture->pixbuf = gdk_pixbuf_copy (pixbuf);
-          if (object->picture->pixbuf == NULL) {
-            fprintf(stderr, "change picture: Couldn't get enough memory for the new picture\n");
-            return;
-          }
-        }
-
-        object->picture->ratio = (double)gdk_pixbuf_get_width(pixbuf) /
-                                         gdk_pixbuf_get_height(pixbuf);
-        /* Draw new picture */
-        o_invalidate (w_current, object);
-      }
+    if (object->type == OBJ_PICTURE) {
+      gboolean status;
+
+      /* Erase previous picture */
+      o_invalidate (w_current, object);
+
+      status = o_picture_set_from_file (toplevel, object, filename, error);
+      if (!status) return FALSE;
+
+      /* Draw new picture */
+      o_invalidate (w_current, object);
     }
-    list = g_list_next(list);
   }
+  return TRUE;
 }
 
 /*! \brief Create dialog to exchange picture objects
@@ -499,7 +503,7 @@ void picture_change_filename_dialog (GSCHEM_TOPLEVEL *w_current)
 {
   TOPLEVEL *toplevel = w_current->toplevel;
   gchar *filename;
-  GdkPixbuf *pixbuf;
+  gboolean result;
   GError *error = NULL;
   
   w_current->pfswindow = gtk_file_chooser_dialog_new ("Select a picture file...",
@@ -527,38 +531,24 @@ void picture_change_filename_dialog (GSCHEM_TOPLEVEL *w_current)
     gtk_widget_destroy(w_current->pfswindow);
     w_current->pfswindow=NULL;
 
-    pixbuf = gdk_pixbuf_new_from_file (filename, &error);
-    
-    if (!pixbuf) {
+    /* Actually update the pictures */
+    result = o_picture_exchange (w_current, filename, &error);
+
+    if (!result) {
       GtkWidget *dialog;
-      
+
       dialog = gtk_message_dialog_new (GTK_WINDOW (w_current->main_window),
 				       GTK_DIALOG_DESTROY_WITH_PARENT,
 				       GTK_MESSAGE_ERROR,
 				       GTK_BUTTONS_CLOSE,
-				       _("Failed to load picture: %s"),
+				       _("Failed to replace pictures: %s"),
 				       error->message);
       /* Wait for any user response */
       gtk_dialog_run (GTK_DIALOG (dialog));
-      
+
       g_error_free (error);
       gtk_widget_destroy(dialog);
-    }
-    else {
-#if DEBUG
-      printf("Picture loaded succesfully.\n");
-#endif
-
-      o_invalidate_rubber(w_current);
-      w_current->inside_action = 0;
-
-      /* \FIXME Should we set the pixbuf buffer in GSCHEM_TOPLEVEL to store
-	 the current pixbuf? (Werner)
-	 o_picture_set_pixbuf(w_current, pixbuf, filename); */
-
-      o_picture_exchange(w_current, pixbuf, filename);
-
-      g_object_unref(pixbuf);
+    } else {
       toplevel->page_current->CHANGED=1;
     }
     g_free (filename);
diff --git a/libgeda/include/libgeda/prototype.h b/libgeda/include/libgeda/prototype.h
index 85cab06..bb69439 100644
--- a/libgeda/include/libgeda/prototype.h
+++ b/libgeda/include/libgeda/prototype.h
@@ -198,21 +198,29 @@ void o_path_rotate_world(TOPLEVEL *toplevel, int world_centerx, int world_center
 void o_path_mirror_world(TOPLEVEL *toplevel, int world_centerx, int world_centery, OBJECT *object);
 
 /* o_picture.c */
-OBJECT *o_picture_new(TOPLEVEL *toplevel, GdkPixbuf *pixbuf,
-                      gchar *file_content, gsize file_length, char *filename,
-                      double ratio, char type,
-                      int x1, int y1, int x2, int y2, int angle, char mirrored,
-                      char embedded);
+OBJECT *o_picture_new(TOPLEVEL *toplevel,
+                      const gchar *file_content, gsize file_length,
+                      const gchar *filename, char type,
+                      int x1, int y1, int x2, int y2, int angle, int mirrored,
+                      int embedded) G_GNUC_WARN_UNUSED_RESULT;
+double o_picture_get_ratio (TOPLEVEL *toplevel, OBJECT *object);
 void o_picture_modify(TOPLEVEL *toplevel, OBJECT *object, int x, int y, int whichone);
+void o_picture_modify_all (TOPLEVEL *toplevel, OBJECT *object, int x1, int y1, int x2, int y2);
 void o_picture_rotate_world(TOPLEVEL *toplevel, int world_centerx, int world_centery, int angle,OBJECT *object);
 void o_picture_mirror_world(TOPLEVEL *toplevel, int world_centerx, int world_centery, OBJECT *object);
 void o_picture_translate_world(TOPLEVEL *toplevel, int dx, int dy, OBJECT *object);
-OBJECT *o_picture_copy(TOPLEVEL *toplevel, OBJECT *o_current);
-guint8 *o_picture_rgb_data(GdkPixbuf *image);
-guint8 *o_picture_mask_data(GdkPixbuf *image);
-void o_picture_embed(TOPLEVEL *toplevel, OBJECT *object);
-void o_picture_unembed(TOPLEVEL *toplevel, OBJECT *object);
-GdkPixbuf *o_picture_pixbuf_from_buffer (gchar *file_content, gsize file_length, GError **err);
+OBJECT *o_picture_copy(TOPLEVEL *toplevel, OBJECT *o_current) G_GNUC_WARN_UNUSED_RESULT;
+gboolean o_picture_is_embedded (TOPLEVEL *toplevel, OBJECT *object);
+GdkPixbuf *o_picture_get_pixbuf (TOPLEVEL *toplevel, OBJECT *object) G_GNUC_WARN_UNUSED_RESULT;
+const char *o_picture_get_data (TOPLEVEL *toplevel, OBJECT *object,
+                                size_t *len);
+gboolean o_picture_set_from_buffer (TOPLEVEL *toplevel, OBJECT *object,
+                                    const gchar *filename, const gchar *data,
+                                    size_t len, GError **error);
+gboolean o_picture_set_from_file (TOPLEVEL *toplevel, OBJECT *object,
+                                  const gchar *filename, GError **error);
+const gchar *o_picture_get_filename (TOPLEVEL *toplevel, OBJECT *object);
+GdkPixbuf *o_picture_get_fallback_pixbuf (TOPLEVEL *toplevel) G_GNUC_WARN_UNUSED_RESULT;
 
 /* o_pin_basic.c */
 OBJECT *o_pin_new(TOPLEVEL *toplevel, char type, int color, int x1, int y1, int x2, int y2, int pin_type, int whichend);
diff --git a/libgeda/include/prototype_priv.h b/libgeda/include/prototype_priv.h
index 63f411b..a6edf75 100644
--- a/libgeda/include/prototype_priv.h
+++ b/libgeda/include/prototype_priv.h
@@ -192,6 +192,8 @@ double o_picture_shortest_distance(OBJECT *object, int x, int y, int force_soild
 void world_get_picture_bounds(TOPLEVEL *toplevel, OBJECT *object, int *left, int *top, int *right, int *bottom);
 gboolean o_picture_get_position(TOPLEVEL *toplevel, gint *x, gint *y, OBJECT *object);
 void o_picture_recalc(TOPLEVEL *toplevel, OBJECT *o_current);
+void o_picture_embed(TOPLEVEL *toplevel, OBJECT *object);
+void o_picture_unembed(TOPLEVEL *toplevel, OBJECT *object);
 
 /* o_pin_basic.c */
 OBJECT *o_pin_read(TOPLEVEL *toplevel, char buf[], unsigned int release_ver, unsigned int fileformat_ver);
diff --git a/libgeda/src/o_embed.c b/libgeda/src/o_embed.c
index eb833ec..6e7933a 100644
--- a/libgeda/src/o_embed.c
+++ b/libgeda/src/o_embed.c
@@ -62,7 +62,7 @@ void o_embed(TOPLEVEL *toplevel, OBJECT *o_current)
 
   /* If it's a picture and it's not embedded */
   if ( (o_current->type == OBJ_PICTURE) &&
-       (o_current->picture->embedded == 0) ) {
+       !o_picture_is_embedded (toplevel, o_current) ) {
     o_picture_embed (toplevel, o_current);
 
     page_modified = 1;
@@ -116,7 +116,7 @@ void o_unembed(TOPLEVEL *toplevel, OBJECT *o_current)
 
   /* If it's a picture and it's embedded */
   if ( (o_current->type == OBJ_PICTURE) &&
-       (o_current->picture->embedded == 1) ) {
+       o_picture_is_embedded (toplevel, o_current)) {
     o_picture_unembed (toplevel, o_current);
 
     page_modified = 1;
diff --git a/libgeda/src/o_picture.c b/libgeda/src/o_picture.c
index 3119c12..82a5bac 100644
--- a/libgeda/src/o_picture.c
+++ b/libgeda/src/o_picture.c
@@ -31,13 +31,14 @@
 #include <math.h>
 
 #include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gio/gio.h>
 
 #include "libgeda_priv.h"
 
 /*! \brief Create picture OBJECT from character string.
  *  \par Function Description
- *  This function will get the description of a picture from the
- *  character string <B>*first_line</B>.
+ *  Parses \a first_line and subsequent lines from \a tb, and returns
+ *  a newly-created picture #OBJECT.
  *
  *  \param [in]  toplevel       The TOPLEVEL object.
  *  \param [in]  first_line      Character string with picture description.
@@ -55,17 +56,15 @@ OBJECT *o_picture_read (TOPLEVEL *toplevel,
   OBJECT *new_obj;
   int x1, y1;
   int width, height, angle;
-  gchar mirrored, embedded;
+  int mirrored, embedded;
   int num_conv;
   gchar type;
   gchar *line = NULL;
   gchar *filename;
-  GdkPixbuf *pixbuf = NULL;
   gchar *file_content = NULL;
   guint file_length = 0;
-  GError *err = NULL;
 
-  num_conv = sscanf(first_line, "%c %d %d %d %d %d %c %c\n",
+  num_conv = sscanf(first_line, "%c %d %d %d %d %d %d %d\n",
 	 &type, &x1, &y1, &width, &height, &angle, &mirrored, &embedded);
   
   if (num_conv != 8) {
@@ -73,33 +72,25 @@ OBJECT *o_picture_read (TOPLEVEL *toplevel,
                    first_line);
   }
 
-  /* Convert from ascii character to number */
-  if (g_ascii_isdigit(mirrored)) {
-    mirrored -= 0x30;
-  }
-
-  if (g_ascii_isdigit(embedded)) {
-    embedded -= 0x30;
-  }
-
   if (width == 0 || height == 0) {
     s_log_message(_("Found a zero width/height picture [ %c %d %d %d %d ]\n"),
                   type, x1, y1, width, height);
   }
 
   if ( (mirrored > 1) || (mirrored < 0)) {
-    s_log_message(_("Found a picture with a wrong 'mirrored' parameter: %c.\n"),
+    s_log_message(_("Found a picture with a wrong 'mirrored' parameter: %d.\n"),
 	    mirrored);
     s_log_message(_("Setting mirrored to 0\n"));
     mirrored = 0;
   }
 
   if ( (embedded > 1) || (embedded < 0)) {
-    s_log_message(_("Found a picture with a wrong 'embedded' parameter: %c.\n"),
+    s_log_message(_("Found a picture with a wrong 'embedded' parameter: %d.\n"),
 	    embedded);
     s_log_message(_("Setting embedded to 0\n"));
     embedded = 0;
   }
+
   switch(angle) {
 	
     case(0):
@@ -119,6 +110,12 @@ OBJECT *o_picture_read (TOPLEVEL *toplevel,
   filename = g_strdup(s_textbuffer_next_line(tb));
   filename = remove_last_nl(filename);	
 
+  /* Handle empty filenames */
+  if (strlen (filename) == 0) {
+    s_log_message (_("Found an image with no filename."));
+    g_free (filename);
+  }
+
   if (embedded == 1) {
     GString *encoded_picture=g_string_new("");
     char finished = 0;
@@ -152,56 +149,15 @@ OBJECT *o_picture_read (TOPLEVEL *toplevel,
     }
   }
 
-  /* If we have embedded data, try loading from the decoded buffer */
-  if (file_content != NULL) {
-    pixbuf = o_picture_pixbuf_from_buffer (file_content, file_length, &err);
-    if (err != NULL) {
-      s_log_message (_("Failed to load image from embedded data [%s]: %s\n"),
-                     filename, err->message);
-      s_log_message (_("Falling back to file loading. Picture unembedded.\n"));
-      g_error_free (err);
-      err = NULL;
-      embedded = 0;
-    }
-  }
-
-  /* If we haven't loaded the pixbuf above, try loading from file */
-  if (pixbuf == NULL) {
-    pixbuf = gdk_pixbuf_new_from_file (filename, &err);
-    if (err != NULL) {
-      s_log_message (_("Failed to load image from file [%s]: %s\n"),
-                     filename, err->message);
-      g_error_free (err);
-      err = NULL;
-    }
-  }
-
-  /* If the pixbuf couldn't be loaded, then try to load a warning picture */
-  if (pixbuf == NULL) {
-    char *temp_filename;
-
-    s_log_message (_("Loading warning picture.\n"));
-    
-    temp_filename = g_build_filename (toplevel->bitmap_directory,
-                                      "gschem-warning.png", NULL);
-    pixbuf = gdk_pixbuf_new_from_file (temp_filename, NULL);
-    if (pixbuf == NULL) {
-      s_log_message( _("Error loading picture from file: %s.\n"),
-                     temp_filename);
-    }      
-    g_free (temp_filename);
-  }
-  
   /* create the picture */
   /* The picture is described by its upper left and lower right corner */
-  new_obj = o_picture_new(toplevel, pixbuf,
-                          file_content, file_length, filename,
-                          (double)width / (double)height,
-                          type,
-                          x1, y1+height, x1+width, y1,
-                          angle, mirrored, embedded);
+  new_obj = o_picture_new (toplevel, file_content, file_length, filename,
+                           type,
+                           x1, y1+height, x1+width, y1,
+                           angle, mirrored, embedded);
 
-  /* Don't free file_content, it is now owned by the picture object */
+  g_free (file_content);
+  g_free (filename);
 
   return new_obj;
 }
@@ -226,6 +182,7 @@ char *o_picture_save(TOPLEVEL *toplevel, OBJECT *object)
   gchar *encoded_picture=NULL;
   gchar *out=NULL;
   guint encoded_picture_length;
+  const gchar *filename = NULL;
 
   /* calculate the width and height of the box */
   width  = abs(object->picture->lower_x - object->picture->upper_x); 
@@ -240,7 +197,7 @@ char *o_picture_save(TOPLEVEL *toplevel, OBJECT *object)
 #endif
 
   /* Encode the picture if it's embedded */
-  if (object->picture->embedded == 1) {
+  if (o_picture_is_embedded (toplevel, object)) {
     encoded_picture =
       s_encoding_base64_encode( (char *)object->picture->file_content,
                                 object->picture->file_length,
@@ -251,7 +208,11 @@ char *o_picture_save(TOPLEVEL *toplevel, OBJECT *object)
     }
   }
 
-  if (object->picture->embedded==1 &&
+  /* Cope with null filename */
+  filename = o_picture_get_filename (toplevel, object);
+  if (filename == NULL) filename = "";
+
+  if (o_picture_is_embedded (toplevel, object) &&
       encoded_picture != NULL) {
     out = g_strdup_printf("%c %d %d %d %d %d %c %c\n%s\n%s\n%s", 
 			  object->type,
@@ -259,8 +220,8 @@ char *o_picture_save(TOPLEVEL *toplevel, OBJECT *object)
 			  object->picture->angle,
 			  /* Convert the (0,1) chars to ASCII */
 			  (object->picture->mirrored)+0x30, 
-			  object->picture->embedded+0x30, 
-			  object->picture->filename,
+			  '1', 
+			  filename,
 			  encoded_picture,
 			  ".");
   }
@@ -271,8 +232,8 @@ char *o_picture_save(TOPLEVEL *toplevel, OBJECT *object)
 			  object->picture->angle,
 			  /* Convert the (0,1) chars to ASCII */
 			  (object->picture->mirrored)+0x30, 
-			  object->picture->embedded+0x30, 
-			  object->picture->filename);
+			  '0', 
+			  filename);
   }
   g_free(encoded_picture);
 
@@ -280,29 +241,24 @@ char *o_picture_save(TOPLEVEL *toplevel, OBJECT *object)
 }
 
 
-/*! \brief Create and add picture OBJECT to list.
+/*! \brief Create a picture object.
  *  \par Function Description
  *  This function creates a new object representing a picture.
  *
- *  The picture is described by its upper left corner - <B>x1</B>, <B>y1</B> -
- *  and its lower right corner - <B>x2</B>, <B>y2</B>.
- *  The <B>type</B> parameter must be equal to #OBJ_PICTURE. 
+ *  The picture is described by its upper left corner (\a x1, \a y1)
+ *  and its lower right corner (\a x2, \ay2).  The \a type parameter
+ *  must be equal to #OBJ_PICTURE.
  *
- *  The #OBJECT structure is allocated with the #s_basic_init_object()
- *  function. The structure describing the picture is allocated and
- *  initialized with the parameters given to the function.
+ *  If \a file_content is non-NULL, it must be a pointer to a buffer
+ *  containing raw image data.  If loading data from \a file_content
+ *  is unsuccessful, and \a filename is non-NULL, an image will
+ *  attempt to be loaded from \a filename.  Otherwise, the picture
+ *  object will be initially empty.
  *
  *  \param [in]     toplevel      The TOPLEVEL object.
- *  \param [in]     pixbuf        The GdkPixbuf picture to add.
- *                                A copy of this pixbuf is made.
- *  \param [in]     file_content  Raw data of the image file.
- *                                NULL for non embedded loading. The object
- *                                object takes ownership of this buffer, and it
- *                                should not be free'd by the caller.
+ *  \param [in]     file_content  Raw data of the image file, or NULL.
  *  \param [in]     file_length   Length of raw data buffer
- *  \param [in]     filename      File name backing this picture.
- *                                A copy of this string is made.
- *  \param [in]     ratio         Picture height to width ratio.
+ *  \param [in]     filename      File name backing this picture, or NULL.
  *  \param [in]     type          Must be OBJ_PICTURE.
  *  \param [in]     x1            Upper x coordinate.
  *  \param [in]     y1            Upper y coordinate.
@@ -311,13 +267,13 @@ char *o_picture_save(TOPLEVEL *toplevel, OBJECT *object)
  *  \param [in]     angle         Picture rotation angle.
  *  \param [in]     mirrored      Whether the image should be mirrored or not.
  *  \param [in]     embedded      Whether the embedded flag should be set or not.
- *  \return A pointer to the new end of the object list.
+ *  \return A pointer to a new picture #OBJECT.
  */
-OBJECT *o_picture_new(TOPLEVEL *toplevel, GdkPixbuf *pixbuf,
-                      gchar *file_content, gsize file_length, char *filename,
-                      double ratio, char type,
-                      int x1, int y1, int x2, int y2, int angle, char mirrored,
-                      char embedded)
+OBJECT *o_picture_new (TOPLEVEL *toplevel,
+                       const gchar *file_content, gsize file_length,
+                       const gchar *filename,
+                       char type, int x1, int y1, int x2, int y2, int angle,
+                       int mirrored, int embedded)
 {
   OBJECT *new_node;
   PICTURE *picture;
@@ -325,24 +281,48 @@ OBJECT *o_picture_new(TOPLEVEL *toplevel, GdkPixbuf *pixbuf,
   /* create the object */
   new_node = s_basic_new_object(type, "picture");
 
-  picture = (PICTURE *) g_malloc(sizeof(PICTURE));
+  picture = (PICTURE *) g_malloc0 (sizeof(PICTURE));
   new_node->picture = picture;
 
   /* describe the picture with its upper left and lower right corner */
-  picture->upper_x = x1;
-  picture->upper_y = y1;
-  picture->lower_x = x2;
-  picture->lower_y = y2;
+  picture->upper_x = (x1 > x2) ? x2 : x1;
+  picture->upper_y = (y1 > y2) ? y1 : y2;
+  picture->lower_x = (x1 > x2) ? x1 : x2;
+  picture->lower_y = (y1 > y2) ? y2 : y1;
+
+  picture->pixbuf = NULL;
+  picture->file_content = NULL;
+  picture->file_length = 0;
 
-  picture->file_content = file_content;
-  picture->file_length  = file_length;
+  picture->ratio = abs ((double) (x1 - x2) / (y1 - y2));
   picture->filename = g_strdup (filename);
-  picture->ratio = ratio;
-  picture->pixbuf = gdk_pixbuf_copy (pixbuf);
   picture->angle = angle;
   picture->mirrored = mirrored;
   picture->embedded = embedded;
 
+  if (file_content != NULL) {
+    GError *error = NULL;
+    if (!o_picture_set_from_buffer (toplevel, new_node, filename,
+                                    file_content, file_length, &error)) {
+      s_log_message (_("Failed to load buffer image [%s]: %s\n"),
+                     filename, error->message);
+      g_error_free (error);
+
+      /* Force the data into the object anyway, so as to prevent data
+       * loss of embedded images. */
+      picture->file_content = g_memdup (file_content, file_length);
+      picture->file_length = file_length;
+    }
+  }
+  if (picture->pixbuf == NULL && filename != NULL) {
+    GError *error = NULL;
+    if (!o_picture_set_from_file (toplevel, new_node, filename, &error)) {
+      s_log_message (_("Failed to load image from [%s]: %s\n"),
+                     filename, error->message);
+      g_error_free (error);
+    }
+  }
+
   /* compute the bounding picture */
   o_picture_recalc(toplevel, new_node);
 
@@ -416,6 +396,39 @@ gboolean o_picture_get_position (TOPLEVEL *toplevel, gint *x, gint *y,
   return TRUE;
 }
                  
+
+/*! \brief Get the width/height ratio of an image.
+ * \par Function Description
+
+ * Returns the width/height ratio of picture \a object, taking the
+ * image rotation into account.
+ *
+ * \param toplevel  The current #TOPLEVEL.
+ * \param object    Picture #OBJECT to inspect.
+ * \return width/height ratio for \a object.
+ */
+double
+o_picture_get_ratio (TOPLEVEL *toplevel, OBJECT *object)
+{
+  g_return_val_if_fail (object != NULL, 1);
+  g_return_val_if_fail (object->picture != NULL, 1);
+
+  /* The effective ratio varies depending on the rotation of the
+   * image. */
+  switch (object->picture->angle) {
+  case 0:
+  case 180:
+    return object->picture->ratio;
+  case 90:
+  case 270:
+    return 1.0 / object->picture->ratio;
+  default:
+    g_critical (_("Picture %p has invalid angle %i\n"), object,
+                object->picture->angle);
+  }
+  return 0;
+}
+
 /*! \brief Modify the description of a picture OBJECT.
  *  \par Function Description
  *  This function modifies the coordinates of one of the four corner of
@@ -443,6 +456,7 @@ void o_picture_modify(TOPLEVEL *toplevel, OBJECT *object,
 		      int x, int y, int whichone)
 {
   int tmp;
+  double ratio = o_picture_get_ratio (toplevel, object);
 
   o_emit_pre_change_notify (toplevel, object);
 
@@ -450,8 +464,7 @@ void o_picture_modify(TOPLEVEL *toplevel, OBJECT *object,
   switch(whichone) {
     case PICTURE_UPPER_LEFT:
       object->picture->upper_x = x;
-      tmp = abs(object->picture->upper_x - object->picture->lower_x) / 
-	object->picture->ratio;
+      tmp = abs(object->picture->upper_x - object->picture->lower_x) / ratio;
       if (y < object->picture->lower_y) {
 	tmp = -tmp;
       }
@@ -460,8 +473,7 @@ void o_picture_modify(TOPLEVEL *toplevel, OBJECT *object,
 			
     case PICTURE_LOWER_LEFT:
       object->picture->upper_x = x;
-      tmp = abs(object->picture->upper_x - object->picture->lower_x) / 
-	object->picture->ratio;
+      tmp = abs(object->picture->upper_x - object->picture->lower_x) / ratio;
       if (y > object->picture->upper_y) {
 	tmp = -tmp;
       }
@@ -470,8 +482,7 @@ void o_picture_modify(TOPLEVEL *toplevel, OBJECT *object,
       
     case PICTURE_UPPER_RIGHT:
       object->picture->lower_x = x;
-      tmp = abs(object->picture->upper_x - object->picture->lower_x) / 
-	object->picture->ratio;
+      tmp = abs(object->picture->upper_x - object->picture->lower_x) / ratio;
       if (y < object->picture->lower_y) {
 	tmp = -tmp;
       }
@@ -480,8 +491,7 @@ void o_picture_modify(TOPLEVEL *toplevel, OBJECT *object,
       
     case PICTURE_LOWER_RIGHT:
       object->picture->lower_x = x;
-      tmp = abs(object->picture->upper_x - object->picture->lower_x) / 
-	object->picture->ratio;
+      tmp = abs(object->picture->upper_x - object->picture->lower_x) / ratio;
       if (y > object->picture->upper_y) {
 	tmp = -tmp;
       }
@@ -510,6 +520,37 @@ void o_picture_modify(TOPLEVEL *toplevel, OBJECT *object,
   o_emit_change_notify (toplevel, object);
 }
 
+/*! \brief Modify a picture object's coordinates.
+ * \par Function Description
+ * Modifies the coordinates of all four corners of a picture \a
+ * object.  The picture is adjusted to fit the rectangle enclosed by
+ * the points (\a x1, \a y1) and (\a x2, \a y2), and scaled as large
+ * as possible to still fit within that rectangle.
+ *
+ * \param [in]     toplevel current #TOPLEVEL.
+ * \param [in,out] object   picture #OBJECT to be modified.
+ * \param [in]     x1       x coordinate of first corner of box.
+ * \param [in]     y1       y coordinate of first corner of box.
+ * \param [in]     x2       x coordinate of second corner of box.
+ * \param [in]     y2       y coordinate of second corner of box.
+ */
+void
+o_picture_modify_all (TOPLEVEL *toplevel, OBJECT *object,
+                      int x1, int y1, int x2, int y2)
+{
+  o_emit_pre_change_notify (toplevel, object);
+
+  /* Normalise the requested rectangle. */
+  object->picture->lower_x = (x1 > x2) ? x1 : x2;
+  object->picture->lower_y = (y1 > y2) ? y2 : y1;
+  object->picture->upper_x = (x1 > x2) ? x2 : x1;
+  object->picture->upper_y = (y1 > y2) ? y1 : y2;
+
+  /* recalculate the world coords and bounds */
+  o_box_recalc(toplevel, object);
+  o_emit_change_notify (toplevel, object);
+}
+
 /*! \brief Rotate picture OBJECT using WORLD coordinates.
  *  \par Function Description 
  *  This function rotates the picture described by <B>*object</B> around
@@ -596,9 +637,17 @@ void o_picture_mirror_world(TOPLEVEL *toplevel,
   int newx1, newy1;
   int newx2, newy2;
 
-  
-  /* Set info in object */
-  object->picture->mirrored = (object->picture->mirrored ^ 1) & 1;
+  /* Set info in object. Sometimes it's necessary to change the
+   * rotation angle as well as the mirror flag. */
+  object->picture->mirrored = !object->picture->mirrored;
+  switch (object->picture->angle) {
+  case 90:
+    object->picture->angle = 270;
+    break;
+  case 270:
+    object->picture->angle = 90;
+    break;
+  }
 
   /* translate object to origin */
   object->picture->upper_x -= world_centerx;
@@ -684,9 +733,8 @@ OBJECT *o_picture_copy(TOPLEVEL *toplevel, OBJECT *object)
   picture->lower_y = object->picture->lower_y;
 
   if (object->picture->file_content != NULL) {
-    picture->file_content = g_malloc (object->picture->file_length);
-    memcpy (picture->file_content, object->picture->file_content,
-                                   object->picture->file_length);
+    picture->file_content = g_memdup (object->picture->file_content,
+                                      object->picture->file_length);
   } else {
     picture->file_content = NULL;
   }
@@ -698,8 +746,8 @@ OBJECT *o_picture_copy(TOPLEVEL *toplevel, OBJECT *object)
   picture->mirrored    = object->picture->mirrored;
   picture->embedded    = object->picture->embedded;
 
-  /* Copy the picture data */
-  picture->pixbuf = gdk_pixbuf_copy (object->picture->pixbuf);
+  /* Get the picture data */
+  picture->pixbuf = o_picture_get_pixbuf (toplevel, object);
 
   /* compute the bounding picture */
   o_picture_recalc(toplevel, new_node);
@@ -720,7 +768,8 @@ OBJECT *o_picture_copy(TOPLEVEL *toplevel, OBJECT *object)
  *  \note
  *  Caller must g_free returned guint8 array.
  */
-guint8 *o_picture_rgb_data(GdkPixbuf *image)
+static guint8 *
+o_picture_rgb_data(GdkPixbuf *image)
 {
   int width = gdk_pixbuf_get_width(image);
   int height = gdk_pixbuf_get_height(image);
@@ -759,7 +808,8 @@ guint8 *o_picture_rgb_data(GdkPixbuf *image)
  *  \note
  *  Caller must g_free returned guint8 array.
  */
-guint8 *o_picture_mask_data(GdkPixbuf *image)
+static guint8 *
+o_picture_mask_data(GdkPixbuf *image)
 {
   guint8 *pixels;
   guint8 *mask;
@@ -788,6 +838,10 @@ guint8 *o_picture_mask_data(GdkPixbuf *image)
  *  This function prints a picture object. The picture is defined by the
  *  coordinates of its upper left corner in (<B>x</B>,<B>y</B>) and its width
  *  and height given by the <B>width</B> and <B>height</B> parameters. 
+ *
+ *  If the picture object was unable to be loaded, prints a crossed
+ *  box of the same dimensions.
+ *
  *  The Postscript document is defined by the file pointer <B>fp</B>.
  *  Function based on the DIA source code (http://www.gnome.org/projects/dia)
  *  and licensed under the GNU GPL version 2.
@@ -805,7 +859,7 @@ void o_picture_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current,
 {
   int x1, y1, x, y;
   int height, width;
-  GdkPixbuf* image = o_current->picture->pixbuf;
+  GdkPixbuf* image = o_picture_get_pixbuf (toplevel, o_current);
   int img_width, img_height, img_rowstride;
   guint8 *rgb_data;
   guint8 *mask_data;
@@ -818,6 +872,22 @@ void o_picture_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current,
   x1 = o_current->picture->upper_x;
   y1 = o_current->picture->upper_y;
 
+  /* If the image failed to load, try to get hold of the fallback
+   * pixbuf. */
+  if (image == NULL) image = o_picture_get_fallback_pixbuf (toplevel);
+  /* If the image failed to load, draw a box in the default color with a
+   * cross in it. */
+  if (image == NULL) {
+    int line_width = (toplevel->line_style == THICK) ? LINE_WIDTH : 2;
+    o_box_print_solid (toplevel, fp, x1, y1, width, height,
+                       DEFAULT_COLOR, line_width, -1, -1, -1, -1);
+    o_line_print_solid (toplevel, fp, x1, y1, x1+width, y1+height,
+                        DEFAULT_COLOR, line_width, -1, -1, -1, -1);
+    o_line_print_solid (toplevel, fp, x1+width, y1, x1, y1+height,
+                        DEFAULT_COLOR, line_width, -1, -1, -1, -1);
+    return;
+  }
+
   img_width = gdk_pixbuf_get_width(image);
   img_rowstride = gdk_pixbuf_get_rowstride(image);
   img_height = gdk_pixbuf_get_height(image);
@@ -863,71 +933,46 @@ void o_picture_print(TOPLEVEL *toplevel, FILE *fp, OBJECT *o_current,
   fprintf(fp, "grestore\n");
   fprintf(fp, "\n");
    
+  g_object_unref (image);
   g_free(rgb_data);
   g_free(mask_data);
 }
 
 
 /*! \brief Embed the image file associated with a picture
- *
- *  \par Function Description
- *  This function reads and embeds image file associated with the picture.
+ * \par Function Description
+ * Verify that a picture has valid data associated with it, and if so,
+ * mark it to be embedded.
  *
  *  \param [in]     toplevel     The TOPLEVEL object.
  *  \param [in]     object       The picture OBJECT to embed
  */
 void o_picture_embed (TOPLEVEL *toplevel, OBJECT *object)
 {
-  GError *err = NULL;
-  GdkPixbuf *pixbuf;
-  gchar *filename;
+  const gchar *filename = o_picture_get_filename (toplevel, object);
+  gchar *basename;
 
-  /* Free any existing embedded data */
-  g_free (object->picture->file_content);
-  object->picture->file_content = NULL;
+  if (o_picture_is_embedded (toplevel, object)) return;
 
-  g_file_get_contents (object->picture->filename,
-                       &object->picture->file_content,
-                       &object->picture->file_length,
-                       &err);
-  if (err != NULL) {
-    s_log_message (_("Failed to load image from file [%s]: %s\n"),
-                   object->picture->filename, err->message);
-    g_error_free (err);
-    return;
-  }
-
-  object->picture->embedded = 1;
-
-  pixbuf = o_picture_pixbuf_from_buffer (object->picture->file_content,
-                                         object->picture->file_length,
-                                         &err);
-  if (err != NULL) {
-    s_log_message (_("Failed to load image from embedded data [%s]: %s\n"),
-                   object->picture->filename, err->message);
-    s_log_message (_("Falling back to file loading. Picture unembedded.\n"));
-    g_error_free (err);
+  if (object->picture->file_content == NULL) {
+    s_log_message (_("Picture [%s] has no image data.\n"), filename);
+    s_log_message (_("Falling back to file loading. Picture is still unembedded.\n"));
     object->picture->embedded = 0;
     return;
   }
 
-  /* Change to the new pixbuf loaded before we embedded. */
-  if (object->picture->pixbuf != NULL)
-    g_object_unref (object->picture->pixbuf);
-
-  object->picture->pixbuf = pixbuf;
+  object->picture->embedded = 1;
 
-  filename = g_path_get_basename(object->picture->filename);
-  s_log_message (_("Picture [%s] has been embedded\n"), filename);
-  g_free(filename);
+  basename = g_path_get_basename (filename);
+  s_log_message (_("Picture [%s] has been embedded\n"), basename);
+  g_free (basename);
 }
 
 
 /*! \brief Unembed a picture, reloading the image from disk
- *
- *  \par Function Description
- *  This function re-reads the image file associated with the picture, and
- *  discards the embeded copy of the file.
+ * \par Function Description
+ * Verify that the file associated with \a object exists on disk and
+ * is usable, and if so, reload the picture and mark it as unembedded.
  *
  *  \param [in]     toplevel     The TOPLEVEL object.
  *  \param [in]     object       The picture OBJECT to unembed
@@ -935,72 +980,26 @@ void o_picture_embed (TOPLEVEL *toplevel, OBJECT *object)
 void o_picture_unembed (TOPLEVEL *toplevel, OBJECT *object)
 {
   GError *err = NULL;
-  GdkPixbuf *pixbuf;
-  gchar *filename;
+  const gchar *filename = o_picture_get_filename (toplevel, object);
+  gchar *basename;
+
+  if (!o_picture_is_embedded (toplevel, object)) return;
+
+  o_picture_set_from_file (toplevel, object, filename, &err);
 
-  pixbuf = gdk_pixbuf_new_from_file (object->picture->filename, &err);
   if (err != NULL) {
     s_log_message (_("Failed to load image from file [%s]: %s\n"),
-                   object->picture->filename, err->message);
+                   filename, err->message);
+    s_log_message (_("Picture is still embedded.\n"));
     g_error_free (err);
     return;
   }
 
-  /* Change to the new pixbuf loaded from the file. */
-  if (object->picture->pixbuf != NULL)
-    g_object_unref(object->picture->pixbuf);
-
-  object->picture->pixbuf = pixbuf;
-
-  g_free (object->picture->file_content);
-  object->picture->file_content = NULL;
-  object->picture->file_length = 0;
   object->picture->embedded = 0;
 
-  filename = g_path_get_basename(object->picture->filename);
-  s_log_message (_("Picture [%s] has been unembedded\n"), filename);
-  g_free(filename);
-}
-
-
-/*! \brief Load a GdkPixbuf from a memory buffer
- *
- *  \par Function Description
- *  This function loads a GdkPixbuf from a memory buffer. The pixbuf
- *  returned already has a reference taken out on the callers behalf.
- *
- *  \param [in]   file_content  The memory buffer containing the image data.
- *  \param [in]   file_length   The size of the image data
- *  \param [out]  err           GError** pointer to return any error messages.
- *  \return  A GdkPixbuf loaded from the image data, or NULL on error.
- */
-
-GdkPixbuf *o_picture_pixbuf_from_buffer (gchar *file_content,
-                                         gsize file_length,
-                                         GError **err)
-{
-  GdkPixbufLoader *loader;
-  GdkPixbuf *pixbuf;
-
-  loader = gdk_pixbuf_loader_new();
-
-  gdk_pixbuf_loader_write (loader, (guchar *)file_content,
-                                             file_length, err);
-  if (err != NULL && *err != NULL)
-    return NULL;
-
-  gdk_pixbuf_loader_close (loader, err);
-  if (err != NULL && *err != NULL)
-    return NULL;
-
-  pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
-
-  if (pixbuf != NULL)
-    g_object_ref (pixbuf);
-
-  g_object_unref (loader);
-
-  return pixbuf;
+  basename = g_path_get_basename(filename);
+  s_log_message (_("Picture [%s] has been unembedded\n"), basename);
+  g_free(basename);
 }
 
 /*! \brief Calculates the distance between the given point and the closest
@@ -1037,3 +1036,214 @@ double o_picture_shortest_distance (OBJECT *object, int x, int y,
   return sqrt ((dx * dx) + (dy * dy));
 }
 
+/*! \brief Test whether a picture object is embedded.
+ * \par Function Description
+ * Returns TRUE if the picture \a object will have its data embedded
+ * in a schematic or symbol file; returns FALSE if its data will be
+ * obtained from a separate file.
+ *
+ * \param toplevel  The current #TOPLEVEL.
+ * \param object    The picture #OBJECT to inspect.
+ * \return TRUE if \a object is embedded.
+ */
+gboolean
+o_picture_is_embedded (TOPLEVEL *toplevel, OBJECT *object)
+{
+  g_return_val_if_fail (object != NULL, FALSE);
+  g_return_val_if_fail (object->picture != NULL, FALSE);
+
+  return object->picture->embedded;
+}
+
+/*! \brief Get a pixel buffer for a picture object.
+ * \par Function Description
+ * Returns a #GdkPixbuf for the picture object \a object, or NULL if
+ * the picture could not be loaded.
+ *
+ * The returned value should have its reference count decremented with
+ * g_object_unref() when no longer needed.
+ *
+ * \param toplevel  The current #TOPLEVEL.
+ * \param object    The picture #OBJECT to inspect.
+ * \return A #GdkPixbuf for the picture.
+ */
+GdkPixbuf *
+o_picture_get_pixbuf (TOPLEVEL *toplevel, OBJECT *object)
+{
+  g_return_val_if_fail (object != NULL, NULL);
+  g_return_val_if_fail (object->picture != NULL, NULL);
+
+  if (object->picture->pixbuf != NULL) {
+    return g_object_ref (object->picture->pixbuf);
+  } else {
+    return NULL;
+  }
+}
+
+/*! \brief Get the raw image data from a picture object.
+ * \par Function Description
+ * Returns the raw image file data underlying the picture \a object,
+ * or NULL if the picture could not be loaded.
+ *
+ * \param toplevel  The current #TOPLEVEL.
+ * \param object    The picture #OBJECT to inspect.
+ * \param len       Location to store buffer length.
+ * \return A read-only buffer of raw image data.
+ */
+const char *
+o_picture_get_data (TOPLEVEL *toplevel, OBJECT *object,
+                    size_t *len)
+{
+  g_return_val_if_fail (object != NULL, NULL);
+  g_return_val_if_fail (object->picture != NULL, NULL);
+
+  *len = object->picture->file_length;
+  return object->picture->file_content;
+}
+
+/*! \brief Set a picture object's contents from a buffer.
+ * \par Function Description
+ * Sets the contents of the picture \a object by reading image data
+ * from a buffer.  The buffer should be in on-disk format.
+ *
+ * \param toplevel The current #TOPLEVEL.
+ * \param object   The picture #OBJECT to modify.
+ * \param filename The new filename for the picture.
+ * \param data     The new image data buffer.
+ * \param len      The size of the data buffer.
+ * \param error    Location to return error information.
+ * \return TRUE on success, FALSE on failure.
+ */
+gboolean
+o_picture_set_from_buffer (TOPLEVEL *toplevel, OBJECT *object,
+                           const gchar *filename,
+                           const gchar *data, size_t len,
+                           GError **error)
+{
+  GdkPixbuf *pixbuf;
+  GInputStream *stream;
+  gchar *tmp;
+
+  g_return_val_if_fail (toplevel != NULL, FALSE);
+  g_return_val_if_fail (object != NULL, FALSE);
+  g_return_val_if_fail (object->picture != NULL, FALSE);
+  g_return_val_if_fail (data != NULL, FALSE);
+
+  /* Check that we can actually load the data before making any
+   * changes to the object. */
+  stream = G_INPUT_STREAM (g_memory_input_stream_new_from_data (data, len, NULL));
+  pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, error);
+  g_object_unref (stream);
+  if (pixbuf == NULL) return FALSE;
+
+  o_emit_pre_change_notify (toplevel, object);
+
+  if (object->picture->pixbuf != NULL) {
+    g_object_unref (object->picture->pixbuf);
+  }
+  object->picture->pixbuf = pixbuf;
+
+  object->picture->ratio = ((double) gdk_pixbuf_get_width(pixbuf) /
+                            gdk_pixbuf_get_height(pixbuf));
+
+  tmp = g_strdup (filename);
+  g_free (object->picture->filename);
+  object->picture->filename = tmp;
+
+  gchar *buf = g_realloc (object->picture->file_content,
+                          len);
+  /* It's possible that these buffers might overlap, because the
+   * library user hates us. */
+  memmove (buf, data, len);
+  object->picture->file_content = buf;
+  object->picture->file_length = len;
+
+  o_emit_change_notify (toplevel, object);
+  return TRUE;
+}
+
+/*! \brief Set a picture object's contents from a file.
+ * \par Function Description
+ * Sets the contents of the picture \a object by reading image data
+ * from a file.
+ *
+ * \param toplevel The current #TOPLEVEL.
+ * \param object   The picture #OBJECT to modify.
+ * \param filename The filename to load image data from.
+ * \param error    Location to return error information.
+ * \return TRUE on success, FALSE on failure.
+ */
+gboolean
+o_picture_set_from_file (TOPLEVEL *toplevel, OBJECT *object,
+                         const gchar *filename,
+                         GError **error)
+{
+  gchar *buf;
+  size_t len;
+  gboolean status;
+
+  g_return_val_if_fail (filename != NULL, FALSE);
+
+  if (!g_file_get_contents (filename, &buf, &len, error)) {
+    return FALSE;
+  }
+
+  status = o_picture_set_from_buffer (toplevel, object, filename,
+                                      buf, len, error);
+  g_free (buf);
+  return status;
+}
+
+/*! \brief Get a picture's corresponding filename.
+ * \par Function Description
+ * Returns the filename associated with the picture \a object.
+ *
+ * \param toplevel The current #TOPLEVEL.
+ * \param object   The picture #OBJECT to inspect.
+ * \return the filename associated with \a object.
+ */
+const gchar *
+o_picture_get_filename (TOPLEVEL *toplevel, OBJECT *object)
+{
+  g_return_val_if_fail (object != NULL, NULL);
+  g_return_val_if_fail (object->picture != NULL, NULL);
+
+  return object->picture->filename;
+}
+
+/*! \brief Get fallback pixbuf for displaying pictures.
+ * \par Function Description
+ * Returns a pixbuf containing the fallback image to be used if a
+ * picture object fails to load.  The returned pixbuf should be freed
+ * with g_object_unref() when no longer needed.
+ *
+ * \return a #GdkPixbuf containing a warning image.
+ */
+GdkPixbuf *
+o_picture_get_fallback_pixbuf (TOPLEVEL *toplevel)
+{
+  static GdkPixbuf *pixbuf = NULL;
+  static gboolean failed = FALSE;
+
+  if (pixbuf == NULL && !failed) {
+    gchar *filename;
+    GError *error = NULL;
+
+    filename = g_build_filename (toplevel->bitmap_directory,
+                                 "gschem-warning.png", NULL);
+    pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
+
+    if (pixbuf == NULL) {
+      g_warning ( _("Failed to load fallback image %s: %s.\n"),
+                      filename, error->message);
+      g_error_free (error);
+      failed = TRUE;
+    }
+    g_free (filename);
+  }
+
+  if (failed) return NULL;
+
+  g_assert (GDK_IS_PIXBUF (pixbuf));
+  return g_object_ref (pixbuf);
+}

commit e85e8c5843f23432cb03d4dd8c95fb34753f7801
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    libgeda: Add missing pre change notify to o_box_modify_all().

diff --git a/libgeda/src/o_box_basic.c b/libgeda/src/o_box_basic.c
index 8a0d165..144d89c 100644
--- a/libgeda/src/o_box_basic.c
+++ b/libgeda/src/o_box_basic.c
@@ -151,6 +151,8 @@ void
 o_box_modify_all (TOPLEVEL *toplevel, OBJECT *object,
                   int x1, int y1, int x2, int y2)
 {
+  o_emit_pre_change_notify (toplevel, object);
+
   object->box->lower_x = (x1 > x2) ? x1 : x2;
   object->box->lower_y = (y1 > y2) ? y2 : y1;
 

commit 121bd353ac7c4e9de0f94c4b7378945cf33222c6
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    gschem: Fix a crash when cancelling out of an action.
    
    In some cases, the new keybinding code could cause a crash when
    cancelling out of an action with the right mouse button.  This was
    because there was an call to scm_c_eval_string() which could sometimes
    be called in a context where Guile exceptions weren't caught, and
    which hadn't been updated to reflect the changes to the keybinding
    system.

diff --git a/gschem/include/prototype.h b/gschem/include/prototype.h
index 4795ef3..1ce0283 100644
--- a/gschem/include/prototype.h
+++ b/gschem/include/prototype.h
@@ -37,6 +37,7 @@ void g_run_hook_object (const char *name, OBJECT *obj);
 void g_run_hook_object_list (const char *name, GList *obj_lst);
 void g_run_hook_page (const char *name, PAGE *page);
 /* g_keys.c */
+void g_keys_reset (GSCHEM_TOPLEVEL *w_current);
 int g_keys_execute(GSCHEM_TOPLEVEL *w_current, GdkEventKey *event);
 GtkListStore *g_keys_to_list_store (void);
 SCM g_keys_file_new(SCM rest);
diff --git a/gschem/scheme/gschem.scm b/gschem/scheme/gschem.scm
index ba0b587..6593886 100644
--- a/gschem/scheme/gschem.scm
+++ b/gschem/scheme/gschem.scm
@@ -41,6 +41,9 @@
 (define (press-key key)
   (eval-pressed-key current-keymap key))
 
+;; Function for resetting current key sequence
+(define (reset-keys) (set! current-keys '()) #f)
+
 ;; Does the work of evaluating a key.  Adds the key to the current key
 ;; sequence, then looks up the key sequence in the current keymap.  If
 ;; the key sequence resolves to an action, calls the action.  If the
@@ -49,9 +52,6 @@
 ;; symbol; otherwise, returns #f.  If the key is #f, clears the
 ;; current key sequence.
 (define (eval-pressed-key keymap key)
-  ;; Function for resetting current key sequence
-  (define (reset-keys) (set! current-keys '()) #f)
-
   (if key
       (begin
         ;; Add key to current key sequence
diff --git a/gschem/src/g_keys.c b/gschem/src/g_keys.c
index 6338f48..696573d 100644
--- a/gschem/src/g_keys.c
+++ b/gschem/src/g_keys.c
@@ -457,6 +457,7 @@ g_key_free (SCM key) {
   return 0;
 }
 
+SCM_SYMBOL (reset_keys_sym, "reset-keys");
 SCM_SYMBOL (press_key_sym, "press-key");
 SCM_SYMBOL (prefix_sym, "prefix");
 
@@ -486,6 +487,30 @@ static gboolean clear_keyaccel_string(gpointer data)
   return FALSE;
 }
 
+/*! \brief Reset the current key sequence.
+ * \par Function Description
+ * If any prefix keys are stored in the current key sequence, clears
+ * them.
+ *
+ * \param w_current  The active #GSCHEM_TOPLEVEL context.
+ */
+void
+g_keys_reset (GSCHEM_TOPLEVEL *w_current)
+{
+  SCM s_expr = scm_list_1 (reset_keys_sym);
+
+  /* Reset the status bar */
+  g_free (w_current->keyaccel_string);
+  w_current->keyaccel_string = NULL;
+  i_show_state(w_current, NULL);
+
+  /* Reset the Scheme keybinding state */
+  scm_dynwind_begin (0);
+  g_dynwind_window (w_current);
+  g_scm_eval_protected (s_expr, scm_interaction_environment ());
+  scm_dynwind_end ();
+}
+
 /*! \brief Evaluate a user keystroke.
  * \par Function Description
  * Evaluates the key combination specified by \a event using the
@@ -537,39 +562,33 @@ g_keys_execute(GSCHEM_TOPLEVEL *w_current, GdkEventKey *event)
 
   /* Validate the key -- there are some keystrokes we mask out. */
   if (!g_key_is_valid (key, mods)) {
-    return 0;
+    return FALSE;
   }
 
   /* Create Scheme key value */
   /* FIXME Escape as cancel key shouldn't be hardcoded in. */
   if (key == GDK_Escape) {
-    s_key = SCM_BOOL_F;
-  } else {
-    s_key = g_make_key (key, mods);
+    g_keys_reset (w_current);
+    return FALSE;
   }
 
+  s_key = g_make_key (key, mods);
+
   /* Update key hint string for status bar. */
-  if (s_key == SCM_BOOL_F) {
-    /* Cancelled key sequence, so clear hint string */
+  gchar *keystr = gtk_accelerator_get_label (key, mods);
+
+  /* If no current hint string, or the hint string is going to be
+   * cleared anyway, use key string directly */
+  if ((w_current->keyaccel_string == NULL) ||
+      w_current->keyaccel_string_source_id) {
     g_free (w_current->keyaccel_string);
-    w_current->keyaccel_string = NULL;
+    w_current->keyaccel_string = keystr;
 
   } else {
-    gchar *keystr = gtk_accelerator_get_label (key, mods);
-
-    /* If no current hint string, or the hint string is going to be
-     * cleared anyway, use key string directly */
-    if ((w_current->keyaccel_string == NULL) ||
-        w_current->keyaccel_string_source_id) {
-      g_free (w_current->keyaccel_string);
-      w_current->keyaccel_string = keystr;
-
-    } else {
-      gchar *p = w_current->keyaccel_string;
-      w_current->keyaccel_string = g_strconcat (p, " ", keystr, NULL);
-      g_free (p);
-      g_free (keystr);
-    }
+    gchar *p = w_current->keyaccel_string;
+    w_current->keyaccel_string = g_strconcat (p, " ", keystr, NULL);
+    g_free (p);
+    g_free (keystr);
   }
 
   /* Update status bar */
diff --git a/gschem/src/i_callbacks.c b/gschem/src/i_callbacks.c
index f37e68e..7546b00 100644
--- a/gschem/src/i_callbacks.c
+++ b/gschem/src/i_callbacks.c
@@ -3529,7 +3529,7 @@ DEFINE_I_CALLBACK(cancel)
   i_update_toolbar(w_current);
 
   /* clear the key guile command-sequence */
-  scm_c_eval_string ("(set! current-command-sequence '())");
+  g_keys_reset (w_current);
 
   if (w_current->inside_action) { 
      o_invalidate_all (w_current);

commit 32ca3b25355ca4bef14ed3a2d15277367c32fead
Author: Peter TB Brett <peter@xxxxxxxxxxxxx>
Commit: Peter TB Brett <peter@xxxxxxxxxxxxx>

    scheme-api: Stop show-uri from leaking a GError on failure.

diff --git a/gschem/src/g_util.c b/gschem/src/g_util.c
index f96ada3..0eecfab 100644
--- a/gschem/src/g_util.c
+++ b/gschem/src/g_util.c
@@ -50,9 +50,13 @@ SCM_DEFINE (show_uri, "%show-uri", 1, 0, 0, (SCM uri_s),
   GError *err = NULL;
 
   if (!x_show_uri (w_current, uri, &err)) {
+    scm_dynwind_begin (0);
+    scm_dynwind_unwind_handler ((void (*)(void *)) g_error_free,
+                                err, SCM_F_WIND_EXPLICITLY);
     scm_misc_error (s_show_uri, _("Could not launch URI ~S: ~A"),
                     scm_list_2 (uri_s,
                                 scm_from_utf8_string (err->message)));
+    scm_dynwind_end ();
   }
   return SCM_UNDEFINED;
 }




_______________________________________________
geda-cvs mailing list
geda-cvs@xxxxxxxxxxxxxx
http://www.seul.org/cgi-bin/mailman/listinfo/geda-cvs