tibbs / rpms / xournal

Forked from rpms/xournal 6 years ago
Clone
Blob Blame History Raw
# This is a patch for xournal-0.4.5 to update it to xournal
# 
# To apply this patch:
# STEP 1: Chdir to the source directory.
# STEP 2: Run the 'applypatch' program with this patch file as input.
#
# If you do not have 'applypatch', it is part of the 'makepatch' package
# that you can fetch from the Comprehensive Perl Archive Network:
# http://www.perl.com/CPAN/authors/Johan_Vromans/makepatch-x.y.tar.gz
# In the above URL, 'x' should be 2 or higher.
#
# To apply this patch without the use of 'applypatch':
# STEP 1: Chdir to the source directory.
# If you have a decent Bourne-type shell:
# STEP 2: Run the shell with this file as input.
# If you don't have such a shell, you may need to manually create
# the files as shown below.
# STEP 3: Run the 'patch' program with this file as input.
#
# These are the commands needed to create/delete files/directories:
#
touch './README.image'
chmod 0644 './README.image'
touch './src/xo-clipboard.c'
chmod 0644 './src/xo-clipboard.c'
touch './src/xo-clipboard.h'
chmod 0644 './src/xo-clipboard.h'
touch './src/xo-image.c'
chmod 0644 './src/xo-image.c'
touch './src/xo-image.h'
chmod 0644 './src/xo-image.h'
#
# This command terminates the shell and need not be executed manually.
exit
#
#### End of Preamble ####

#### Patch data follows ####
diff -c /dev/null 'xournal/README.image'
Index: ./README.image
*** ./README.image	Thu Jan  1 12:00:00 1970
--- ./README.image	Thu Apr 15 17:16:44 2010
***************
*** 0 ****
--- 1,19 ----
+ This paste image patch is based on Victor Saase's insert image patch,
+ with grateful thanks to Victor for making a good start.
+ 
+ This patch is to be applied to a vanilla xournal-0.4.5.
+ 
+ This patch therefore contains Victor's changes, and also:
+ 
+ + images are now stored in the journal file, inline in the XML, as 
+   base64 encoded PNGs.
+ + images can be pasted in from the clipboard
+ + copy and paste of images works within the application
+ + export of image with PDF now works
+ 
+ I also fixed this bug:
+ 
+ + free pixbufs using g_object_unref not g_free.
+ 
+ 
+ Simon Guest 14/4/10
diff -c 'xournal-0.4.5/src/Makefile.am' 'xournal/src/Makefile.am'
Index: ./src/Makefile.am
*** ./src/Makefile.am	Tue Sep 22 03:24:32 2009
--- ./src/Makefile.am	Thu Apr 15 17:22:24 2010
***************
*** 12,17 ****
--- 12,19 ----
  xournal_SOURCES = \
  	main.c xournal.h \
  	xo-misc.c xo-misc.h \
+ 	xo-clipboard.c xo-clipboard.h \
+ 	xo-image.c xo-image.h \
  	xo-file.c xo-file.h \
  	xo-paint.c xo-paint.h \
  	xo-print.c xo-print.h \
diff -c 'xournal-0.4.5/src/Makefile.in' 'xournal/src/Makefile.in'
Index: ./src/Makefile.in
*** ./src/Makefile.in	Fri Oct  2 19:42:14 2009
--- ./src/Makefile.in	Thu Apr 15 17:27:17 2010
***************
*** 1,4 ****
! # Makefile.in generated by automake 1.11 from Makefile.am.
  # @configure_input@
  
  # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
--- 1,4 ----
! # Makefile.in generated by automake 1.11.1 from Makefile.am.
  # @configure_input@
  
  # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
***************
*** 46,54 ****
  am__installdirs = "$(DESTDIR)$(bindir)"
  PROGRAMS = $(bin_PROGRAMS)
  am_xournal_OBJECTS = main.$(OBJEXT) xo-misc.$(OBJEXT) \
! 	xo-file.$(OBJEXT) xo-paint.$(OBJEXT) xo-print.$(OBJEXT) \
! 	xo-support.$(OBJEXT) xo-interface.$(OBJEXT) \
! 	xo-callbacks.$(OBJEXT) xo-shapes.$(OBJEXT)
  xournal_OBJECTS = $(am_xournal_OBJECTS)
  am__DEPENDENCIES_1 =
  xournal_DEPENDENCIES = ttsubset/libttsubset.a $(am__DEPENDENCIES_1)
--- 46,55 ----
  am__installdirs = "$(DESTDIR)$(bindir)"
  PROGRAMS = $(bin_PROGRAMS)
  am_xournal_OBJECTS = main.$(OBJEXT) xo-misc.$(OBJEXT) \
! 	xo-clipboard.$(OBJEXT) xo-image.$(OBJEXT) xo-file.$(OBJEXT) \
! 	xo-paint.$(OBJEXT) xo-print.$(OBJEXT) xo-support.$(OBJEXT) \
! 	xo-interface.$(OBJEXT) xo-callbacks.$(OBJEXT) \
! 	xo-shapes.$(OBJEXT)
  xournal_OBJECTS = $(am_xournal_OBJECTS)
  am__DEPENDENCIES_1 =
  xournal_DEPENDENCIES = ttsubset/libttsubset.a $(am__DEPENDENCIES_1)
***************
*** 154,159 ****
--- 155,161 ----
  PACKAGE_NAME = @PACKAGE_NAME@
  PACKAGE_STRING = @PACKAGE_STRING@
  PACKAGE_TARNAME = @PACKAGE_TARNAME@
+ PACKAGE_URL = @PACKAGE_URL@
  PACKAGE_VERSION = @PACKAGE_VERSION@
  PATH_SEPARATOR = @PATH_SEPARATOR@
  PKG_CONFIG = @PKG_CONFIG@
***************
*** 219,224 ****
--- 221,228 ----
  xournal_SOURCES = \
  	main.c xournal.h \
  	xo-misc.c xo-misc.h \
+ 	xo-clipboard.c xo-clipboard.h \
+ 	xo-image.c xo-image.h \
  	xo-file.c xo-file.h \
  	xo-paint.c xo-paint.h \
  	xo-print.c xo-print.h \
***************
*** 311,317 ****
--- 315,323 ----
  
  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xo-callbacks.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xo-clipboard.Po@am__quote@
  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xo-file.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xo-image.Po@am__quote@
  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xo-interface.Po@am__quote@
  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xo-misc.Po@am__quote@
  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xo-paint.Po@am__quote@
***************
*** 340,346 ****
  #     (which will cause the Makefiles to be regenerated when you run `make');
  # (2) otherwise, pass the desired values on the `make' command line.
  $(RECURSIVE_TARGETS):
! 	@failcom='exit 1'; \
  	for f in x $$MAKEFLAGS; do \
  	  case $$f in \
  	    *=* | --[!k]*);; \
--- 346,352 ----
  #     (which will cause the Makefiles to be regenerated when you run `make');
  # (2) otherwise, pass the desired values on the `make' command line.
  $(RECURSIVE_TARGETS):
! 	@fail= failcom='exit 1'; \
  	for f in x $$MAKEFLAGS; do \
  	  case $$f in \
  	    *=* | --[!k]*);; \
***************
*** 365,371 ****
  	fi; test -z "$$fail"
  
  $(RECURSIVE_CLEAN_TARGETS):
! 	@failcom='exit 1'; \
  	for f in x $$MAKEFLAGS; do \
  	  case $$f in \
  	    *=* | --[!k]*);; \
--- 371,377 ----
  	fi; test -z "$$fail"
  
  $(RECURSIVE_CLEAN_TARGETS):
! 	@fail= failcom='exit 1'; \
  	for f in x $$MAKEFLAGS; do \
  	  case $$f in \
  	    *=* | --[!k]*);; \
diff -c 'xournal-0.4.5/src/TODO' 'xournal/src/TODO'
Index: ./src/TODO
*** ./src/TODO	Sat Oct  3 12:20:35 2009
--- ./src/TODO	Fri May 14 17:59:39 2010
***************
*** 138,145 ****
  - copy/paste of an entire page (beware if PDF bg is not compatible!)
  - rewrite printing using GtkPrint + Cairo as GnomePrint replacement
     (keep GnomePrint option for compatibility with GTK+ <2.10)
- - insert images (screen capture or from file or from clipboard), 
-   not as full-page backgrounds (new ITEM type)
  
  - convert to/from Jarnal format; to/from MS Journal format???
  - export as SVG, as bitmap (use Cairo for this)
--- 138,143 ----
diff -c 'xournal-0.4.5/src/main.c' 'xournal/src/main.c'
Index: ./src/main.c
*** ./src/main.c	Mon Sep 28 11:08:34 2009
--- ./src/main.c	Sun Jun 27 16:22:44 2010
***************
*** 287,292 ****
--- 287,295 ----
    g_free(tmpfn);
    set_cursor_busy(FALSE);
    if (!success) {
+ 	  #ifdef IMAGE_DEBUG
+ 	  printf("error opening file '%s'\n",argv[1]);
+ 	  #endif
      w = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT,
         GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Error opening file '%s'"), argv[1]);
      gtk_dialog_run(GTK_DIALOG(w));
diff -c 'xournal-0.4.5/src/xo-callbacks.c' 'xournal/src/xo-callbacks.c'
Index: ./src/xo-callbacks.c
*** ./src/xo-callbacks.c	Tue Sep 29 12:42:49 2009
--- ./src/xo-callbacks.c	Thu Jun 24 20:32:09 2010
***************
*** 452,458 ****
    if (undo == NULL) return; // nothing to undo!
    reset_selection(); // safer
    reset_recognizer(); // safer
!   if (undo->type == ITEM_STROKE || undo->type == ITEM_TEXT) {
      // we're keeping the stroke info, but deleting the canvas item
      gtk_object_destroy(GTK_OBJECT(undo->item->canvas_item));
      undo->item->canvas_item = NULL;
--- 452,458 ----
    if (undo == NULL) return; // nothing to undo!
    reset_selection(); // safer
    reset_recognizer(); // safer
!   if (undo->type == ITEM_STROKE || undo->type == ITEM_TEXT || undo->type == ITEM_IMAGE) {
      // we're keeping the stroke info, but deleting the canvas item
      gtk_object_destroy(GTK_OBJECT(undo->item->canvas_item));
      undo->item->canvas_item = NULL;
***************
*** 666,672 ****
    if (redo == NULL) return; // nothing to redo!
    reset_selection(); // safer
    reset_recognizer(); // safer
!   if (redo->type == ITEM_STROKE || redo->type == ITEM_TEXT) {
      // re-create the canvas_item
      make_canvas_item_one(redo->layer->group, redo->item);
      // reinsert the item on its layer
--- 666,672 ----
    if (redo == NULL) return; // nothing to redo!
    reset_selection(); // safer
    reset_recognizer(); // safer
!   if (redo->type == ITEM_STROKE || redo->type == ITEM_TEXT || redo->type == ITEM_IMAGE) {
      // re-create the canvas_item
      make_canvas_item_one(redo->layer->group, redo->item);
      // reinsert the item on its layer
***************
*** 824,829 ****
--- 824,835 ----
        if (it->type == ITEM_TEXT && it->canvas_item != NULL)
          gnome_canvas_item_set(it->canvas_item, 
            "fill-color-rgba", it->brush.color_rgba, NULL);
+       if (it->type == ITEM_IMAGE && it->canvas_item != NULL) {
+         // remark: a variable-width item might have lost its variable-width
+         group = (GnomeCanvasGroup *) it->canvas_item->parent;
+         gtk_object_destroy(GTK_OBJECT(it->canvas_item));
+         make_canvas_item_one(group, it);
+       }
      }
    }
    else if (redo->type == ITEM_TEXT_EDIT) {
***************
*** 946,951 ****
--- 952,958 ----
    gnome_canvas_set_pixels_per_unit(canvas, ui.zoom);
    rescale_text_items();
    rescale_bg_pixmaps();
+   rescale_images();
  }
  
  
***************
*** 958,963 ****
--- 965,971 ----
    gnome_canvas_set_pixels_per_unit(canvas, ui.zoom);
    rescale_text_items();
    rescale_bg_pixmaps();
+   rescale_images();
  }
  
  
***************
*** 969,974 ****
--- 977,983 ----
    gnome_canvas_set_pixels_per_unit(canvas, ui.zoom);
    rescale_text_items();
    rescale_bg_pixmaps();
+   rescale_images();
  }
  
  
***************
*** 980,985 ****
--- 989,995 ----
    gnome_canvas_set_pixels_per_unit(canvas, ui.zoom);
    rescale_text_items();
    rescale_bg_pixmaps();
+   rescale_images();
  }
  
  
***************
*** 1539,1544 ****
--- 1549,1555 ----
      gnome_canvas_set_pixels_per_unit(canvas, ui.zoom);
      rescale_text_items();
      rescale_bg_pixmaps();
+     rescale_images();
    }
    do_switch_page(ui.pageno, TRUE, TRUE);
  }
***************
*** 1585,1590 ****
--- 1596,1602 ----
      gnome_canvas_set_pixels_per_unit(canvas, ui.zoom);
      rescale_text_items();
      rescale_bg_pixmaps();
+     rescale_images();
    }
    do_switch_page(ui.pageno, TRUE, TRUE);
  }
***************
*** 1747,1752 ****
--- 1759,1790 ----
    update_cursor();
  }
  
+ void
+ on_toolsImage_activate                  (GtkMenuItem     *menuitem,
+                                         gpointer         user_data)
+ {
+   if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_MENU_ITEM) {
+     if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
+       return;
+   } else {
+     if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem)))
+       return;
+   }
+   
+   if (ui.cur_mapping != 0 && !ui.button_switch_mapping) return; // not user-generated
+   if (ui.toolno[ui.cur_mapping] == TOOL_IMAGE) return;
+   
+   ui.cur_mapping = 0; // don't use switch_mapping() (refreshes buttons too soon)
+   reset_selection();
+   ui.toolno[ui.cur_mapping] = TOOL_IMAGE;
+   ui.cur_brush = &(ui.brushes[ui.cur_mapping][TOOL_PEN]);
+   update_mapping_linkings(-1);
+   update_tool_buttons();
+   update_tool_menu();
+   update_color_menu();
+   update_cursor();
+ }
+ 
  
  void
  on_toolsSelectRegion_activate          (GtkMenuItem     *menuitem,
***************
*** 2321,2328 ****
                                          gpointer         user_data)
  {
    double pt[2];
-   gboolean page_change;
-   struct Page *tmppage;
    GtkWidget *dialog;
    int mapping;
    gboolean is_core;
--- 2359,2364 ----
***************
*** 2407,2430 ****
    else mapping = event->button-1;
  
    // check whether we're in a page
-   page_change = FALSE;
-   tmppage = ui.cur_page;
    get_pointer_coords((GdkEvent *)event, pt);
!   while (ui.view_continuous && (pt[1] < - VIEW_CONTINUOUS_SKIP)) {
!     if (ui.pageno == 0) break;
!     page_change = TRUE;
!     ui.pageno--;
!     tmppage = g_list_nth_data(journal.pages, ui.pageno);
!     pt[1] += tmppage->height + VIEW_CONTINUOUS_SKIP;
!   }
!   while (ui.view_continuous && (pt[1] > tmppage->height + VIEW_CONTINUOUS_SKIP)) {
!     if (ui.pageno == journal.npages-1) break;
!     pt[1] -= tmppage->height + VIEW_CONTINUOUS_SKIP;
!     page_change = TRUE;
!     ui.pageno++;
!     tmppage = g_list_nth_data(journal.pages, ui.pageno);
!   }
!   if (page_change) do_switch_page(ui.pageno, FALSE, FALSE);
    
    // can't paint on the background...
  
--- 2443,2450 ----
    else mapping = event->button-1;
  
    // check whether we're in a page
    get_pointer_coords((GdkEvent *)event, pt);
!   set_current_page(pt);
    
    // can't paint on the background...
  
***************
*** 2487,2492 ****
--- 2507,2515 ----
    else if (ui.toolno[mapping] == TOOL_TEXT) {
      start_text((GdkEvent *)event, NULL);
    }
+   else if (ui.toolno[mapping] == TOOL_IMAGE) {
+     insert_image((GdkEvent *)event, NULL);
+   }
    return FALSE;
  }
  
***************
*** 2665,2671 ****
       or if there's a selection (then we might want to change the mouse
       cursor to indicate the possibility of resizing) */  
    if (ui.cur_item_type == ITEM_NONE && ui.selection==NULL) return FALSE;
!   if (ui.cur_item_type == ITEM_TEXT) return FALSE;
  
    is_core = (event->device == gdk_device_get_core_pointer());
    if (!ui.use_xinput && !is_core) return FALSE;
--- 2688,2694 ----
       or if there's a selection (then we might want to change the mouse
       cursor to indicate the possibility of resizing) */  
    if (ui.cur_item_type == ITEM_NONE && ui.selection==NULL) return FALSE;
!   if (ui.cur_item_type == ITEM_TEXT || ui.cur_item_type == ITEM_IMAGE) return FALSE;
  
    is_core = (event->device == gdk_device_get_core_pointer());
    if (!ui.use_xinput && !is_core) return FALSE;
***************
*** 3340,3345 ****
--- 3363,3369 ----
        gnome_canvas_set_pixels_per_unit(canvas, ui.zoom);
        rescale_text_items();
        rescale_bg_pixmaps();
+       rescale_images();
      }
    } while (response == GTK_RESPONSE_APPLY);
    
diff -c 'xournal-0.4.5/src/xo-callbacks.h' 'xournal/src/xo-callbacks.h'
Index: ./src/xo-callbacks.h
*** ./src/xo-callbacks.h	Tue Sep 29 12:43:34 2009
--- ./src/xo-callbacks.h	Mon Mar 22 11:39:25 2010
***************
*** 211,216 ****
--- 211,220 ----
  void
  on_toolsText_activate                  (GtkMenuItem     *menuitem,
                                          gpointer         user_data);
+ 					
+ void
+ on_toolsImage_activate                  (GtkMenuItem     *menuitem,
+                                         gpointer         user_data);
  
  void
  on_toolsSelectRegion_activate          (GtkMenuItem     *menuitem,
diff -c /dev/null 'xournal/src/xo-clipboard.c'
Index: ./src/xo-clipboard.c
*** ./src/xo-clipboard.c	Thu Jan  1 12:00:00 1970
--- ./src/xo-clipboard.c	Thu Jul 29 19:56:43 2010
***************
*** 0 ****
--- 1,304 ----
+ #ifdef HAVE_CONFIG_H
+ #  include <config.h>
+ #endif
+ 
+ #include <string.h>
+ #include <gtk/gtk.h>
+ 
+ #include "xournal.h"
+ #include "xo-callbacks.h"
+ #include "xo-interface.h"
+ #include "xo-support.h"
+ #include "xo-misc.h"
+ #include "xo-paint.h"
+ #include "xo-image.h"
+ 
+ 
+ void callback_clipboard_get(GtkClipboard *clipboard,
+                             GtkSelectionData *selection_data,
+                             guint info, gpointer user_data)
+ {
+   int length;
+   
+   g_memmove(&length, user_data, sizeof(int));
+   gtk_selection_data_set(selection_data,
+      gdk_atom_intern("_XOURNAL", FALSE), 8, user_data, length);
+ }
+ 
+ void callback_clipboard_clear(GtkClipboard *clipboard, gpointer user_data)
+ {
+   g_free(user_data);
+ }
+ 
+ void callback_clipboard_targets_received(GtkClipboard *clipboard,
+                                          GdkAtom *atoms,
+                                          gint n_atoms,
+                                          gpointer data)
+ {
+   gint i;
+   printf("clipboard targets:\n");
+   for (i = 0; i < n_atoms; i++) {
+     printf("%s\n", gdk_atom_name(atoms[i]));
+   }
+ }
+ 
+ void selection_to_clip(void)
+ {
+   int bufsz, nitems, val;
+   char *buf, *p;
+   GList *list;
+   struct Item *item;
+   GtkTargetEntry target;
+   
+   if (ui.selection == NULL) return;
+   bufsz = 2*sizeof(int) // bufsz, nitems
+         + sizeof(struct BBox); // bbox
+   nitems = 0;
+   for (list = ui.selection->items; list != NULL; list = list->next) {
+     item = (struct Item *)list->data;
+     nitems++;
+     if (item->type == ITEM_STROKE) {
+       bufsz+= sizeof(int) // type
+             + sizeof(struct Brush) // brush
+             + sizeof(int) // num_points
+             + 2*item->path->num_points*sizeof(double); // the points
+       if (item->brush.variable_width)
+         bufsz += (item->path->num_points-1)*sizeof(double); // the widths
+     }
+     else if (item->type == ITEM_TEXT) {
+       bufsz+= sizeof(int) // type
+             + sizeof(struct Brush) // brush
+             + 2*sizeof(double) // bbox upper-left
+             + sizeof(int) // text len
+             + strlen(item->text)+1 // text
+             + sizeof(int) // font_name len
+             + strlen(item->font_name)+1 // font_name
+             + sizeof(double); // font_size
+     }
+     else if (item->type == ITEM_IMAGE) {
+       if (item->image_png == NULL) {
+         if (!pixbuf_to_buffer(item->image, &item->image_png, &item->image_png_len, "png")) {
+           item->image_png_len = 0;       // failed for some reason, so forget it
+         }
+       }
+       bufsz+= sizeof(int) // type
+         + sizeof(struct BBox)
+         + sizeof(gsize) // png_buflen
+         + item->image_png_len;
+     }
+     else bufsz+= sizeof(int); // type
+   }
+   p = buf = g_malloc(bufsz);
+   g_memmove(p, &bufsz, sizeof(int)); p+= sizeof(int);
+   g_memmove(p, &nitems, sizeof(int)); p+= sizeof(int);
+   g_memmove(p, &ui.selection->bbox, sizeof(struct BBox)); p+= sizeof(struct BBox);
+   for (list = ui.selection->items; list != NULL; list = list->next) {
+     item = (struct Item *)list->data;
+     g_memmove(p, &item->type, sizeof(int)); p+= sizeof(int);
+     if (item->type == ITEM_STROKE) {
+       g_memmove(p, &item->brush, sizeof(struct Brush)); p+= sizeof(struct Brush);
+       g_memmove(p, &item->path->num_points, sizeof(int)); p+= sizeof(int);
+       g_memmove(p, item->path->coords, 2*item->path->num_points*sizeof(double));
+       p+= 2*item->path->num_points*sizeof(double);
+       if (item->brush.variable_width) {
+         g_memmove(p, item->widths, (item->path->num_points-1)*sizeof(double));
+         p+= (item->path->num_points-1)*sizeof(double);
+       }
+     }
+     if (item->type == ITEM_TEXT) {
+       g_memmove(p, &item->brush, sizeof(struct Brush)); p+= sizeof(struct Brush);
+       g_memmove(p, &item->bbox.left, sizeof(double)); p+= sizeof(double);
+       g_memmove(p, &item->bbox.top, sizeof(double)); p+= sizeof(double);
+       val = strlen(item->text);
+       g_memmove(p, &val, sizeof(int)); p+= sizeof(int);
+       g_memmove(p, item->text, val+1); p+= val+1;
+       val = strlen(item->font_name);
+       g_memmove(p, &val, sizeof(int)); p+= sizeof(int);
+       g_memmove(p, item->font_name, val+1); p+= val+1;
+       g_memmove(p, &item->font_size, sizeof(double)); p+= sizeof(double);
+     }
+     if (item->type == ITEM_IMAGE) {
+       g_memmove(p, &item->bbox, sizeof(struct BBox)); p+= sizeof(struct BBox);
+       g_memmove(p, &item->image_png_len, sizeof(gsize)); p+= sizeof(gsize);
+       if (item->image_png_len > 0) {
+         g_memmove(p, item->image_png, item->image_png_len); p+= item->image_png_len;
+       }
+     }
+   }
+   
+   target.target = "_XOURNAL";
+   target.flags = 0;
+   target.info = 0;
+   
+   gtk_clipboard_set_with_data(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), 
+        &target, 1,
+        callback_clipboard_get, callback_clipboard_clear, buf);
+ }
+ 
+ // local paste within the application
+ void clipboard_paste_from_xournal(GtkSelectionData *sel_data)
+ {
+   unsigned char *p;
+   int nitems, npts, i, len;
+   struct Item *item;
+   double hoffset, voffset, cx, cy;
+   double *pf;
+   int sx, sy, wx, wy;
+   
+   reset_selection();
+ 
+   ui.selection = g_new(struct Selection, 1);
+   p = sel_data->data + sizeof(int);
+   g_memmove(&nitems, p, sizeof(int)); p+= sizeof(int);
+   ui.selection->type = ITEM_SELECTRECT;
+   ui.selection->layer = ui.cur_layer;
+   g_memmove(&ui.selection->bbox, p, sizeof(struct BBox)); p+= sizeof(struct BBox);
+   ui.selection->items = NULL;
+   
+   // find by how much we translate the pasted selection
+   gnome_canvas_get_scroll_offsets(canvas, &sx, &sy);
+   gdk_window_get_geometry(GTK_WIDGET(canvas)->window, NULL, NULL, &wx, &wy, NULL);
+   gnome_canvas_window_to_world(canvas, sx + wx/2, sy + wy/2, &cx, &cy);
+   cx -= ui.cur_page->hoffset;
+   cy -= ui.cur_page->voffset;
+   if (cx + (ui.selection->bbox.right-ui.selection->bbox.left)/2 > ui.cur_page->width)
+     cx = ui.cur_page->width - (ui.selection->bbox.right-ui.selection->bbox.left)/2;
+   if (cx - (ui.selection->bbox.right-ui.selection->bbox.left)/2 < 0)
+     cx = (ui.selection->bbox.right-ui.selection->bbox.left)/2;
+   if (cy + (ui.selection->bbox.bottom-ui.selection->bbox.top)/2 > ui.cur_page->height)
+     cy = ui.cur_page->height - (ui.selection->bbox.bottom-ui.selection->bbox.top)/2;
+   if (cy - (ui.selection->bbox.bottom-ui.selection->bbox.top)/2 < 0)
+     cy = (ui.selection->bbox.bottom-ui.selection->bbox.top)/2;
+   hoffset = cx - (ui.selection->bbox.right+ui.selection->bbox.left)/2;
+   voffset = cy - (ui.selection->bbox.top+ui.selection->bbox.bottom)/2;
+   ui.selection->bbox.left += hoffset;
+   ui.selection->bbox.right += hoffset;
+   ui.selection->bbox.top += voffset;
+   ui.selection->bbox.bottom += voffset;
+ 
+   ui.selection->canvas_item = gnome_canvas_item_new(ui.cur_layer->group,
+       gnome_canvas_rect_get_type(), "width-pixels", 1,
+       "outline-color-rgba", 0x000000ff,
+       "fill-color-rgba", 0x80808040,
+       "x1", ui.selection->bbox.left, "x2", ui.selection->bbox.right, 
+       "y1", ui.selection->bbox.top, "y2", ui.selection->bbox.bottom, NULL);
+   make_dashed(ui.selection->canvas_item);
+ 
+   while (nitems-- > 0) {
+     item = g_new(struct Item, 1);
+     ui.selection->items = g_list_append(ui.selection->items, item);
+     ui.cur_layer->items = g_list_append(ui.cur_layer->items, item);
+     ui.cur_layer->nitems++;
+     g_memmove(&item->type, p, sizeof(int)); p+= sizeof(int);
+     if (item->type == ITEM_STROKE) {
+       g_memmove(&item->brush, p, sizeof(struct Brush)); p+= sizeof(struct Brush);
+       g_memmove(&npts, p, sizeof(int)); p+= sizeof(int);
+       item->path = gnome_canvas_points_new(npts);
+       pf = (double *)p;
+       for (i=0; i<npts; i++) {
+         item->path->coords[2*i] = pf[2*i] + hoffset;
+         item->path->coords[2*i+1] = pf[2*i+1] + voffset;
+       }
+       p+= 2*item->path->num_points*sizeof(double);
+       if (item->brush.variable_width) {
+         item->widths = g_memdup(p, (item->path->num_points-1)*sizeof(double));
+         p+= (item->path->num_points-1)*sizeof(double);
+       }
+       else item->widths = NULL;
+       update_item_bbox(item);
+       make_canvas_item_one(ui.cur_layer->group, item);
+     }
+     if (item->type == ITEM_TEXT) {
+       g_memmove(&item->brush, p, sizeof(struct Brush)); p+= sizeof(struct Brush);
+       g_memmove(&item->bbox.left, p, sizeof(double)); p+= sizeof(double);
+       g_memmove(&item->bbox.top, p, sizeof(double)); p+= sizeof(double);
+       item->bbox.left += hoffset;
+       item->bbox.top += voffset;
+       g_memmove(&len, p, sizeof(int)); p+= sizeof(int);
+       item->text = g_malloc(len+1);
+       g_memmove(item->text, p, len+1); p+= len+1;
+       g_memmove(&len, p, sizeof(int)); p+= sizeof(int);
+       item->font_name = g_malloc(len+1);
+       g_memmove(item->font_name, p, len+1); p+= len+1;
+       g_memmove(&item->font_size, p, sizeof(double)); p+= sizeof(double);
+       make_canvas_item_one(ui.cur_layer->group, item);
+     }
+     if (item->type == ITEM_IMAGE) {
+       item->canvas_item = NULL;
+       item->image_scaled = NULL;
+       item->image_png = NULL;
+       item->image_png_len = 0;
+       g_memmove(&item->bbox, p, sizeof(struct BBox)); p+= sizeof(struct BBox);
+       item->bbox.left += hoffset;
+       item->bbox.right += hoffset;
+       item->bbox.top += voffset;
+       item->bbox.bottom += voffset;
+       g_memmove(&item->image_png_len, p, sizeof(gsize)); p+= sizeof(gsize);
+       if (item->image_png_len > 0) {
+         item->image_png = g_memdup(p, item->image_png_len);
+         item->image = pixbuf_from_buffer(item->image_png, item->image_png_len);
+         p+= item->image_png_len;
+       } else {
+         item->image = NULL;
+       }
+       make_canvas_item_one(ui.cur_layer->group, item);
+     }
+   }
+ 
+   prepare_new_undo();
+   undo->type = ITEM_PASTE;
+   undo->layer = ui.cur_layer;
+   undo->itemlist = g_list_copy(ui.selection->items);  
+   
+   gtk_selection_data_free(sel_data);
+   update_copy_paste_enabled();
+   update_color_menu();
+   update_thickness_buttons();
+   update_color_buttons();
+   update_font_button();  
+   update_cursor(); // FIXME: can't know if pointer is within selection!
+ }
+ 
+ // paste an external image
+ void clipboard_paste_image(GdkPixbuf *pixbuf)
+ {
+   double pt[2];
+ 
+   reset_selection();
+ 
+   get_current_pointer_coords(pt);
+   set_current_page(pt);  
+ 
+   create_image_from_pixbuf(pixbuf, NULL, pt);
+ }
+ 
+ // work out what format the clipboard data is in, and paste accordingly
+ void clipboard_paste(void)
+ {
+   GtkSelectionData *sel_data;
+   GdkPixbuf *pixbuf;
+   GtkClipboard *clipboard;
+   unsigned char *p;
+   int nitems, npts, i, len;
+   struct Item *item;
+   double hoffset, voffset, cx, cy;
+   double *pf;
+   int sx, sy, wx, wy;
+ 
+   if (ui.cur_layer == NULL) return;
+ 
+   ui.cur_item_type = ITEM_PASTE;
+   clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
+   sel_data = gtk_clipboard_wait_for_contents(
+       clipboard,
+       gdk_atom_intern("_XOURNAL", FALSE));
+   ui.cur_item_type = ITEM_NONE;
+   if (sel_data != NULL) {
+     clipboard_paste_from_xournal(sel_data);
+   } else {
+     pixbuf = gtk_clipboard_wait_for_image(clipboard);
+     if (pixbuf != NULL) {
+       clipboard_paste_image(pixbuf);
+     }
+   }
+ }
diff -c /dev/null 'xournal/src/xo-clipboard.h'
Index: ./src/xo-clipboard.h
*** ./src/xo-clipboard.h	Thu Jan  1 12:00:00 1970
--- ./src/xo-clipboard.h	Thu Mar 25 15:09:53 2010
***************
*** 0 ****
--- 1,2 ----
+ void selection_to_clip(void);
+ void clipboard_paste(void);
diff -c 'xournal-0.4.5/src/xo-file.c' 'xournal/src/xo-file.c'
Index: ./src/xo-file.c
*** ./src/xo-file.c	Tue Sep 29 12:36:05 2009
--- ./src/xo-file.c	Thu Jul 29 16:59:47 2010
***************
*** 25,30 ****
--- 25,31 ----
  #include "xo-misc.h"
  #include "xo-file.h"
  #include "xo-paint.h"
+ #include "xo-image.h"
  
  const char *tool_names[NUM_TOOLS] = {"pen", "eraser", "highlighter", "text", "", "selectrect", "vertspace", "hand"};
  const char *color_names[COLOR_MAX] = {"black", "blue", "red", "green",
***************
*** 68,73 ****
--- 69,122 ----
    }
  }
  
+ 
+ // Write image to file: returns true on success, false on error.
+ // The image is written as a base64 encoded PNG.
+ gboolean write_image(gzFile f, Item *item)
+ {
+   gchar *base64_str;
+   GError **error;
+ 
+   error = NULL;
+ 
+   if (item->image_png == NULL) {
+     if (!pixbuf_to_buffer(item->image, &item->image_png, &item->image_png_len, "png")) {
+       item->image_png_len = 0;       // failed for some reason, so forget it
+       return FALSE;
+     }
+   }
+ 
+   base64_str = g_base64_encode(item->image_png, item->image_png_len);
+ 
+   gzputs(f, base64_str);
+ 
+   g_free(base64_str);
+ 
+   return TRUE;
+ }
+ 
+ // create pixbuf from base64 encoded PNG, or return NULL on failure
+ GdkPixbuf *read_pixbuf(const gchar *base64_str, gsize base64_strlen)
+ {
+   gchar *base64_str2;
+   gchar *png_buf;
+   gsize png_buflen;
+   GdkPixbuf *pixbuf;
+ 
+   // We have to copy the string in order to null terminate it, sigh.
+   base64_str2 = g_memdup(base64_str, base64_strlen + 1);
+   base64_str2[ base64_strlen ] = '\0';
+   
+   png_buf = g_base64_decode(base64_str2, &png_buflen);
+ 
+   pixbuf = pixbuf_from_buffer(png_buf, png_buflen);
+ 
+   g_free(png_buf);
+   g_free(base64_str2);
+ 
+   return pixbuf;
+ }
+ 
  // saves the journal to a file: returns true on success, false on error
  
  gboolean save_journal(const char *filename)
***************
*** 199,204 ****
--- 248,261 ----
            gzprintf(f, "\">%s</text>\n", tmpstr);
            g_free(tmpstr);
          }
+ 	if (item->type == ITEM_IMAGE) {
+           gzprintf(f, "<image left=\"%.2f\" top=\"%.2f\" right=\"%.2f\" bottom=\"%.2f\">", item->bbox.left, item->bbox.top, item->bbox.right, item->bbox.bottom);
+ 
+           if (!write_image(f, item)) {
+             success = FALSE;
+           }
+           gzprintf(f, "</image>\n");
+         }
        }
        gzprintf(f, "</layer>\n");
      }
***************
*** 575,580 ****
--- 632,688 ----
      }
      if (has_attr!=31) *error = xoj_invalid();
    }
+   else if (!strcmp(element_name, "image")) { // start of a image item
+     if (tmpLayer == NULL || tmpItem != NULL) {
+       *error = xoj_invalid();
+       return;
+     }
+     tmpItem = (struct Item *)g_malloc0(sizeof(struct Item));
+     tmpItem->type = ITEM_IMAGE;
+     tmpItem->canvas_item = NULL;
+     tmpItem->image=NULL;
+     tmpItem->image_scaled=NULL;
+     tmpItem->image_png = NULL;
+     tmpItem->image_png_len = 0;
+     tmpLayer->items = g_list_append(tmpLayer->items, tmpItem);
+     tmpLayer->nitems++;
+     // scan for x, y
+     has_attr = 0;
+     while (*attribute_names!=NULL) {
+       if (!strcmp(*attribute_names, "left")) {
+         if (has_attr & 1) *error = xoj_invalid();
+         cleanup_numeric((gchar *)*attribute_values);
+         tmpItem->bbox.left = g_ascii_strtod(*attribute_values, &ptr);
+         if (ptr == *attribute_values) *error = xoj_invalid();
+         has_attr |= 1;
+       }
+       else if (!strcmp(*attribute_names, "top")) {
+         if (has_attr & 2) *error = xoj_invalid();
+         cleanup_numeric((gchar *)*attribute_values);
+         tmpItem->bbox.top = g_ascii_strtod(*attribute_values, &ptr);
+         if (ptr == *attribute_values) *error = xoj_invalid();
+         has_attr |= 2;
+       }
+       else if (!strcmp(*attribute_names, "right")) {
+         if (has_attr & 4) *error = xoj_invalid();
+         cleanup_numeric((gchar *)*attribute_values);
+         tmpItem->bbox.right = g_ascii_strtod(*attribute_values, &ptr);
+         if (ptr == *attribute_values) *error = xoj_invalid();
+         has_attr |= 4;
+       }
+       else if (!strcmp(*attribute_names, "bottom")) {
+         if (has_attr & 8) *error = xoj_invalid();
+         cleanup_numeric((gchar *)*attribute_values);
+         tmpItem->bbox.bottom = g_ascii_strtod(*attribute_values, &ptr);
+         if (ptr == *attribute_values) *error = xoj_invalid();
+         has_attr |= 8;
+       }
+       else *error = xoj_invalid();
+       attribute_names++;
+       attribute_values++;
+     }
+     if (has_attr!=15) *error = xoj_invalid();
+   }
  }
  
  void xoj_parser_end_element(GMarkupParseContext *context,
***************
*** 610,615 ****
--- 718,730 ----
      }
      tmpItem = NULL;
    }
+   if (!strcmp(element_name, "image")) {
+     if (tmpItem == NULL) {
+       *error = xoj_invalid();
+       return;
+     }
+     tmpItem = NULL;
+   }
  }
  
  void xoj_parser_text(GMarkupParseContext *context,
***************
*** 647,652 ****
--- 762,770 ----
      g_memmove(tmpItem->text, text, text_len);
      tmpItem->text[text_len]=0;
    }
+   if (!strcmp(element_name, "image")) {
+     tmpItem->image = read_pixbuf(text, text_len);
+   }
  }
  
  gboolean user_wants_second_chance(char **filename)
***************
*** 716,722 ****
    g_free(tmpfn);
  
    f = gzopen(filename, "r");
!   if (f==NULL) return FALSE;
    if (filename[0]=='/') {
      if (ui.default_path != NULL) g_free(ui.default_path);
      ui.default_path = g_path_get_dirname(filename);
--- 834,845 ----
    g_free(tmpfn);
  
    f = gzopen(filename, "r");
!   if (f==NULL) {
! 	  #ifdef IMAGE_DEBUG
! 	  printf("gzopen failed\n");
! 	  #endif
! 	  return FALSE;
!   }
    if (filename[0]=='/') {
      if (ui.default_path != NULL) g_free(ui.default_path);
      ui.default_path = g_path_get_dirname(filename);
***************
*** 737,752 ****
  
    while (valid && !gzeof(f)) {
      len = gzread(f, buffer, 1000);
!     if (len<0) valid = FALSE;
      if (maybe_pdf && len>=4 && !strncmp(buffer, "%PDF", 4))
        { valid = FALSE; break; } // most likely pdf
      else maybe_pdf = FALSE;
      if (len<=0) break;
      valid = g_markup_parse_context_parse(context, buffer, len, &error);
    }
    gzclose(f);
!   if (valid) valid = g_markup_parse_context_end_parse(context, &error);
!   if (tmpJournal.npages == 0) valid = FALSE;
    g_markup_parse_context_free(context);
    
    if (!valid) {
--- 860,893 ----
  
    while (valid && !gzeof(f)) {
      len = gzread(f, buffer, 1000);
!     if (len<0){
! 	    valid = FALSE;
!     }
      if (maybe_pdf && len>=4 && !strncmp(buffer, "%PDF", 4))
        { valid = FALSE; break; } // most likely pdf
      else maybe_pdf = FALSE;
      if (len<=0) break;
      valid = g_markup_parse_context_parse(context, buffer, len, &error);
+ 	      
+ #ifdef IMAGE_DEBUG
+     if(!valid) printf("parsing failed\n");
+ #endif
    }
    gzclose(f);
!   
!   if (valid) {
! 	  valid = g_markup_parse_context_end_parse(context, &error);
! 	  
! 	  #ifdef IMAGE_DEBUG
! 	  if(!valid) printf("end parsing failed\n");
! 	  #endif
!   }
!   if (tmpJournal.npages == 0){
! 	   #ifdef IMAGE_DEBUG
! 	  printf("found no pages\n");
! 	  #endif
! 	  valid = FALSE;
!   }
    g_markup_parse_context_free(context);
    
    if (!valid) {
***************
*** 823,828 ****
--- 964,970 ----
    update_page_stuff();
    rescale_bg_pixmaps(); // this requests the PDF pages if need be
    gtk_adjustment_set_value(gtk_layout_get_vadjustment(GTK_LAYOUT(canvas)), 0);
+   
    return TRUE;
  }
  
***************
*** 1338,1343 ****
--- 1480,1486 ----
    ui.print_ruling = TRUE;
    ui.default_unit = UNIT_CM;
    ui.default_path = NULL;
+   ui.default_image = NULL;
    ui.default_font_name = g_strdup(DEFAULT_FONT);
    ui.default_font_size = DEFAULT_FONT_SIZE;
    ui.pressure_sensitivity = FALSE;
diff -c /dev/null 'xournal/src/xo-image.c'
Index: ./src/xo-image.c
*** ./src/xo-image.c	Thu Jan  1 12:00:00 1970
--- ./src/xo-image.c	Thu Jul 29 16:54:52 2010
***************
*** 0 ****
--- 1,238 ----
+ #ifdef HAVE_CONFIG_H
+ #  include <config.h>
+ #endif
+ 
+ #include <math.h>
+ #include <string.h>
+ #include <gtk/gtk.h>
+ #include <gio/gio.h>
+ 
+ #include "xournal.h"
+ #include "xo-support.h"
+ #include "xo-image.h"
+ 
+ 
+ // Write pixmap to buffer: returns true on success, false on error.
+ gboolean pixbuf_to_buffer(GdkPixbuf *pixbuf, gchar **buf, gsize *buflen, const char *type)
+ {
+   GError *error;
+ 
+   error = NULL;
+ 
+   if (!gdk_pixbuf_save_to_buffer(pixbuf,
+                                  buf,
+                                  buflen,
+                                  type,
+                                  &error,
+                                  NULL)) {
+     return FALSE;
+   }
+ 
+   return TRUE;
+ }
+ 
+ // create pixbuf from buffer, or return NULL on failure
+ GdkPixbuf *pixbuf_from_buffer(const gchar *buf, gsize buflen)
+ {
+   GInputStream *istream;
+   GdkPixbuf *pixbuf;
+   GError *error;
+ 
+   error = NULL;
+ 
+   istream = g_memory_input_stream_new_from_data (buf, buflen, NULL);
+ 
+   pixbuf = gdk_pixbuf_new_from_stream(istream, NULL, &error); 
+ 
+   g_input_stream_close(istream, NULL, &error);
+ 
+   return pixbuf;
+ }
+ 
+ void create_image_from_pixbuf(GdkPixbuf *pixbuf, struct Item *item, double *pt)
+ {
+   GtkTextBuffer *buffer;
+   GnomeCanvasItem *canvas_item;
+   GdkColor color;
+   GtkWidget *dialog;
+   GtkFileFilter *filt_all;
+   GtkFileFilter *filt_gdkimage;
+   double scale;
+ 
+   if (item==NULL) {
+     item = g_new(struct Item, 1);
+     item->type = ITEM_IMAGE;
+     item->canvas_item = NULL;
+     item->bbox.left = pt[0];
+     item->bbox.top = pt[1];
+     item->image = pixbuf;
+     item->image_scaled = NULL;
+     item->image_png = NULL;
+     item->image_png_len = 0;
+ 
+     // Scale at native size, unless that won't fit, 
+     // in which case we shrink it down.
+     scale = 1 / ui.zoom;
+     if( (scale * gdk_pixbuf_get_width(item->image)) > ui.cur_page->width - item->bbox.left ) {
+       //set scale so that it does not extend too far to the right
+       scale = (ui.cur_page->width - item->bbox.left) / gdk_pixbuf_get_width(item->image);
+     }
+     if( (scale * gdk_pixbuf_get_height(item->image)) > ui.cur_page->height - item->bbox.top ) {
+       //set scale so that it does not extend too far to the bottom
+       scale = (ui.cur_page->height - item->bbox.top) / gdk_pixbuf_get_height(item->image);
+     }
+ 
+     item->bbox.right = item->bbox.left + scale * gdk_pixbuf_get_width(item->image);
+     item->bbox.bottom = item->bbox.top + scale * gdk_pixbuf_get_height(item->image);
+     g_memmove(&(item->brush), ui.cur_brush, sizeof(struct Brush));
+     ui.cur_layer->items = g_list_append(ui.cur_layer->items, item);
+     ui.cur_layer->nitems++;
+   }
+   
+   item->type = ITEM_IMAGE;
+   ui.cur_item = item;
+   
+   if (item->canvas_item!=NULL) {
+     lower_canvas_item_to(ui.cur_layer->group, canvas_item, item->canvas_item);
+     gtk_object_destroy(GTK_OBJECT(item->canvas_item));
+   }
+ 
+   make_canvas_item_one(ui.cur_layer->group, item);
+ 
+   // select image
+   reset_selection();
+   ui.selection = g_new0(struct Selection, 1);
+   ui.selection->type = ITEM_SELECTRECT;
+   ui.selection->layer = ui.cur_layer;
+   ui.selection->bbox = item->bbox;
+   ui.selection->items = g_list_append(ui.selection->items, item);
+   ui.selection->canvas_item = gnome_canvas_item_new(ui.cur_layer->group,
+       gnome_canvas_rect_get_type(), "width-pixels", 1,
+       "outline-color-rgba", 0x000000ff,
+       "fill-color-rgba", 0x80808040,
+       "x1", ui.selection->bbox.left, "x2", ui.selection->bbox.right, 
+       "y1", ui.selection->bbox.top, "y2", ui.selection->bbox.bottom, NULL);
+   make_dashed(ui.selection->canvas_item);
+ 
+   // add undo information
+   prepare_new_undo();
+   undo->type = ITEM_IMAGE;
+   undo->item = ui.cur_item;
+   undo->layer = ui.cur_layer;
+   
+   ui.cur_item = NULL;
+   ui.cur_item_type = ITEM_NONE;
+ }
+ 
+ void insert_image(GdkEvent *event, struct Item *item)
+ {
+   GtkTextBuffer *buffer;
+   GnomeCanvasItem *canvas_item;
+   GdkColor color;
+   GtkWidget *dialog;
+   GtkFileFilter *filt_all;
+   GtkFileFilter *filt_gdkimage;
+   char *filename;
+   GdkPixbuf *pixbuf;
+   double scale=1;
+   double pt[2];
+   
+   dialog = gtk_file_chooser_dialog_new(_("Insert Image"), GTK_WINDOW (winMain),
+      GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+      GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
+ #ifdef FILE_DIALOG_SIZE_BUGFIX
+   gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 400);
+ #endif
+      
+   filt_all = gtk_file_filter_new();
+   gtk_file_filter_set_name(filt_all, _("All files"));
+   gtk_file_filter_add_pattern(filt_all, "*");
+   filt_gdkimage = gtk_file_filter_new();
+   gtk_file_filter_set_name(filt_gdkimage, _("supported image files"));
+   gtk_file_filter_add_pixbuf_formats(filt_gdkimage);
+   gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (dialog), filt_gdkimage);
+   gtk_file_chooser_add_filter(GTK_FILE_CHOOSER (dialog), filt_all);
+ 
+   if (ui.default_image != NULL) gtk_file_chooser_set_filename(GTK_FILE_CHOOSER (dialog), ui.default_image);
+ 
+   if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_OK) {
+     gtk_widget_destroy(dialog);
+     return;
+   }
+   filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (dialog));
+   gtk_widget_destroy(dialog);
+ 
+   if (filename == NULL) {
+     /* nothing selected */
+     return;
+   }
+ 
+   if (ui.default_image != NULL) g_free(ui.default_image);
+   ui.default_image = g_strdup(filename);
+   
+   pixbuf=gdk_pixbuf_new_from_file(filename, NULL);
+   if(pixbuf==NULL){
+ 	  /* open failed */
+ 	  dialog = gtk_message_dialog_new(GTK_WINDOW (winMain), GTK_DIALOG_DESTROY_WITH_PARENT,
+ 	    GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Error opening image '%s'"), filename);
+ 	  gtk_dialog_run(GTK_DIALOG(dialog));
+ 	  gtk_widget_destroy(dialog);
+ 	  g_free(filename);
+ 	  ui.cur_item = NULL;
+ 	  ui.cur_item_type = ITEM_NONE;
+ 	  return;
+   }
+ 
+   ui.cur_item_type = ITEM_IMAGE;
+ 
+   get_pointer_coords(event, pt);
+   set_current_page(pt);  
+ 
+   create_image_from_pixbuf(pixbuf, item, pt);
+ }
+ 
+ void update_scaled_image(struct Item *item)
+ {
+   gboolean use_native = is_native_image_usable( item );
+   if ( is_native_image_usable( item ) != (item->image_scaled == NULL) ) {
+     // we are currently using a scaled image, and should switch to native,
+     // or vice versa
+ 
+     adjust_or_make_canvas_item_image(ui.cur_layer->group, item);
+   }
+ }
+ 
+ void rescale_images(void)
+ {
+   GList *pagelist, *layerlist, *itemlist;
+   struct Item *item;
+   
+   for (pagelist = journal.pages; pagelist!=NULL; pagelist = pagelist->next)
+     for (layerlist = ((struct Page *)pagelist->data)->layers; layerlist!=NULL; layerlist = layerlist->next)
+       for (itemlist = ((struct Layer *)layerlist->data)->items; itemlist!=NULL; itemlist = itemlist->next) {
+         item = (struct Item *)itemlist->data;
+         if ( item->type == ITEM_IMAGE ) {
+           update_scaled_image( item );
+         }
+       }
+ }
+ 
+ gboolean is_native_image_usable(struct Item *item)
+ {
+   double native_width;
+   double native_height;
+   double required_width;
+   double required_height;
+   gboolean usable;
+ 
+   // use the original image at native resolution if it's close enough to what we need
+   native_width  = gdk_pixbuf_get_width(item->image) / ui.zoom;
+   native_height = gdk_pixbuf_get_height(item->image) / ui.zoom;
+   required_width = item->bbox.right - item->bbox.left;
+   required_height = item->bbox.bottom - item->bbox.top;
+     
+   usable = ( fabs( native_width - required_width ) < 1 && 
+              fabs( native_height - required_height ) < 1 );
+ 
+   return usable;
+ }
diff -c /dev/null 'xournal/src/xo-image.h'
Index: ./src/xo-image.h
*** ./src/xo-image.h	Thu Jan  1 12:00:00 1970
--- ./src/xo-image.h	Thu Jun 24 20:42:02 2010
***************
*** 0 ****
--- 1,7 ----
+ extern gboolean pixbuf_to_buffer(GdkPixbuf *pixbuf, gchar **buf, gsize *buflen, const char *type);
+ extern GdkPixbuf *pixbuf_from_buffer(const gchar *buf, gsize buflen);
+ 
+ void create_image_from_pixbuf(GdkPixbuf *pixbuf, struct Item *item, double *pt);
+ void insert_image(GdkEvent *event, struct Item *item);
+ void rescale_images(void);
+ gboolean is_native_image_usable(struct Item *item);
diff -c 'xournal-0.4.5/src/xo-interface.c' 'xournal/src/xo-interface.c'
Index: ./src/xo-interface.c
*** ./src/xo-interface.c	Fri Oct  2 19:03:32 2009
--- ./src/xo-interface.c	Mon Mar 22 11:39:25 2010
***************
*** 36,42 ****
    GtkWidget *menuFile_menu;
    GtkWidget *fileNew;
    GtkWidget *fileNewBackground;
-   GtkWidget *image623;
    GtkWidget *fileOpen;
    GtkWidget *fileSave;
    GtkWidget *fileSaveAs;
--- 36,41 ----
***************
*** 53,59 ****
    GtkWidget *mru7;
    GtkWidget *separator22;
    GtkWidget *filePrintOptions;
-   GtkWidget *image624;
    GtkWidget *filePrint;
    GtkWidget *filePrintPDF;
    GtkWidget *separator2;
--- 52,57 ----
***************
*** 81,102 ****
    GtkWidget *viewZoomOut;
    GtkWidget *viewNormalSize;
    GtkWidget *viewPageWidth;
-   GtkWidget *image625;
    GtkWidget *viewSetZoom;
    GtkWidget *separator5;
    GtkWidget *viewFirstPage;
-   GtkWidget *image626;
    GtkWidget *viewPreviousPage;
-   GtkWidget *image627;
    GtkWidget *viewNextPage;
-   GtkWidget *image628;
    GtkWidget *viewLastPage;
-   GtkWidget *image629;
    GtkWidget *separator6;
    GtkWidget *viewShowLayer;
-   GtkWidget *image630;
    GtkWidget *viewHideLayer;
-   GtkWidget *image631;
    GtkWidget *menuJournal;
    GtkWidget *menuJournal_menu;
    GtkWidget *journalNewPageBefore;
--- 79,93 ----
***************
*** 131,137 ****
    GtkWidget *journalApplyAllPages;
    GtkWidget *separator23;
    GtkWidget *journalLoadBackground;
-   GtkWidget *image632;
    GtkWidget *journalScreenshot;
    GtkWidget *separator19;
    GtkWidget *journalDefaultBackground;
--- 122,127 ----
***************
*** 153,159 ****
    GtkWidget *toolsHand;
    GtkWidget *separator16;
    GtkWidget *toolsColor;
-   GtkWidget *image633;
    GtkWidget *toolsColor_menu;
    GSList *colorBlack_group = NULL;
    GtkWidget *colorBlack;
--- 143,148 ----
***************
*** 196,202 ****
    GtkWidget *highlighterMedium;
    GtkWidget *highlighterThick;
    GtkWidget *toolsTextFont;
-   GtkWidget *image634;
    GtkWidget *separator10;
    GtkWidget *toolsDefaultPen;
    GtkWidget *toolsDefaultEraser;
--- 185,190 ----
***************
*** 289,294 ****
--- 277,283 ----
    GtkWidget *buttonEraser;
    GtkWidget *buttonHighlighter;
    GtkWidget *buttonText;
+   GtkWidget *buttonImage;
    GtkWidget *buttonReco;
    GtkWidget *buttonRuler;
    GtkWidget *toolitem15;
***************
*** 368,381 ****
    gtk_widget_show (fileNew);
    gtk_container_add (GTK_CONTAINER (menuFile_menu), fileNew);
  
!   fileNewBackground = gtk_image_menu_item_new_with_mnemonic (_("Annotate PD_F"));
    gtk_widget_show (fileNewBackground);
    gtk_container_add (GTK_CONTAINER (menuFile_menu), fileNewBackground);
  
-   image623 = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_MENU);
-   gtk_widget_show (image623);
-   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (fileNewBackground), image623);
- 
    fileOpen = gtk_image_menu_item_new_from_stock ("gtk-open", accel_group);
    gtk_widget_show (fileOpen);
    gtk_container_add (GTK_CONTAINER (menuFile_menu), fileOpen);
--- 357,366 ----
    gtk_widget_show (fileNew);
    gtk_container_add (GTK_CONTAINER (menuFile_menu), fileNew);
  
!   fileNewBackground = gtk_image_menu_item_new_with_mnemonic ("Annotate PD_F");
    gtk_widget_show (fileNewBackground);
    gtk_container_add (GTK_CONTAINER (menuFile_menu), fileNewBackground);
  
    fileOpen = gtk_image_menu_item_new_from_stock ("gtk-open", accel_group);
    gtk_widget_show (fileOpen);
    gtk_container_add (GTK_CONTAINER (menuFile_menu), fileOpen);
***************
*** 437,450 ****
    gtk_container_add (GTK_CONTAINER (menuFile_menu), separator22);
    gtk_widget_set_sensitive (separator22, FALSE);
  
!   filePrintOptions = gtk_image_menu_item_new_with_mnemonic (_("Print Options"));
    gtk_widget_show (filePrintOptions);
    gtk_container_add (GTK_CONTAINER (menuFile_menu), filePrintOptions);
  
-   image624 = gtk_image_new_from_stock ("gtk-preferences", GTK_ICON_SIZE_MENU);
-   gtk_widget_show (image624);
-   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (filePrintOptions), image624);
- 
    filePrint = gtk_image_menu_item_new_from_stock ("gtk-print", accel_group);
    gtk_widget_show (filePrint);
    gtk_container_add (GTK_CONTAINER (menuFile_menu), filePrint);
--- 422,431 ----
    gtk_container_add (GTK_CONTAINER (menuFile_menu), separator22);
    gtk_widget_set_sensitive (separator22, FALSE);
  
!   filePrintOptions = gtk_image_menu_item_new_with_mnemonic ("Print Options");
    gtk_widget_show (filePrintOptions);
    gtk_container_add (GTK_CONTAINER (menuFile_menu), filePrintOptions);
  
    filePrint = gtk_image_menu_item_new_from_stock ("gtk-print", accel_group);
    gtk_widget_show (filePrint);
    gtk_container_add (GTK_CONTAINER (menuFile_menu), filePrint);
***************
*** 577,593 ****
                                GDK_0, (GdkModifierType) GDK_CONTROL_MASK,
                                GTK_ACCEL_VISIBLE);
  
!   viewPageWidth = gtk_image_menu_item_new_with_mnemonic (_("Page _Width"));
    gtk_widget_show (viewPageWidth);
    gtk_container_add (GTK_CONTAINER (menuViewZoom_menu), viewPageWidth);
    gtk_widget_add_accelerator (viewPageWidth, "activate", accel_group,
                                GDK_equal, (GdkModifierType) GDK_CONTROL_MASK,
                                GTK_ACCEL_VISIBLE);
  
-   image625 = gtk_image_new_from_stock ("gtk-zoom-fit", GTK_ICON_SIZE_MENU);
-   gtk_widget_show (image625);
-   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (viewPageWidth), image625);
- 
    viewSetZoom = gtk_menu_item_new_with_mnemonic (_("_Set Zoom"));
    gtk_widget_show (viewSetZoom);
    gtk_container_add (GTK_CONTAINER (menuViewZoom_menu), viewSetZoom);
--- 558,570 ----
                                GDK_0, (GdkModifierType) GDK_CONTROL_MASK,
                                GTK_ACCEL_VISIBLE);
  
!   viewPageWidth = gtk_image_menu_item_new_with_mnemonic ("Page _Width");
    gtk_widget_show (viewPageWidth);
    gtk_container_add (GTK_CONTAINER (menuViewZoom_menu), viewPageWidth);
    gtk_widget_add_accelerator (viewPageWidth, "activate", accel_group,
                                GDK_equal, (GdkModifierType) GDK_CONTROL_MASK,
                                GTK_ACCEL_VISIBLE);
  
    viewSetZoom = gtk_menu_item_new_with_mnemonic (_("_Set Zoom"));
    gtk_widget_show (viewSetZoom);
    gtk_container_add (GTK_CONTAINER (menuViewZoom_menu), viewSetZoom);
***************
*** 597,667 ****
    gtk_container_add (GTK_CONTAINER (menuView_menu), separator5);
    gtk_widget_set_sensitive (separator5, FALSE);
  
!   viewFirstPage = gtk_image_menu_item_new_with_mnemonic (_("_First Page"));
    gtk_widget_show (viewFirstPage);
    gtk_container_add (GTK_CONTAINER (menuView_menu), viewFirstPage);
    gtk_widget_add_accelerator (viewFirstPage, "activate", accel_group,
                                GDK_Home, (GdkModifierType) GDK_CONTROL_MASK,
                                GTK_ACCEL_VISIBLE);
  
!   image626 = gtk_image_new_from_stock ("gtk-goto-first", GTK_ICON_SIZE_MENU);
!   gtk_widget_show (image626);
!   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (viewFirstPage), image626);
! 
!   viewPreviousPage = gtk_image_menu_item_new_with_mnemonic (_("_Previous Page"));
    gtk_widget_show (viewPreviousPage);
    gtk_container_add (GTK_CONTAINER (menuView_menu), viewPreviousPage);
    gtk_widget_add_accelerator (viewPreviousPage, "activate", accel_group,
                                GDK_Left, (GdkModifierType) GDK_CONTROL_MASK,
                                GTK_ACCEL_VISIBLE);
  
!   image627 = gtk_image_new_from_stock ("gtk-go-back", GTK_ICON_SIZE_MENU);
!   gtk_widget_show (image627);
!   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (viewPreviousPage), image627);
! 
!   viewNextPage = gtk_image_menu_item_new_with_mnemonic (_("_Next Page"));
    gtk_widget_show (viewNextPage);
    gtk_container_add (GTK_CONTAINER (menuView_menu), viewNextPage);
    gtk_widget_add_accelerator (viewNextPage, "activate", accel_group,
                                GDK_Right, (GdkModifierType) GDK_CONTROL_MASK,
                                GTK_ACCEL_VISIBLE);
  
!   image628 = gtk_image_new_from_stock ("gtk-go-forward", GTK_ICON_SIZE_MENU);
!   gtk_widget_show (image628);
!   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (viewNextPage), image628);
! 
!   viewLastPage = gtk_image_menu_item_new_with_mnemonic (_("_Last Page"));
    gtk_widget_show (viewLastPage);
    gtk_container_add (GTK_CONTAINER (menuView_menu), viewLastPage);
    gtk_widget_add_accelerator (viewLastPage, "activate", accel_group,
                                GDK_End, (GdkModifierType) GDK_CONTROL_MASK,
                                GTK_ACCEL_VISIBLE);
  
-   image629 = gtk_image_new_from_stock ("gtk-goto-last", GTK_ICON_SIZE_MENU);
-   gtk_widget_show (image629);
-   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (viewLastPage), image629);
- 
    separator6 = gtk_separator_menu_item_new ();
    gtk_widget_show (separator6);
    gtk_container_add (GTK_CONTAINER (menuView_menu), separator6);
    gtk_widget_set_sensitive (separator6, FALSE);
  
!   viewShowLayer = gtk_image_menu_item_new_with_mnemonic (_("_Show Layer"));
    gtk_widget_show (viewShowLayer);
    gtk_container_add (GTK_CONTAINER (menuView_menu), viewShowLayer);
  
!   image630 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU);
!   gtk_widget_show (image630);
!   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (viewShowLayer), image630);
! 
!   viewHideLayer = gtk_image_menu_item_new_with_mnemonic (_("_Hide Layer"));
    gtk_widget_show (viewHideLayer);
    gtk_container_add (GTK_CONTAINER (menuView_menu), viewHideLayer);
  
-   image631 = gtk_image_new_from_stock ("gtk-remove", GTK_ICON_SIZE_MENU);
-   gtk_widget_show (image631);
-   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (viewHideLayer), image631);
- 
    menuJournal = gtk_menu_item_new_with_mnemonic (_("_Journal"));
    gtk_widget_show (menuJournal);
    gtk_container_add (GTK_CONTAINER (menubar), menuJournal);
--- 574,620 ----
    gtk_container_add (GTK_CONTAINER (menuView_menu), separator5);
    gtk_widget_set_sensitive (separator5, FALSE);
  
!   viewFirstPage = gtk_image_menu_item_new_with_mnemonic ("_First Page");
    gtk_widget_show (viewFirstPage);
    gtk_container_add (GTK_CONTAINER (menuView_menu), viewFirstPage);
    gtk_widget_add_accelerator (viewFirstPage, "activate", accel_group,
                                GDK_Home, (GdkModifierType) GDK_CONTROL_MASK,
                                GTK_ACCEL_VISIBLE);
  
!   viewPreviousPage = gtk_image_menu_item_new_with_mnemonic ("_Previous Page");
    gtk_widget_show (viewPreviousPage);
    gtk_container_add (GTK_CONTAINER (menuView_menu), viewPreviousPage);
    gtk_widget_add_accelerator (viewPreviousPage, "activate", accel_group,
                                GDK_Left, (GdkModifierType) GDK_CONTROL_MASK,
                                GTK_ACCEL_VISIBLE);
  
!   viewNextPage = gtk_image_menu_item_new_with_mnemonic ("_Next Page");
    gtk_widget_show (viewNextPage);
    gtk_container_add (GTK_CONTAINER (menuView_menu), viewNextPage);
    gtk_widget_add_accelerator (viewNextPage, "activate", accel_group,
                                GDK_Right, (GdkModifierType) GDK_CONTROL_MASK,
                                GTK_ACCEL_VISIBLE);
  
!   viewLastPage = gtk_image_menu_item_new_with_mnemonic ("_Last Page");
    gtk_widget_show (viewLastPage);
    gtk_container_add (GTK_CONTAINER (menuView_menu), viewLastPage);
    gtk_widget_add_accelerator (viewLastPage, "activate", accel_group,
                                GDK_End, (GdkModifierType) GDK_CONTROL_MASK,
                                GTK_ACCEL_VISIBLE);
  
    separator6 = gtk_separator_menu_item_new ();
    gtk_widget_show (separator6);
    gtk_container_add (GTK_CONTAINER (menuView_menu), separator6);
    gtk_widget_set_sensitive (separator6, FALSE);
  
!   viewShowLayer = gtk_image_menu_item_new_with_mnemonic ("_Show Layer");
    gtk_widget_show (viewShowLayer);
    gtk_container_add (GTK_CONTAINER (menuView_menu), viewShowLayer);
  
!   viewHideLayer = gtk_image_menu_item_new_with_mnemonic ("_Hide Layer");
    gtk_widget_show (viewHideLayer);
    gtk_container_add (GTK_CONTAINER (menuView_menu), viewHideLayer);
  
    menuJournal = gtk_menu_item_new_with_mnemonic (_("_Journal"));
    gtk_widget_show (menuJournal);
    gtk_container_add (GTK_CONTAINER (menubar), menuJournal);
***************
*** 808,821 ****
    gtk_container_add (GTK_CONTAINER (menuJournal_menu), separator23);
    gtk_widget_set_sensitive (separator23, FALSE);
  
!   journalLoadBackground = gtk_image_menu_item_new_with_mnemonic (_("_Load Background"));
    gtk_widget_show (journalLoadBackground);
    gtk_container_add (GTK_CONTAINER (menuJournal_menu), journalLoadBackground);
  
-   image632 = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_MENU);
-   gtk_widget_show (image632);
-   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (journalLoadBackground), image632);
- 
    journalScreenshot = gtk_menu_item_new_with_mnemonic (_("Background Screens_hot"));
    gtk_widget_show (journalScreenshot);
    gtk_container_add (GTK_CONTAINER (menuJournal_menu), journalScreenshot);
--- 761,770 ----
    gtk_container_add (GTK_CONTAINER (menuJournal_menu), separator23);
    gtk_widget_set_sensitive (separator23, FALSE);
  
!   journalLoadBackground = gtk_image_menu_item_new_with_mnemonic ("_Load Background");
    gtk_widget_show (journalLoadBackground);
    gtk_container_add (GTK_CONTAINER (menuJournal_menu), journalLoadBackground);
  
    journalScreenshot = gtk_menu_item_new_with_mnemonic (_("Background Screens_hot"));
    gtk_widget_show (journalScreenshot);
    gtk_container_add (GTK_CONTAINER (menuJournal_menu), journalScreenshot);
***************
*** 940,953 ****
    gtk_container_add (GTK_CONTAINER (menuTools_menu), separator16);
    gtk_widget_set_sensitive (separator16, FALSE);
  
!   toolsColor = gtk_image_menu_item_new_with_mnemonic (_("_Color"));
    gtk_widget_show (toolsColor);
    gtk_container_add (GTK_CONTAINER (menuTools_menu), toolsColor);
  
-   image633 = gtk_image_new_from_stock ("gtk-select-color", GTK_ICON_SIZE_MENU);
-   gtk_widget_show (image633);
-   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (toolsColor), image633);
- 
    toolsColor_menu = gtk_menu_new ();
    gtk_menu_item_set_submenu (GTK_MENU_ITEM (toolsColor), toolsColor_menu);
  
--- 889,898 ----
    gtk_container_add (GTK_CONTAINER (menuTools_menu), separator16);
    gtk_widget_set_sensitive (separator16, FALSE);
  
!   toolsColor = gtk_image_menu_item_new_with_mnemonic ("_Color");
    gtk_widget_show (toolsColor);
    gtk_container_add (GTK_CONTAINER (menuTools_menu), toolsColor);
  
    toolsColor_menu = gtk_menu_new ();
    gtk_menu_item_set_submenu (GTK_MENU_ITEM (toolsColor), toolsColor_menu);
  
***************
*** 1141,1157 ****
    gtk_container_add (GTK_CONTAINER (toolsHighlighterOptions_menu), highlighterThick);
    gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (highlighterThick), TRUE);
  
!   toolsTextFont = gtk_image_menu_item_new_with_mnemonic (_("Text _Font..."));
    gtk_widget_show (toolsTextFont);
    gtk_container_add (GTK_CONTAINER (menuTools_menu), toolsTextFont);
    gtk_widget_add_accelerator (toolsTextFont, "activate", accel_group,
                                GDK_F, (GdkModifierType) GDK_CONTROL_MASK | GDK_SHIFT_MASK,
                                GTK_ACCEL_VISIBLE);
  
-   image634 = gtk_image_new_from_stock ("gtk-select-font", GTK_ICON_SIZE_MENU);
-   gtk_widget_show (image634);
-   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (toolsTextFont), image634);
- 
    separator10 = gtk_separator_menu_item_new ();
    gtk_widget_show (separator10);
    gtk_container_add (GTK_CONTAINER (menuTools_menu), separator10);
--- 1086,1098 ----
    gtk_container_add (GTK_CONTAINER (toolsHighlighterOptions_menu), highlighterThick);
    gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (highlighterThick), TRUE);
  
!   toolsTextFont = gtk_image_menu_item_new_with_mnemonic ("Text _Font...");
    gtk_widget_show (toolsTextFont);
    gtk_container_add (GTK_CONTAINER (menuTools_menu), toolsTextFont);
    gtk_widget_add_accelerator (toolsTextFont, "activate", accel_group,
                                GDK_F, (GdkModifierType) GDK_CONTROL_MASK | GDK_SHIFT_MASK,
                                GTK_ACCEL_VISIBLE);
  
    separator10 = gtk_separator_menu_item_new ();
    gtk_widget_show (separator10);
    gtk_container_add (GTK_CONTAINER (menuTools_menu), separator10);
***************
*** 1588,1593 ****
--- 1529,1545 ----
    gtk_radio_tool_button_set_group (GTK_RADIO_TOOL_BUTTON (buttonText), buttonPen_group);
    buttonPen_group = gtk_radio_tool_button_get_group (GTK_RADIO_TOOL_BUTTON (buttonText));
  
+   buttonImage = (GtkWidget*) gtk_radio_tool_button_new (NULL);
+   gtk_tool_button_set_label (GTK_TOOL_BUTTON (buttonImage), _("Image"));
+   tmp_image = gtk_image_new_from_stock ("gtk-orientation-portrait", tmp_toolbar_icon_size);
+   gtk_widget_show (tmp_image);
+   gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (buttonImage), tmp_image);
+   gtk_widget_show (buttonImage);
+   gtk_container_add (GTK_CONTAINER (toolbarPen), buttonImage);
+   gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (buttonImage), tooltips, _("Image"), NULL);
+   gtk_radio_tool_button_set_group (GTK_RADIO_TOOL_BUTTON (buttonImage), buttonPen_group);
+   buttonPen_group = gtk_radio_tool_button_get_group (GTK_RADIO_TOOL_BUTTON (buttonImage));
+ 
    buttonReco = (GtkWidget*) gtk_toggle_tool_button_new ();
    gtk_tool_button_set_label (GTK_TOOL_BUTTON (buttonReco), _("Shape Recognizer"));
    tmp_image = create_pixmap (winMain, "shapes.png");
***************
*** 1669,1675 ****
    gtk_widget_show (tmp_image);
    buttonToolDefault = (GtkWidget*) gtk_tool_button_new (tmp_image, _("Default"));
    gtk_widget_show (buttonToolDefault);
-   gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (buttonToolDefault), FALSE);
    gtk_container_add (GTK_CONTAINER (toolbarPen), buttonToolDefault);
    gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (buttonToolDefault), tooltips, _("Default"), NULL);
  
--- 1621,1626 ----
***************
*** 1694,1700 ****
    gtk_widget_show (tmp_image);
    gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (buttonFine), tmp_image);
    gtk_widget_show (buttonFine);
-   gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (buttonFine), FALSE);
    gtk_container_add (GTK_CONTAINER (toolbarPen), buttonFine);
    gtk_widget_set_size_request (buttonFine, 24, -1);
    gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (buttonFine), tooltips, _("Fine"), NULL);
--- 1645,1650 ----
***************
*** 1707,1713 ****
    gtk_widget_show (tmp_image);
    gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (buttonMedium), tmp_image);
    gtk_widget_show (buttonMedium);
-   gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (buttonMedium), FALSE);
    gtk_container_add (GTK_CONTAINER (toolbarPen), buttonMedium);
    gtk_widget_set_size_request (buttonMedium, 24, -1);
    gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (buttonMedium), tooltips, _("Medium"), NULL);
--- 1657,1662 ----
***************
*** 1720,1726 ****
    gtk_widget_show (tmp_image);
    gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (buttonThick), tmp_image);
    gtk_widget_show (buttonThick);
-   gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (buttonThick), FALSE);
    gtk_container_add (GTK_CONTAINER (toolbarPen), buttonThick);
    gtk_widget_set_size_request (buttonThick, 24, -1);
    gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (buttonThick), tooltips, _("Thick"), NULL);
--- 1669,1674 ----
***************
*** 1747,1753 ****
    gtk_widget_show (tmp_image);
    gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (buttonBlack), tmp_image);
    gtk_widget_show (buttonBlack);
-   gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (buttonBlack), FALSE);
    gtk_container_add (GTK_CONTAINER (toolbarPen), buttonBlack);
    gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (buttonBlack), tooltips, _("Black"), NULL);
    gtk_radio_tool_button_set_group (GTK_RADIO_TOOL_BUTTON (buttonBlack), buttonBlack_group);
--- 1695,1700 ----
***************
*** 1759,1765 ****
    gtk_widget_show (tmp_image);
    gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (buttonBlue), tmp_image);
    gtk_widget_show (buttonBlue);
-   gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (buttonBlue), FALSE);
    gtk_container_add (GTK_CONTAINER (toolbarPen), buttonBlue);
    gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (buttonBlue), tooltips, _("Blue"), NULL);
    gtk_radio_tool_button_set_group (GTK_RADIO_TOOL_BUTTON (buttonBlue), buttonBlack_group);
--- 1706,1711 ----
***************
*** 1771,1777 ****
    gtk_widget_show (tmp_image);
    gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (buttonRed), tmp_image);
    gtk_widget_show (buttonRed);
-   gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (buttonRed), FALSE);
    gtk_container_add (GTK_CONTAINER (toolbarPen), buttonRed);
    gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (buttonRed), tooltips, _("Red"), NULL);
    gtk_radio_tool_button_set_group (GTK_RADIO_TOOL_BUTTON (buttonRed), buttonBlack_group);
--- 1717,1722 ----
***************
*** 1783,1789 ****
    gtk_widget_show (tmp_image);
    gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (buttonGreen), tmp_image);
    gtk_widget_show (buttonGreen);
-   gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (buttonGreen), FALSE);
    gtk_container_add (GTK_CONTAINER (toolbarPen), buttonGreen);
    gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (buttonGreen), tooltips, _("Green"), NULL);
    gtk_radio_tool_button_set_group (GTK_RADIO_TOOL_BUTTON (buttonGreen), buttonBlack_group);
--- 1728,1733 ----
***************
*** 1795,1801 ****
    gtk_widget_show (tmp_image);
    gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (buttonGray), tmp_image);
    gtk_widget_show (buttonGray);
-   gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (buttonGray), FALSE);
    gtk_container_add (GTK_CONTAINER (toolbarPen), buttonGray);
    gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (buttonGray), tooltips, _("Gray"), NULL);
    gtk_radio_tool_button_set_group (GTK_RADIO_TOOL_BUTTON (buttonGray), buttonBlack_group);
--- 1739,1744 ----
***************
*** 1807,1813 ****
    gtk_widget_show (tmp_image);
    gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (buttonLightBlue), tmp_image);
    gtk_widget_show (buttonLightBlue);
-   gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (buttonLightBlue), FALSE);
    gtk_container_add (GTK_CONTAINER (toolbarPen), buttonLightBlue);
    gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (buttonLightBlue), tooltips, _("Light Blue"), NULL);
    gtk_radio_tool_button_set_group (GTK_RADIO_TOOL_BUTTON (buttonLightBlue), buttonBlack_group);
--- 1750,1755 ----
***************
*** 1819,1825 ****
    gtk_widget_show (tmp_image);
    gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (buttonLightGreen), tmp_image);
    gtk_widget_show (buttonLightGreen);
-   gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (buttonLightGreen), FALSE);
    gtk_container_add (GTK_CONTAINER (toolbarPen), buttonLightGreen);
    gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (buttonLightGreen), tooltips, _("Light Green"), NULL);
    gtk_radio_tool_button_set_group (GTK_RADIO_TOOL_BUTTON (buttonLightGreen), buttonBlack_group);
--- 1761,1766 ----
***************
*** 1831,1837 ****
    gtk_widget_show (tmp_image);
    gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (buttonMagenta), tmp_image);
    gtk_widget_show (buttonMagenta);
-   gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (buttonMagenta), FALSE);
    gtk_container_add (GTK_CONTAINER (toolbarPen), buttonMagenta);
    gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (buttonMagenta), tooltips, _("Magenta"), NULL);
    gtk_radio_tool_button_set_group (GTK_RADIO_TOOL_BUTTON (buttonMagenta), buttonBlack_group);
--- 1772,1777 ----
***************
*** 1843,1849 ****
    gtk_widget_show (tmp_image);
    gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (buttonOrange), tmp_image);
    gtk_widget_show (buttonOrange);
-   gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (buttonOrange), FALSE);
    gtk_container_add (GTK_CONTAINER (toolbarPen), buttonOrange);
    gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (buttonOrange), tooltips, _("Orange"), NULL);
    gtk_radio_tool_button_set_group (GTK_RADIO_TOOL_BUTTON (buttonOrange), buttonBlack_group);
--- 1783,1788 ----
***************
*** 1855,1861 ****
    gtk_widget_show (tmp_image);
    gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (buttonYellow), tmp_image);
    gtk_widget_show (buttonYellow);
-   gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (buttonYellow), FALSE);
    gtk_container_add (GTK_CONTAINER (toolbarPen), buttonYellow);
    gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (buttonYellow), tooltips, _("Yellow"), NULL);
    gtk_radio_tool_button_set_group (GTK_RADIO_TOOL_BUTTON (buttonYellow), buttonBlack_group);
--- 1794,1799 ----
***************
*** 1867,1873 ****
    gtk_widget_show (tmp_image);
    gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (buttonWhite), tmp_image);
    gtk_widget_show (buttonWhite);
-   gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (buttonWhite), FALSE);
    gtk_container_add (GTK_CONTAINER (toolbarPen), buttonWhite);
    gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (buttonWhite), tooltips, _("White"), NULL);
    gtk_radio_tool_button_set_group (GTK_RADIO_TOOL_BUTTON (buttonWhite), buttonBlack_group);
--- 1805,1810 ----
***************
*** 2426,2431 ****
--- 2363,2371 ----
    g_signal_connect ((gpointer) buttonText, "toggled",
                      G_CALLBACK (on_toolsText_activate),
                      NULL);
+   g_signal_connect ((gpointer) buttonImage, "toggled",
+                     G_CALLBACK (on_toolsImage_activate),
+                     NULL);
    g_signal_connect ((gpointer) buttonReco, "toggled",
                      G_CALLBACK (on_toolsReco_activate),
                      NULL);
***************
*** 2513,2519 ****
    GLADE_HOOKUP_OBJECT (winMain, menuFile_menu, "menuFile_menu");
    GLADE_HOOKUP_OBJECT (winMain, fileNew, "fileNew");
    GLADE_HOOKUP_OBJECT (winMain, fileNewBackground, "fileNewBackground");
-   GLADE_HOOKUP_OBJECT (winMain, image623, "image623");
    GLADE_HOOKUP_OBJECT (winMain, fileOpen, "fileOpen");
    GLADE_HOOKUP_OBJECT (winMain, fileSave, "fileSave");
    GLADE_HOOKUP_OBJECT (winMain, fileSaveAs, "fileSaveAs");
--- 2453,2458 ----
***************
*** 2530,2536 ****
    GLADE_HOOKUP_OBJECT (winMain, mru7, "mru7");
    GLADE_HOOKUP_OBJECT (winMain, separator22, "separator22");
    GLADE_HOOKUP_OBJECT (winMain, filePrintOptions, "filePrintOptions");
-   GLADE_HOOKUP_OBJECT (winMain, image624, "image624");
    GLADE_HOOKUP_OBJECT (winMain, filePrint, "filePrint");
    GLADE_HOOKUP_OBJECT (winMain, filePrintPDF, "filePrintPDF");
    GLADE_HOOKUP_OBJECT (winMain, separator2, "separator2");
--- 2469,2474 ----
***************
*** 2557,2578 ****
    GLADE_HOOKUP_OBJECT (winMain, viewZoomOut, "viewZoomOut");
    GLADE_HOOKUP_OBJECT (winMain, viewNormalSize, "viewNormalSize");
    GLADE_HOOKUP_OBJECT (winMain, viewPageWidth, "viewPageWidth");
-   GLADE_HOOKUP_OBJECT (winMain, image625, "image625");
    GLADE_HOOKUP_OBJECT (winMain, viewSetZoom, "viewSetZoom");
    GLADE_HOOKUP_OBJECT (winMain, separator5, "separator5");
    GLADE_HOOKUP_OBJECT (winMain, viewFirstPage, "viewFirstPage");
-   GLADE_HOOKUP_OBJECT (winMain, image626, "image626");
    GLADE_HOOKUP_OBJECT (winMain, viewPreviousPage, "viewPreviousPage");
-   GLADE_HOOKUP_OBJECT (winMain, image627, "image627");
    GLADE_HOOKUP_OBJECT (winMain, viewNextPage, "viewNextPage");
-   GLADE_HOOKUP_OBJECT (winMain, image628, "image628");
    GLADE_HOOKUP_OBJECT (winMain, viewLastPage, "viewLastPage");
-   GLADE_HOOKUP_OBJECT (winMain, image629, "image629");
    GLADE_HOOKUP_OBJECT (winMain, separator6, "separator6");
    GLADE_HOOKUP_OBJECT (winMain, viewShowLayer, "viewShowLayer");
-   GLADE_HOOKUP_OBJECT (winMain, image630, "image630");
    GLADE_HOOKUP_OBJECT (winMain, viewHideLayer, "viewHideLayer");
-   GLADE_HOOKUP_OBJECT (winMain, image631, "image631");
    GLADE_HOOKUP_OBJECT (winMain, menuJournal, "menuJournal");
    GLADE_HOOKUP_OBJECT (winMain, menuJournal_menu, "menuJournal_menu");
    GLADE_HOOKUP_OBJECT (winMain, journalNewPageBefore, "journalNewPageBefore");
--- 2495,2509 ----
***************
*** 2605,2611 ****
    GLADE_HOOKUP_OBJECT (winMain, journalApplyAllPages, "journalApplyAllPages");
    GLADE_HOOKUP_OBJECT (winMain, separator23, "separator23");
    GLADE_HOOKUP_OBJECT (winMain, journalLoadBackground, "journalLoadBackground");
-   GLADE_HOOKUP_OBJECT (winMain, image632, "image632");
    GLADE_HOOKUP_OBJECT (winMain, journalScreenshot, "journalScreenshot");
    GLADE_HOOKUP_OBJECT (winMain, separator19, "separator19");
    GLADE_HOOKUP_OBJECT (winMain, journalDefaultBackground, "journalDefaultBackground");
--- 2536,2541 ----
***************
*** 2626,2632 ****
    GLADE_HOOKUP_OBJECT (winMain, toolsHand, "toolsHand");
    GLADE_HOOKUP_OBJECT (winMain, separator16, "separator16");
    GLADE_HOOKUP_OBJECT (winMain, toolsColor, "toolsColor");
-   GLADE_HOOKUP_OBJECT (winMain, image633, "image633");
    GLADE_HOOKUP_OBJECT (winMain, toolsColor_menu, "toolsColor_menu");
    GLADE_HOOKUP_OBJECT (winMain, colorBlack, "colorBlack");
    GLADE_HOOKUP_OBJECT (winMain, colorBlue, "colorBlue");
--- 2556,2561 ----
***************
*** 2664,2670 ****
    GLADE_HOOKUP_OBJECT (winMain, highlighterMedium, "highlighterMedium");
    GLADE_HOOKUP_OBJECT (winMain, highlighterThick, "highlighterThick");
    GLADE_HOOKUP_OBJECT (winMain, toolsTextFont, "toolsTextFont");
-   GLADE_HOOKUP_OBJECT (winMain, image634, "image634");
    GLADE_HOOKUP_OBJECT (winMain, separator10, "separator10");
    GLADE_HOOKUP_OBJECT (winMain, toolsDefaultPen, "toolsDefaultPen");
    GLADE_HOOKUP_OBJECT (winMain, toolsDefaultEraser, "toolsDefaultEraser");
--- 2593,2598 ----
***************
*** 2750,2755 ****
--- 2678,2684 ----
    GLADE_HOOKUP_OBJECT (winMain, buttonEraser, "buttonEraser");
    GLADE_HOOKUP_OBJECT (winMain, buttonHighlighter, "buttonHighlighter");
    GLADE_HOOKUP_OBJECT (winMain, buttonText, "buttonText");
+   GLADE_HOOKUP_OBJECT (winMain, buttonImage, "buttonImage");
    GLADE_HOOKUP_OBJECT (winMain, buttonReco, "buttonReco");
    GLADE_HOOKUP_OBJECT (winMain, buttonRuler, "buttonRuler");
    GLADE_HOOKUP_OBJECT (winMain, toolitem15, "toolitem15");
***************
*** 2860,2865 ****
--- 2789,2795 ----
    entryWidth = gtk_entry_new ();
    gtk_widget_show (entryWidth);
    gtk_box_pack_start (GTK_BOX (hbox3), entryWidth, TRUE, TRUE, 0);
+   gtk_entry_set_invisible_char (GTK_ENTRY (entryWidth), 9679);
    gtk_entry_set_width_chars (GTK_ENTRY (entryWidth), 5);
  
    labelHeight = gtk_label_new (_("Height:"));
***************
*** 2869,2874 ****
--- 2799,2805 ----
    entryHeight = gtk_entry_new ();
    gtk_widget_show (entryHeight);
    gtk_box_pack_start (GTK_BOX (hbox3), entryHeight, TRUE, TRUE, 0);
+   gtk_entry_set_invisible_char (GTK_ENTRY (entryHeight), 9679);
    gtk_entry_set_width_chars (GTK_ENTRY (entryHeight), 5);
  
    comboUnit = gtk_combo_box_new_text ();
***************
*** 2951,2962 ****
    labelTitle = gtk_label_new (_("Xournal"));
    gtk_widget_show (labelTitle);
    gtk_box_pack_start (GTK_BOX (dialog_vbox2), labelTitle, FALSE, FALSE, 3);
-   gtk_label_set_justify (GTK_LABEL (labelTitle), GTK_JUSTIFY_CENTER);
  
    labelInfo = gtk_label_new (_("Written by Denis Auroux\nand other contributors\n       http://xournal.sourceforge.net/       "));
    gtk_widget_show (labelInfo);
    gtk_box_pack_start (GTK_BOX (dialog_vbox2), labelInfo, FALSE, FALSE, 0);
-   gtk_label_set_justify (GTK_LABEL (labelInfo), GTK_JUSTIFY_CENTER);
    gtk_misc_set_padding (GTK_MISC (labelInfo), 20, 10);
  
    dialog_action_area2 = GTK_DIALOG (aboutDialog)->action_area;
--- 2882,2891 ----
diff -c 'xournal-0.4.5/src/xo-misc.c' 'xournal/src/xo-misc.c'
Index: ./src/xo-misc.c
*** ./src/xo-misc.c	Fri Oct  2 20:20:30 2009
--- ./src/xo-misc.c	Thu Jul 29 16:11:24 2010
***************
*** 17,22 ****
--- 17,23 ----
  #include "xo-file.h"
  #include "xo-paint.h"
  #include "xo-shapes.h"
+ #include "xo-image.h"
  
  // some global constants
  
***************
*** 90,95 ****
--- 91,121 ----
    return pg;
  }
  
+ // change the current page if necessary for pointer at pt
+ void set_current_page(gdouble *pt)
+ {
+   gboolean page_change;
+   struct Page *tmppage;
+ 
+   page_change = FALSE;
+   tmppage = ui.cur_page;
+   while (ui.view_continuous && (pt[1] < - VIEW_CONTINUOUS_SKIP)) {
+     if (ui.pageno == 0) break;
+     page_change = TRUE;
+     ui.pageno--;
+     tmppage = g_list_nth_data(journal.pages, ui.pageno);
+     pt[1] += tmppage->height + VIEW_CONTINUOUS_SKIP;
+   }
+   while (ui.view_continuous && (pt[1] > tmppage->height + VIEW_CONTINUOUS_SKIP)) {
+     if (ui.pageno == journal.npages-1) break;
+     pt[1] -= tmppage->height + VIEW_CONTINUOUS_SKIP;
+     page_change = TRUE;
+     ui.pageno++;
+     tmppage = g_list_nth_data(journal.pages, ui.pageno);
+   }
+   if (page_change) do_switch_page(ui.pageno, FALSE, FALSE);
+ }
+ 
  void realloc_cur_path(int n)
  {
    if (n <= ui.cur_path_storage_alloc) return;
***************
*** 142,147 ****
--- 168,179 ----
        g_free(redo->item->font_name);
        g_free(redo->item);
      }
+     else if (redo->type == ITEM_IMAGE) {
+       g_object_unref(redo->item->image);
+       if (redo->item->image_scaled != NULL) g_object_unref(redo->item->image_scaled);
+       g_free(redo->item->image_png);
+       g_free(redo->item);
+     }
      else if (redo->type == ITEM_ERASURE || redo->type == ITEM_RECOGNIZER) {
        for (list = redo->erasurelist; list!=NULL; list=list->next) {
          erasure = (struct UndoErasureData *)list->data;
***************
*** 218,223 ****
--- 250,260 ----
          }
          if (erasure->item->type == ITEM_TEXT)
            { g_free(erasure->item->text); g_free(erasure->item->font_name); }
+ 	if (erasure->item->type == ITEM_IMAGE) {
+           g_object_unref(erasure->item->image);
+           if (erasure->item->image_scaled != NULL) g_object_unref(erasure->item->image_scaled);
+           g_free(erasure->item->image_png);
+         }
          g_free(erasure->item);
          g_list_free(erasure->replacement_items);
          g_free(erasure);
***************
*** 302,307 ****
--- 339,349 ----
      if (item->type == ITEM_TEXT) {
        g_free(item->font_name); g_free(item->text);
      }
+     if (item->type == ITEM_IMAGE) {
+       g_object_unref(item->image);
+       if (item->image_scaled != NULL) g_object_unref(item->image_scaled);
+       g_free(item->image_png);
+     }
      // don't need to delete the canvas_item, as it's part of the group destroyed below
      g_free(item);
      l->items = g_list_delete_link(l->items, l->items);
***************
*** 350,355 ****
--- 392,409 ----
    ret[1] -= ui.cur_page->voffset;
  }
  
+ // get the current pointer position in canvas world coordinates
+ void get_current_pointer_coords(gdouble *ret)
+ {
+   gint wx, wy, sx, sy;
+ 
+   gtk_widget_get_pointer((GtkWidget *)canvas, &wx, &wy);
+   gnome_canvas_get_scroll_offsets(canvas, &sx, &sy);
+   gnome_canvas_window_to_world(canvas, (double)(wx + sx), (double)(wy + sy), ret, ret+1);
+   ret[0] -= ui.cur_page->hoffset;
+   ret[1] -= ui.cur_page->voffset;
+ }
+ 
  void fix_xinput_coords(GdkEvent *event)
  {
    double *axes, *px, *py, axis_width;
***************
*** 440,446 ****
  {
    int i;
    gdouble *p, h, w;
!   
    if (item->type == ITEM_STROKE) {
      item->bbox.left = item->bbox.right = item->path->coords[0];
      item->bbox.top = item->bbox.bottom = item->path->coords[1];
--- 494,501 ----
  {
    int i;
    gdouble *p, h, w;
!   gboolean width_in_pixels, height_in_pixels;
! 
    if (item->type == ITEM_STROKE) {
      item->bbox.left = item->bbox.right = item->path->coords[0];
      item->bbox.top = item->bbox.bottom = item->path->coords[1];
***************
*** 458,463 ****
--- 513,534 ----
      item->bbox.right = item->bbox.left + w;
      item->bbox.bottom = item->bbox.top + h;
    }
+   if (item->type == ITEM_IMAGE && item->canvas_item!=NULL) {
+     // be careful in case canvas item size in pixels
+     h=0.; w=0.;
+     g_object_get(item->canvas_item, "width", &w, "height", &h, 
+                  "width-in-pixels", &width_in_pixels,
+                  "height-in-pixels", &height_in_pixels,
+                  NULL);
+     if (width_in_pixels) {
+       w /= ui.zoom;
+     }
+     if (height_in_pixels) {
+       h /= ui.zoom;
+     }
+     item->bbox.right = item->bbox.left + w;
+     item->bbox.bottom = item->bbox.top + h;
+   }
  }
  
  void make_page_clipbox(struct Page *pg)
***************
*** 474,483 ****
--- 545,640 ----
    gnome_canvas_path_def_unref(pg_clip);
  }
  
+ void adjust_or_make_canvas_item_image(GnomeCanvasGroup *group, struct Item *item)
+ {
+   double required_width;
+   double required_height;
+ 
+   // discard previous scaled image, if any
+   if ( item->image_scaled != NULL ) {
+     g_object_unref(item->image_scaled);
+     item->image_scaled = NULL;
+   }
+ 
+   if ( is_native_image_usable( item ) ) {
+     // use native resolution, for sharper image
+     if (item->canvas_item == NULL) {
+       // first time, create new canvas item
+       item->canvas_item = gnome_canvas_item_new(group,
+                                                 GNOME_TYPE_CANVAS_PIXBUF,
+                                                 "anchor", GTK_ANCHOR_NW,
+                                                 "height-in-pixels", TRUE, 
+                                                 "width-in-pixels", TRUE,
+                                                 "x-in-pixels", FALSE,
+                                                 "y-in-pixels", FALSE,
+                                                 "pixbuf", item->image,
+                                                 "x", item->bbox.left, 
+                                                 "y", item->bbox.top,
+                                                 "height", (double)gdk_pixbuf_get_height(item->image),
+                                                 "width", (double)gdk_pixbuf_get_width(item->image),
+                                                 NULL);
+     } else {
+       // update the existing one, which may have been for a scaled image
+       gnome_canvas_item_set(item->canvas_item,
+                             "height-in-pixels", TRUE, 
+                             "width-in-pixels", TRUE,
+                             "pixbuf", item->image,
+                             "height", (double)gdk_pixbuf_get_height(item->image),
+                             "width", (double)gdk_pixbuf_get_width(item->image),
+                             NULL);
+     }
+   } else {
+     // settle for scaled (and blurry) image
+     required_width = item->bbox.right - item->bbox.left;
+     required_height = item->bbox.bottom - item->bbox.top;
+ 
+     item->image_scaled = gdk_pixbuf_scale_simple(item->image,
+                                                  required_width,
+                                                  required_height,
+                                                  GDK_INTERP_HYPER);
+     if (item->canvas_item == NULL) {
+       // first time, create new canvas item
+       item->canvas_item = gnome_canvas_item_new(group,
+                                                 GNOME_TYPE_CANVAS_PIXBUF,
+                                                 "anchor", GTK_ANCHOR_NW,
+                                                 "height-in-pixels", FALSE,
+                                                 "width-in-pixels", FALSE,
+                                                 "x-in-pixels", FALSE,
+                                                 "y-in-pixels", FALSE,
+                                                 "pixbuf", item->image_scaled,
+                                                 "x", item->bbox.left, 
+                                                 "y", item->bbox.top,
+                                                 "height", required_height,
+                                                 "width", required_width,  
+                                                 NULL);
+     } else {
+       // update the existing one, which may have been for a scaled image
+       gnome_canvas_item_set(item->canvas_item,
+                             "height-in-pixels", FALSE,
+                             "width-in-pixels", FALSE,
+                             "pixbuf", item->image_scaled,
+                             "height", required_height,
+                             "width", required_width,  
+                             NULL);
+     }
+   }
+ 
+   // reposition the canvas item absolutely, and reset the affine transformation
+   gnome_canvas_item_affine_absolute(item->canvas_item, NULL);
+   gnome_canvas_item_set(item->canvas_item,
+                         "x", item->bbox.left, 
+                         "y", item->bbox.top,
+                         NULL);
+ }
+ 
  void make_canvas_item_one(GnomeCanvasGroup *group, struct Item *item)
  {
    PangoFontDescription *font_desc;
    GnomeCanvasPoints points;
+   GtkFileFilter *filt_all;
+   GtkFileFilter *filt_gdkimage;
+   GtkWidget *dialog;
+   char *tmp_filename;
    int j;
  
    if (item->type == ITEM_STROKE) {
***************
*** 513,518 ****
--- 670,678 ----
            "text", item->text, NULL);
      update_item_bbox(item);
    }
+   if (item->type == ITEM_IMAGE) {
+     adjust_or_make_canvas_item_image(group, item);
+   }
  }
  
  void make_canvas_items(void)
***************
*** 861,866 ****
--- 1021,1031 ----
        gtk_toggle_tool_button_set_active(
          GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonText")), TRUE);
        break;
+     
+     case TOOL_IMAGE:
+       gtk_toggle_tool_button_set_active(
+         GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonImage")), TRUE);
+       break;
      case TOOL_SELECTREGION:
        gtk_toggle_tool_button_set_active(
          GTK_TOGGLE_TOOL_BUTTON(GET_COMPONENT("buttonSelectRegion")), TRUE);
***************
*** 1377,1383 ****
    gtk_widget_set_sensitive(GET_COMPONENT("viewHideLayer"), ui.layerno>=0);
  
    gtk_widget_set_sensitive(GET_COMPONENT("editPaste"), ui.cur_layer!=NULL);
!   gtk_widget_set_sensitive(GET_COMPONENT("buttonPaste"), ui.cur_layer!=NULL);
  }
  
  void update_toolbar_and_menu(void)
--- 1542,1549 ----
    gtk_widget_set_sensitive(GET_COMPONENT("viewHideLayer"), ui.layerno>=0);
  
    gtk_widget_set_sensitive(GET_COMPONENT("editPaste"), ui.cur_layer!=NULL);
! 
! gtk_widget_set_sensitive(GET_COMPONENT("buttonPaste"), ui.cur_layer!=NULL);
  }
  
  void update_toolbar_and_menu(void)
***************
*** 1716,1722 ****
      if (item->type == ITEM_STROKE)
        for (pt=item->path->coords, i=0; i<item->path->num_points; i++, pt+=2)
          { pt[0] += dx; pt[1] += dy; }
!     if (item->type == ITEM_STROKE || item->type == ITEM_TEXT || item->type == ITEM_TEMP_TEXT) {
        item->bbox.left += dx;
        item->bbox.right += dx;
        item->bbox.top += dy;
--- 1882,1888 ----
      if (item->type == ITEM_STROKE)
        for (pt=item->path->coords, i=0; i<item->path->num_points; i++, pt+=2)
          { pt[0] += dx; pt[1] += dy; }
!     if (item->type == ITEM_STROKE || item->type == ITEM_TEXT || item->type == ITEM_TEMP_TEXT || item->type==ITEM_IMAGE) {
        item->bbox.left += dx;
        item->bbox.right += dx;
        item->bbox.top += dy;
***************
*** 1799,1809 ****
        item->bbox.left = item->bbox.left*scaling_x + offset_x;
        item->bbox.top = item->bbox.top*scaling_y + offset_y;
      }
      // redraw the item
      if (item->canvas_item!=NULL) {
        group = (GnomeCanvasGroup *) item->canvas_item->parent;
!       gtk_object_destroy(GTK_OBJECT(item->canvas_item));
!       make_canvas_item_one(group, item);
      }
    }
  }
--- 1965,1995 ----
        item->bbox.left = item->bbox.left*scaling_x + offset_x;
        item->bbox.top = item->bbox.top*scaling_y + offset_y;
      }
+     if (item->type == ITEM_IMAGE) {
+       item->bbox.left = item->bbox.left*scaling_x + offset_x;
+       item->bbox.right = item->bbox.right*scaling_x + offset_x;
+       item->bbox.top = item->bbox.top*scaling_y + offset_y;
+       item->bbox.bottom = item->bbox.bottom*scaling_y + offset_y;
+       if (item->bbox.left > item->bbox.right) {
+         temp = item->bbox.left;
+         item->bbox.left = item->bbox.right;
+         item->bbox.right = temp;
+       }
+       if (item->bbox.top > item->bbox.bottom) {
+         temp = item->bbox.top;
+         item->bbox.top = item->bbox.bottom;
+         item->bbox.bottom = temp;
+       }
+     }
      // redraw the item
      if (item->canvas_item!=NULL) {
        group = (GnomeCanvasGroup *) item->canvas_item->parent;
!       if (item->type == ITEM_IMAGE) {
!         adjust_or_make_canvas_item_image(group, item);
!       } else {
!         gtk_object_destroy(GTK_OBJECT(item->canvas_item));
!         make_canvas_item_one(group, item);
!       }
      }
    }
  }
diff -c 'xournal-0.4.5/src/xo-misc.h' 'xournal/src/xo-misc.h'
Index: ./src/xo-misc.h
*** ./src/xo-misc.h	Mon Sep 28 16:45:56 2009
--- ./src/xo-misc.h	Sun Jun 27 16:18:01 2010
***************
*** 2,7 ****
--- 2,8 ----
  
  struct Page *new_page(struct Page *template);
  struct Page *new_page_with_bg(struct Background *bg, double width, double height);
+ void set_current_page(gdouble *pt);
  void realloc_cur_path(int n);
  void realloc_cur_widths(int n);
  void clear_redo_stack(void);
***************
*** 20,30 ****
--- 21,33 ----
  // helper functions
  
  void get_pointer_coords(GdkEvent *event, double *ret);
+ void get_current_pointer_coords(double *ret);
  double get_pressure_multiplier(GdkEvent *event);
  void fix_xinput_coords(GdkEvent *event);
  void update_item_bbox(struct Item *item);
  void make_page_clipbox(struct Page *pg);
  void make_canvas_items(void);
+ void adjust_or_make_canvas_item_image(GnomeCanvasGroup *group, struct Item *item);
  void make_canvas_item_one(GnomeCanvasGroup *group, struct Item *item);
  void update_canvas_bg(struct Page *pg);
  gboolean is_visible(struct Page *pg);
diff -c 'xournal-0.4.5/src/xo-paint.c' 'xournal/src/xo-paint.c'
Index: ./src/xo-paint.c
*** ./src/xo-paint.c	Mon Sep 28 09:54:18 2009
--- ./src/xo-paint.c	Thu Jul 29 16:01:42 2010
***************
*** 879,1089 ****
       the forward direction */
  }
  
- void callback_clipboard_get(GtkClipboard *clipboard,
-                             GtkSelectionData *selection_data,
-                             guint info, gpointer user_data)
- {
-   int length;
-   
-   g_memmove(&length, user_data, sizeof(int));
-   gtk_selection_data_set(selection_data,
-      gdk_atom_intern("_XOURNAL", FALSE), 8, user_data, length);
- }
- 
- void callback_clipboard_clear(GtkClipboard *clipboard, gpointer user_data)
- {
-   g_free(user_data);
- }
- 
- void selection_to_clip(void)
- {
-   int bufsz, nitems, val;
-   char *buf, *p;
-   GList *list;
-   struct Item *item;
-   GtkTargetEntry target;
-   
-   if (ui.selection == NULL) return;
-   bufsz = 2*sizeof(int) // bufsz, nitems
-         + sizeof(struct BBox); // bbox
-   nitems = 0;
-   for (list = ui.selection->items; list != NULL; list = list->next) {
-     item = (struct Item *)list->data;
-     nitems++;
-     if (item->type == ITEM_STROKE) {
-       bufsz+= sizeof(int) // type
-             + sizeof(struct Brush) // brush
-             + sizeof(int) // num_points
-             + 2*item->path->num_points*sizeof(double); // the points
-       if (item->brush.variable_width)
-         bufsz += (item->path->num_points-1)*sizeof(double); // the widths
-     }
-     else if (item->type == ITEM_TEXT) {
-       bufsz+= sizeof(int) // type
-             + sizeof(struct Brush) // brush
-             + 2*sizeof(double) // bbox upper-left
-             + sizeof(int) // text len
-             + strlen(item->text)+1 // text
-             + sizeof(int) // font_name len
-             + strlen(item->font_name)+1 // font_name
-             + sizeof(double); // font_size
-     }
-     else bufsz+= sizeof(int); // type
-   }
-   p = buf = g_malloc(bufsz);
-   g_memmove(p, &bufsz, sizeof(int)); p+= sizeof(int);
-   g_memmove(p, &nitems, sizeof(int)); p+= sizeof(int);
-   g_memmove(p, &ui.selection->bbox, sizeof(struct BBox)); p+= sizeof(struct BBox);
-   for (list = ui.selection->items; list != NULL; list = list->next) {
-     item = (struct Item *)list->data;
-     g_memmove(p, &item->type, sizeof(int)); p+= sizeof(int);
-     if (item->type == ITEM_STROKE) {
-       g_memmove(p, &item->brush, sizeof(struct Brush)); p+= sizeof(struct Brush);
-       g_memmove(p, &item->path->num_points, sizeof(int)); p+= sizeof(int);
-       g_memmove(p, item->path->coords, 2*item->path->num_points*sizeof(double));
-       p+= 2*item->path->num_points*sizeof(double);
-       if (item->brush.variable_width) {
-         g_memmove(p, item->widths, (item->path->num_points-1)*sizeof(double));
-         p+= (item->path->num_points-1)*sizeof(double);
-       }
-     }
-     if (item->type == ITEM_TEXT) {
-       g_memmove(p, &item->brush, sizeof(struct Brush)); p+= sizeof(struct Brush);
-       g_memmove(p, &item->bbox.left, sizeof(double)); p+= sizeof(double);
-       g_memmove(p, &item->bbox.top, sizeof(double)); p+= sizeof(double);
-       val = strlen(item->text);
-       g_memmove(p, &val, sizeof(int)); p+= sizeof(int);
-       g_memmove(p, item->text, val+1); p+= val+1;
-       val = strlen(item->font_name);
-       g_memmove(p, &val, sizeof(int)); p+= sizeof(int);
-       g_memmove(p, item->font_name, val+1); p+= val+1;
-       g_memmove(p, &item->font_size, sizeof(double)); p+= sizeof(double);
-     }
-   }
-   
-   target.target = "_XOURNAL";
-   target.flags = 0;
-   target.info = 0;
-   
-   gtk_clipboard_set_with_data(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), 
-        &target, 1,
-        callback_clipboard_get, callback_clipboard_clear, buf);
- }
- 
- 
- void clipboard_paste(void)
- {
-   GtkSelectionData *sel_data;
-   unsigned char *p;
-   int nitems, npts, i, len;
-   struct Item *item;
-   double hoffset, voffset, cx, cy;
-   double *pf;
-   int sx, sy, wx, wy;
-   
-   if (ui.cur_layer == NULL) return;
-   
-   ui.cur_item_type = ITEM_PASTE;
-   sel_data = gtk_clipboard_wait_for_contents(
-       gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
-       gdk_atom_intern("_XOURNAL", FALSE));
-   ui.cur_item_type = ITEM_NONE;
-   if (sel_data == NULL) return; // paste failed
-   
-   reset_selection();
-   
-   ui.selection = g_new(struct Selection, 1);
-   p = sel_data->data + sizeof(int);
-   g_memmove(&nitems, p, sizeof(int)); p+= sizeof(int);
-   ui.selection->type = ITEM_SELECTRECT;
-   ui.selection->layer = ui.cur_layer;
-   g_memmove(&ui.selection->bbox, p, sizeof(struct BBox)); p+= sizeof(struct BBox);
-   ui.selection->items = NULL;
-   
-   // find by how much we translate the pasted selection
-   gnome_canvas_get_scroll_offsets(canvas, &sx, &sy);
-   gdk_window_get_geometry(GTK_WIDGET(canvas)->window, NULL, NULL, &wx, &wy, NULL);
-   gnome_canvas_window_to_world(canvas, sx + wx/2, sy + wy/2, &cx, &cy);
-   cx -= ui.cur_page->hoffset;
-   cy -= ui.cur_page->voffset;
-   if (cx + (ui.selection->bbox.right-ui.selection->bbox.left)/2 > ui.cur_page->width)
-     cx = ui.cur_page->width - (ui.selection->bbox.right-ui.selection->bbox.left)/2;
-   if (cx - (ui.selection->bbox.right-ui.selection->bbox.left)/2 < 0)
-     cx = (ui.selection->bbox.right-ui.selection->bbox.left)/2;
-   if (cy + (ui.selection->bbox.bottom-ui.selection->bbox.top)/2 > ui.cur_page->height)
-     cy = ui.cur_page->height - (ui.selection->bbox.bottom-ui.selection->bbox.top)/2;
-   if (cy - (ui.selection->bbox.bottom-ui.selection->bbox.top)/2 < 0)
-     cy = (ui.selection->bbox.bottom-ui.selection->bbox.top)/2;
-   hoffset = cx - (ui.selection->bbox.right+ui.selection->bbox.left)/2;
-   voffset = cy - (ui.selection->bbox.top+ui.selection->bbox.bottom)/2;
-   ui.selection->bbox.left += hoffset;
-   ui.selection->bbox.right += hoffset;
-   ui.selection->bbox.top += voffset;
-   ui.selection->bbox.bottom += voffset;
- 
-   ui.selection->canvas_item = gnome_canvas_item_new(ui.cur_layer->group,
-       gnome_canvas_rect_get_type(), "width-pixels", 1,
-       "outline-color-rgba", 0x000000ff,
-       "fill-color-rgba", 0x80808040,
-       "x1", ui.selection->bbox.left, "x2", ui.selection->bbox.right, 
-       "y1", ui.selection->bbox.top, "y2", ui.selection->bbox.bottom, NULL);
-   make_dashed(ui.selection->canvas_item);
- 
-   while (nitems-- > 0) {
-     item = g_new(struct Item, 1);
-     ui.selection->items = g_list_append(ui.selection->items, item);
-     ui.cur_layer->items = g_list_append(ui.cur_layer->items, item);
-     ui.cur_layer->nitems++;
-     g_memmove(&item->type, p, sizeof(int)); p+= sizeof(int);
-     if (item->type == ITEM_STROKE) {
-       g_memmove(&item->brush, p, sizeof(struct Brush)); p+= sizeof(struct Brush);
-       g_memmove(&npts, p, sizeof(int)); p+= sizeof(int);
-       item->path = gnome_canvas_points_new(npts);
-       pf = (double *)p;
-       for (i=0; i<npts; i++) {
-         item->path->coords[2*i] = pf[2*i] + hoffset;
-         item->path->coords[2*i+1] = pf[2*i+1] + voffset;
-       }
-       p+= 2*item->path->num_points*sizeof(double);
-       if (item->brush.variable_width) {
-         item->widths = g_memdup(p, (item->path->num_points-1)*sizeof(double));
-         p+= (item->path->num_points-1)*sizeof(double);
-       }
-       else item->widths = NULL;
-       update_item_bbox(item);
-       make_canvas_item_one(ui.cur_layer->group, item);
-     }
-     if (item->type == ITEM_TEXT) {
-       g_memmove(&item->brush, p, sizeof(struct Brush)); p+= sizeof(struct Brush);
-       g_memmove(&item->bbox.left, p, sizeof(double)); p+= sizeof(double);
-       g_memmove(&item->bbox.top, p, sizeof(double)); p+= sizeof(double);
-       item->bbox.left += hoffset;
-       item->bbox.top += voffset;
-       g_memmove(&len, p, sizeof(int)); p+= sizeof(int);
-       item->text = g_malloc(len+1);
-       g_memmove(item->text, p, len+1); p+= len+1;
-       g_memmove(&len, p, sizeof(int)); p+= sizeof(int);
-       item->font_name = g_malloc(len+1);
-       g_memmove(item->font_name, p, len+1); p+= len+1;
-       g_memmove(&item->font_size, p, sizeof(double)); p+= sizeof(double);
-       make_canvas_item_one(ui.cur_layer->group, item);
-     }
-   }
- 
-   prepare_new_undo();
-   undo->type = ITEM_PASTE;
-   undo->layer = ui.cur_layer;
-   undo->itemlist = g_list_copy(ui.selection->items);  
-   
-   gtk_selection_data_free(sel_data);
-   update_copy_paste_enabled();
-   update_color_menu();
-   update_thickness_buttons();
-   update_color_buttons();
-   update_font_button();  
-   update_cursor(); // FIXME: can't know if pointer is within selection!
- }
- 
  // modify the color or thickness of pen strokes in a selection
  
  void recolor_selection(int color_no, guint color_rgba)
--- 879,884 ----
diff -c 'xournal-0.4.5/src/xo-paint.h' 'xournal/src/xo-paint.h'
Index: ./src/xo-paint.h
*** ./src/xo-paint.h	Thu Sep 17 16:49:04 2009
--- ./src/xo-paint.h	Thu Apr 15 16:25:13 2010
***************
*** 22,29 ****
  void finalize_resizesel(void);
  
  void selection_delete(void);
- void selection_to_clip(void);
- void clipboard_paste(void);
  
  void recolor_selection(int color_no, guint color_rgba);
  void rethicken_selection(int val);
--- 22,27 ----
diff -c 'xournal-0.4.5/src/xo-print.c' 'xournal/src/xo-print.c'
Index: ./src/xo-print.c
*** ./src/xo-print.c	Tue Sep 29 10:36:54 2009
--- ./src/xo-print.c	Thu Jul 29 16:31:20 2010
***************
*** 772,777 ****
--- 772,851 ----
    return xref->last;
  }
  
+ gboolean pdf_draw_image(PdfImage *image, struct XrefTable *xref, GString *pdfbuf)
+ {
+   char *buf, *p1, *p2;
+   int height, width, stride, x, y, chan;
+   GString *zpix;
+ 
+   if (gdk_pixbuf_get_bits_per_sample(image->pixbuf) != 8 ||
+       gdk_pixbuf_get_colorspace(image->pixbuf) != GDK_COLORSPACE_RGB) {
+     return FALSE;
+   }
+ 
+   width = gdk_pixbuf_get_width(image->pixbuf);
+   height = gdk_pixbuf_get_height(image->pixbuf);
+   stride = gdk_pixbuf_get_rowstride(image->pixbuf);
+   chan = gdk_pixbuf_get_n_channels(image->pixbuf);
+   if (!((chan==3 && !image->has_alpha) || (chan==4 && image->has_alpha))) {
+     return FALSE;
+   }
+ 
+   p2 = buf = (char *)g_malloc(3*width*height);
+   for (y=0; y<height; y++) {
+     p1 = (char *)gdk_pixbuf_get_pixels(image->pixbuf)+stride*y;
+     for (x=0; x<width; x++) {
+       *(p2++)=*(p1++); *(p2++)=*(p1++); *(p2++)=*(p1++);
+       if (chan==4) p1++;
+     }
+   }
+   zpix = do_deflate(buf, 3*width*height);
+   g_free(buf);
+ 
+   xref->data[image->n_obj] = pdfbuf->len;
+   g_string_append_printf(pdfbuf, 
+     "%d 0 obj\n<< /Length %d /Filter /FlateDecode /Type /Xobject "
+     "/Subtype /Image /Width %d /Height %d /ColorSpace /DeviceRGB "
+     "/BitsPerComponent 8 ",
+     image->n_obj, zpix->len, width, height);
+   if (image->has_alpha) {
+     g_string_append_printf(pdfbuf, 
+       "/SMask %d 0 R ",
+       image->n_obj_smask);
+   }
+   g_string_append_printf(pdfbuf, " >> stream\n");
+ 
+   g_string_append_len(pdfbuf, zpix->str, zpix->len);
+   g_string_free(zpix, TRUE);
+   g_string_append(pdfbuf, "endstream\nendobj\n");
+ 
+   if (image->has_alpha) {
+     p2 = buf = (char *)g_malloc(width*height);
+     for (y=0; y<height; y++) {
+       p1 = (char *)gdk_pixbuf_get_pixels(image->pixbuf)+stride*y;
+       for (x=0; x<width; x++) {
+         p1+=3;                  /* skip the RGB */
+         *(p2++)=*(p1++);        /* just copy the alpha */
+       }
+     }
+     zpix = do_deflate(buf, width*height);
+     g_free(buf);
+     
+     xref->data[image->n_obj_smask] = pdfbuf->len;
+     g_string_append_printf(pdfbuf, 
+       "%d 0 obj\n<< /Length %d /Filter /FlateDecode /Type /Xobject "
+       "/Subtype /Image /Width %d /Height %d /ColorSpace /DeviceGray "
+       "/BitsPerComponent 8 >> stream\n",
+       image->n_obj_smask, zpix->len, width, height);
+ 
+     g_string_append_len(pdfbuf, zpix->str, zpix->len);
+     g_string_free(zpix, TRUE);
+     g_string_append(pdfbuf, "endstream\nendobj\n");
+   }
+ 
+   return TRUE;
+ }
+ 
  // manipulate Pdf fonts
  
  struct PdfFont *new_pdffont(struct XrefTable *xref, GList **fonts,
***************
*** 1006,1015 ****
    g_string_append(pdfbuf, ">> endobj\n");
  }
  
  // draw a page's graphics
  
  void pdf_draw_page(struct Page *pg, GString *str, gboolean *use_hiliter, 
!                   struct XrefTable *xref, GList **pdffonts)
  {
    GList *layerlist, *itemlist, *tmplist;
    struct Layer *l;
--- 1080,1110 ----
    g_string_append(pdfbuf, ">> endobj\n");
  }
  
+ // Pdf images
+ 
+ struct PdfImage *new_pdfimage(struct XrefTable *xref, GList **images, GdkPixbuf *pixbuf)
+ {
+   GList *list;
+   struct PdfImage *image;
+   
+   image = g_malloc(sizeof(struct PdfImage));
+   *images = g_list_append(*images, image);
+   image->n_obj = xref->last+1;
+   make_xref(xref, xref->last+1, 0); // will give it a value later
+   image->has_alpha = gdk_pixbuf_get_has_alpha(pixbuf);
+   if (image->has_alpha) {
+     image->n_obj_smask = xref->last+1;
+     make_xref(xref, xref->last+1, 0); // will give it a value later
+   }
+   image->pixbuf = pixbuf;
+ 
+   return image;
+ }
+ 
  // draw a page's graphics
  
  void pdf_draw_page(struct Page *pg, GString *str, gboolean *use_hiliter, 
!                    struct XrefTable *xref, GList **pdffonts, GList **pdfimages)
  {
    GList *layerlist, *itemlist, *tmplist;
    struct Layer *l;
***************
*** 1034,1039 ****
--- 1129,1135 ----
    int font_id;
    FT_Face ftface;
    struct PdfFont *cur_font;
+   struct PdfImage *cur_image;
    gboolean in_string;
    
    old_rgba = old_text_rgba = 0x12345678;    // not any values we use, so we'll reset them
***************
*** 1161,1166 ****
--- 1257,1272 ----
          pango_layout_iter_free(iter);
          g_object_unref(layout);
        }
+       else if  (item->type == ITEM_IMAGE) {
+         cur_image = new_pdfimage(xref, pdfimages, item->image);
+         g_string_append_printf(str, "\nq 1 0 0 1 %.2f %.2f cm %.2f 0 0 %.2f 0 %.2f cm /Im%d Do Q ",
+                                item->bbox.left, // translation
+                                item->bbox.top,
+                                item->bbox.right - item->bbox.left, // scaling
+                                item->bbox.top - item->bbox.bottom,
+                                item->bbox.bottom - item->bbox.top,
+                                cur_image->n_obj);
+       }
      }
    }
  }
***************
*** 1187,1194 ****
    gboolean use_hiliter;
    struct PdfInfo pdfinfo;
    struct PdfObj *obj;
!   GList *pdffonts, *list;
    struct PdfFont *font;
    char *tmpbuf;
    
    f = fopen(filename, "w");
--- 1293,1301 ----
    gboolean use_hiliter;
    struct PdfInfo pdfinfo;
    struct PdfObj *obj;
!   GList *pdffonts, *pdfimages, *list;
    struct PdfFont *font;
+   struct PdfImage *image;
    char *tmpbuf;
    
    f = fopen(filename, "w");
***************
*** 1198,1203 ****
--- 1305,1311 ----
    xref.data = NULL;
    uses_pdf = FALSE;
    pdffonts = NULL;
+   pdfimages = NULL;
    for (pglist = journal.pages; pglist!=NULL; pglist = pglist->next) {
      pg = (struct Page *)pglist->data;
      if (pg->bg->type == BG_PDF) uses_pdf = TRUE;
***************
*** 1267,1273 ****
        n_obj_bgpix = pdf_draw_bitmap_background(pg, pgstrm, &xref, pdfbuf);
      // draw the page contents
      use_hiliter = FALSE;
!     pdf_draw_page(pg, pgstrm, &use_hiliter, &xref, &pdffonts);
      g_string_append_printf(pgstrm, "Q\n");
      
      // deflate pgstrm and write it
--- 1375,1381 ----
        n_obj_bgpix = pdf_draw_bitmap_background(pg, pgstrm, &xref, pdfbuf);
      // draw the page contents
      use_hiliter = FALSE;
!     pdf_draw_page(pg, pgstrm, &use_hiliter, &xref, &pdffonts, &pdfimages);
      g_string_append_printf(pgstrm, "Q\n");
      
      // deflate pgstrm and write it
***************
*** 1323,1329 ****
      }
      add_dict_subentry(pdfbuf, &xref,
          obj, "/ProcSet", PDFTYPE_ARRAY, NULL, mk_pdfname("/PDF"));
!     if (n_obj_bgpix>0)
        add_dict_subentry(pdfbuf, &xref,
          obj, "/ProcSet", PDFTYPE_ARRAY, NULL, mk_pdfname("/ImageC"));
      if (use_hiliter)
--- 1431,1437 ----
      }
      add_dict_subentry(pdfbuf, &xref,
          obj, "/ProcSet", PDFTYPE_ARRAY, NULL, mk_pdfname("/PDF"));
!     if (n_obj_bgpix>0 || pdfimages!=NULL)
        add_dict_subentry(pdfbuf, &xref,
          obj, "/ProcSet", PDFTYPE_ARRAY, NULL, mk_pdfname("/ImageC"));
      if (use_hiliter)
***************
*** 1343,1353 ****
          g_free(tmpbuf);
        }
      }
      show_pdfobj(obj, pdfbuf);
      free_pdfobj(obj);
      g_string_append(pdfbuf, " >> endobj\n");
    }
!   
    // after the pages, we insert fonts
    for (list = pdffonts; list!=NULL; list = list->next) {
      font = (struct PdfFont *)list->data;
--- 1451,1468 ----
          g_free(tmpbuf);
        }
      }
+     for (list=pdfimages; list!=NULL; list = list->next) {
+       image = (struct PdfImage *)list->data;
+       tmpbuf = g_strdup_printf("/Im%d", image->n_obj);
+       add_dict_subentry(pdfbuf, &xref,
+         obj, "/XObject", PDFTYPE_DICT, tmpbuf, mk_pdfref(image->n_obj));
+       g_free(tmpbuf);
+     }
      show_pdfobj(obj, pdfbuf);
      free_pdfobj(obj);
      g_string_append(pdfbuf, " >> endobj\n");
    }
! 
    // after the pages, we insert fonts
    for (list = pdffonts; list!=NULL; list = list->next) {
      font = (struct PdfFont *)list->data;
***************
*** 1357,1362 ****
--- 1472,1489 ----
      g_free(font);
    }
    g_list_free(pdffonts);
+ 
+   // after the fonts, we insert images
+   if (pdfimages!=NULL) {
+     for (list = pdfimages; list!=NULL; list = list->next) {
+       image = (struct PdfImage *)list->data;
+       if (!pdf_draw_image(image, &xref, pdfbuf)) {
+         return FALSE;
+       }
+       g_free(image);
+     }
+     g_list_free(pdfimages);
+   }
    
    // PDF trailer
    startxref = pdfbuf->len;
***************
*** 1476,1481 ****
--- 1603,1609 ----
  void print_job_render_page(GtkPrintOperation *print, GtkPrintContext *context, gint pageno, gpointer user_data)
  {
    cairo_t *cr;
+   cairo_t *tempcr;
    gdouble width, height, scale;
    struct Page *pg;
    guint old_rgba;
***************
*** 1487,1492 ****
--- 1615,1621 ----
    double *pt;
    PangoFontDescription *font_desc;
    PangoLayout *layout;
+   cairo_surface_t *surf;
          
    pg = (struct Page *)g_list_nth_data(journal.pages, pageno);
    cr = gtk_print_context_get_cairo_context(context);
***************
*** 1509,1515 ****
      l = (struct Layer *)layerlist->data;
      for (itemlist = l->items; itemlist!=NULL; itemlist = itemlist->next) {
        item = (struct Item *)itemlist->data;
!       if (item->type == ITEM_STROKE || item->type == ITEM_TEXT) {
          if (item->brush.color_rgba != old_rgba)
            cairo_set_source_rgba(cr, RGBA_RGB(item->brush.color_rgba),
                                      RGBA_ALPHA(item->brush.color_rgba));
--- 1638,1644 ----
      l = (struct Layer *)layerlist->data;
      for (itemlist = l->items; itemlist!=NULL; itemlist = itemlist->next) {
        item = (struct Item *)itemlist->data;
!       if (item->type == ITEM_STROKE || item->type == ITEM_TEXT || item->type==ITEM_IMAGE) {
          if (item->brush.color_rgba != old_rgba)
            cairo_set_source_rgba(cr, RGBA_RGB(item->brush.color_rgba),
                                      RGBA_ALPHA(item->brush.color_rgba));
***************
*** 1548,1553 ****
--- 1677,1694 ----
          pango_cairo_show_layout(cr, layout);
          g_object_unref(layout);
        }
+       if (item->type == ITEM_IMAGE) {
+         double required_width = item->bbox.right - item->bbox.left;
+         double required_height = item->bbox.bottom - item->bbox.top;
+ 	double scalex = required_width / gdk_pixbuf_get_width(item->image);
+ 	double scaley = required_height / gdk_pixbuf_get_height(item->image);
+ 	cairo_scale(cr,scalex,scaley);
+ 	gdk_cairo_set_source_pixbuf(cr,item->image,item->bbox.left/scalex,item->bbox.top/scaley);
+ 	cairo_scale(cr,1/scalex,1/scaley);
+ 	cairo_paint (cr);
+ 	old_rgba = predef_colors_rgba[COLOR_BLACK]; //this is an ugly fix, I (victor) don't understand cairo enough
+ 	cairo_set_source_rgb(cr, 0, 0, 0);
+       }
      }
    }
  }
diff -c 'xournal-0.4.5/src/xo-print.h' 'xournal/src/xo-print.h'
Index: ./src/xo-print.h
*** ./src/xo-print.h	Tue Sep 15 09:26:26 2009
--- ./src/xo-print.h	Fri May 28 20:43:50 2010
***************
*** 45,50 ****
--- 45,57 ----
    int flags;
  } PdfFont;
  
+ typedef struct PdfImage {
+   int n_obj;
+   gboolean has_alpha;
+   int n_obj_smask;              /* only if has_alpha */
+   GdkPixbuf *pixbuf;
+ } PdfImage;
+ 
  #define PDFTYPE_CST 0    // intval: true=1, false=0, null=-1
  #define PDFTYPE_INT 1    // intval
  #define PDFTYPE_REAL 2   // realval
diff -c 'xournal-0.4.5/src/xournal.h' 'xournal/src/xournal.h'
Index: ./src/xournal.h
*** ./src/xournal.h	Sat Oct  3 12:42:28 2009
--- ./src/xournal.h	Thu Jul 29 17:02:19 2010
***************
*** 17,22 ****
--- 17,24 ----
     "tiny file dialog" syndrome, without hurting those with well-behaved
     versions of GTK+. Comment out if you'd prefer not to include this fix. */
  
+ //#define IMAGE_DEBUG  //this is for debugging of the "insert image" patch
+ 
  // PREF FILES INFO
  
  #define CONFIG_DIR ".xournal"
***************
*** 120,125 ****
--- 122,128 ----
  #define TOOL_SELECTRECT   5
  #define TOOL_VERTSPACE    6
  #define TOOL_HAND         7
+ #define TOOL_IMAGE	8
  #define NUM_STROKE_TOOLS  3
  #define NUM_TOOLS         8
  #define NUM_BUTTONS       3
***************
*** 150,155 ****
--- 153,163 ----
    gchar *font_name;
    gdouble font_size;
    GtkWidget *widget; // the widget while text is being edited (ITEM_TEMP_TEXT)
+   // the following fields for ITEM_IMAGE:
+   GdkPixbuf* image;  // original image for print and resizing quality
+   GdkPixbuf* image_scaled; // scaled pixbuf for display
+   gchar *image_png;  // PNG of original image, for save and clipboard
+   gsize image_png_len;
  } Item;
  
  // item type values for Item.type, UndoItem.type, ui.cur_item_type ...
***************
*** 178,183 ****
--- 186,192 ----
  #define ITEM_TEXT_ATTRIB 21
  #define ITEM_RESIZESEL 22
  #define ITEM_RECOGNIZER 23
+ #define ITEM_IMAGE 24
  
  typedef struct Layer {
    GList *items; // the items on the layer, from bottom to top
***************
*** 251,256 ****
--- 260,266 ----
    gboolean hand_scrollto_pending;
    char *filename;
    gchar *default_path; // default path for new notes
+   gchar *default_image; // path for previous image
    gboolean view_continuous, fullscreen, maximize_at_start;
    gboolean in_update_page_stuff; // semaphore to avoid scrollbar retroaction
    struct Selection *selection;
***************
*** 300,307 ****
  
  typedef struct UndoItem {
    int type;
!   struct Item *item; // for ITEM_STROKE, ITEM_TEXT, ITEM_TEXT_EDIT, ITEM_TEXT_ATTRIB
!   struct Layer *layer; // for ITEM_STROKE, ITEM_ERASURE, ITEM_PASTE, ITEM_NEW_LAYER, ITEM_DELETE_LAYER, ITEM_MOVESEL, ITEM_TEXT, ITEM_TEXT_EDIT, ITEM_RECOGNIZER
    struct Layer *layer2; // for ITEM_DELETE_LAYER with val=-1, ITEM_MOVESEL
    struct Page *page;  // for ITEM_NEW_BG_ONE/RESIZE, ITEM_NEW_PAGE, ITEM_NEW_LAYER, ITEM_DELETE_LAYER, ITEM_DELETE_PAGE
    GList *erasurelist; // for ITEM_ERASURE, ITEM_RECOGNIZER
--- 310,317 ----
  
  typedef struct UndoItem {
    int type;
!   struct Item *item; // for ITEM_STROKE, ITEM_TEXT, ITEM_TEXT_EDIT, ITEM_TEXT_ATTRIB, ITEM_IMAGE
!   struct Layer *layer; // for ITEM_STROKE, ITEM_ERASURE, ITEM_PASTE, ITEM_NEW_LAYER, ITEM_DELETE_LAYER, ITEM_MOVESEL, ITEM_TEXT, ITEM_TEXT_EDIT, ITEM_RECOGNIZER, ITEM_IMAGE
    struct Layer *layer2; // for ITEM_DELETE_LAYER with val=-1, ITEM_MOVESEL
    struct Page *page;  // for ITEM_NEW_BG_ONE/RESIZE, ITEM_NEW_PAGE, ITEM_NEW_LAYER, ITEM_DELETE_LAYER, ITEM_DELETE_PAGE
    GList *erasurelist; // for ITEM_ERASURE, ITEM_RECOGNIZER
#### End of Patch data ####

#### ApplyPatch data follows ####
# Data version        : 1.0
# Date generated      : Thu Jul 29 20:05:54 2010
# Generated by        : makepatch 2.03
# Recurse directories : Yes
# Excluded files      : (\A|/).*\~\Z
#                       (\A|/).*\.a\Z
#                       (\A|/).*\.bak\Z
#                       (\A|/).*\.BAK\Z
#                       (\A|/).*\.elc\Z
#                       (\A|/).*\.exe\Z
#                       (\A|/).*\.gz\Z
#                       (\A|/).*\.ln\Z
#                       (\A|/).*\.o\Z
#                       (\A|/).*\.obj\Z
#                       (\A|/).*\.olb\Z
#                       (\A|/).*\.old\Z
#                       (\A|/).*\.orig\Z
#                       (\A|/).*\.rej\Z
#                       (\A|/).*\.so\Z
#                       (\A|/).*\.Z\Z
#                       (\A|/)\.del\-.*\Z
#                       (\A|/)\.make\.state\Z
#                       (\A|/)\.nse_depinfo\Z
#                       (\A|/)core\Z
#                       (\A|/)tags\Z
#                       (\A|/)TAGS\Z
# c './README.image' 0 1271308604 0100644
# p './src/Makefile.am' 560 1271308944 0100644
# p './src/Makefile.in' 21256 1271309237 0100644
# p './src/TODO' 12113 1273816779 0100644
# p './src/main.c' 11751 1277612564 0100644
# p './src/xo-callbacks.c' 115621 1277368329 0100644
# p './src/xo-callbacks.h' 22740 1269211165 0100644
# c './src/xo-clipboard.c' 0 1280390203 0100644
# c './src/xo-clipboard.h' 0 1269482993 0100644
# p './src/xo-file.c' 72283 1280379587 0100644
# c './src/xo-image.c' 0 1280379292 0100644
# c './src/xo-image.h' 0 1277368922 0100644
# p './src/xo-interface.c' 154893 1269211165 0100644
# p './src/xo-misc.c' 75933 1280376684 0100644
# p './src/xo-misc.h' 4155 1277612281 0100644
# p './src/xo-paint.c' 51578 1280376102 0100644
# p './src/xo-paint.h' 1292 1271305513 0100644
# p './src/xo-print.c' 51697 1280377880 0100644
# p './src/xo-print.h' 1872 1275036230 0100644
# p './src/xournal.h' 12910 1280379739 0100644
#### End of ApplyPatch data ####

#### End of Patch kit [created: Thu Jul 29 20:05:54 2010] ####
#### Patch checksum: 3071 115300 31326 ####
#### Checksum: 3109 116607 9177 ####