static void gnm_soi_copy (SheetObject *dst, SheetObject const *src) { SheetObjectImage const *soi = SHEET_OBJECT_IMAGE (src); SheetObjectImage *new_soi = SHEET_OBJECT_IMAGE (dst); new_soi->type = g_strdup (soi->type); new_soi->bytes.len = soi->bytes.len; new_soi->bytes.data = g_memdup (soi->bytes.data, soi->bytes.len); new_soi->crop_top = soi->crop_top; new_soi->crop_bottom = soi->crop_bottom; new_soi->crop_left = soi->crop_left; new_soi->crop_right = soi->crop_right; }
static SheetObjectView * gnm_soi_new_view (SheetObject *so, SheetObjectViewContainer *container) { SheetObjectImage *soi = SHEET_OBJECT_IMAGE (so); GocItem *item = NULL; GdkPixbuf *pixbuf, *placeholder = NULL; pixbuf = soi_get_pixbuf (soi, 1.); if (pixbuf == NULL) { placeholder = gtk_icon_theme_load_icon ( gtk_icon_theme_get_default (), "unknown_image", 100, 0, NULL); pixbuf = gdk_pixbuf_copy (placeholder); } item = goc_item_new ( gnm_pane_object_group (GNM_PANE (container)), so_image_goc_view_get_type (), NULL); goc_item_hide (goc_item_new (GOC_GROUP (item), GOC_TYPE_PIXBUF, "pixbuf", pixbuf, NULL)); g_object_unref (G_OBJECT (pixbuf)); if (placeholder) g_object_set_data (G_OBJECT (item), "tile", placeholder); return gnm_pane_object_register (so, item, TRUE); }
static void gnm_soi_write_image (SheetObject const *so, char const *format, G_GNUC_UNUSED double resolution, GsfOutput *output, GError **err) { SheetObjectImage *soi = SHEET_OBJECT_IMAGE (so); gboolean res = FALSE; GdkPixbuf *pixbuf = go_image_get_pixbuf (soi->image); if (!soi->type || strcmp (format, soi->type) == 0) { if (soi->bytes.len == 0) { gsize length; guint8 const *data = go_image_get_data (soi->image, &length); res = gsf_output_write (output, length, data); } else res = gsf_output_write (output, soi->bytes.len, soi->bytes.data); } else if (pixbuf) res = gdk_pixbuf_save_to_callback (pixbuf, soi_gdk_pixbuf_save, output, format, err, NULL); if (pixbuf) g_object_unref (pixbuf); if (!res && err && *err == NULL) *err = g_error_new (gsf_output_error_id (), 0, _("Unknown failure while saving image")); }
static void gnm_soi_default_size (SheetObject const *so, double *w, double *h) { SheetObjectImage *soi = SHEET_OBJECT_IMAGE (so); if (soi->image) { *w = go_image_get_width (soi->image); *h = go_image_get_height (soi->image); } else { GdkPixbuf *buf = go_image_get_pixbuf (soi->image); if (!buf) { *w = *h = 5; return; } *w = gdk_pixbuf_get_width (buf); *h = gdk_pixbuf_get_height (buf); /* In case buf is invalid with size 0,0 or if the image is just too * small to be useful default to something slightly larger * http://bugzilla.gnome.org/show_bug.cgi?id=462787 **/ if ((*w * *h) < 25.) { if (*w < 5) *w = 25; if (*h < 5) *h = 25; } g_object_unref (buf); } }
static void gnm_soi_write_xml_sax (SheetObject const *so, GsfXMLOut *output, G_GNUC_UNUSED GnmConventions const *convs) { SheetObjectImage *soi; g_return_if_fail (IS_SHEET_OBJECT_IMAGE (so)); soi = SHEET_OBJECT_IMAGE (so); gsf_xml_out_add_float (output, "crop-top", soi->crop_top, 3); gsf_xml_out_add_float (output, "crop-bottom", soi->crop_bottom, 3); gsf_xml_out_add_float (output, "crop-left", soi->crop_left, 3); gsf_xml_out_add_float (output, "crop-right", soi->crop_right, 3); gsf_xml_out_start_element (output, "Content"); if (soi->type != NULL) gsf_xml_out_add_cstr (output, "image-type", soi->type); if (soi->image && go_image_get_name (soi->image)) { gsf_xml_out_add_cstr (output, "name", go_image_get_name (soi->image)); if (sheet_object_get_sheet (so)) go_doc_save_image (GO_DOC (sheet_object_get_sheet (so)->workbook), go_image_get_name (soi->image)); else { /* looks that this may happen when pasting from another process, see #687414 */ gsize length; guint8 const *data = go_image_get_data (soi->image, &length); gsf_xml_out_add_uint (output, "size-bytes", length); gsf_xml_out_add_base64 (output, NULL, data, length); } } else { gsf_xml_out_add_uint (output, "size-bytes", soi->bytes.len); gsf_xml_out_add_base64 (output, NULL, soi->bytes.data, soi->bytes.len); } gsf_xml_out_end_element (output); }
static void gnm_soi_prep_sax_parser (SheetObject *so, GsfXMLIn *xin, xmlChar const **attrs, G_GNUC_UNUSED GnmConventions const *convs) { static GsfXMLInNode const dtd[] = { GSF_XML_IN_NODE (CONTENT, CONTENT, -1, "Content", GSF_XML_CONTENT, &content_start, &content_end), GSF_XML_IN_NODE_END }; static GsfXMLInDoc *doc = NULL; SheetObjectImage *soi = SHEET_OBJECT_IMAGE (so); if (NULL == doc) doc = gsf_xml_in_doc_new (dtd, NULL); gsf_xml_in_push_state (xin, doc, NULL, NULL, attrs); for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) { if (gnm_xml_attr_double (attrs, "crop-top", &soi->crop_top)) ; else if (gnm_xml_attr_double (attrs, "crop-bottom", &soi->crop_bottom)) /* Nothing */ ; else if (gnm_xml_attr_double (attrs, "crop-left", &soi->crop_left)) /* Nothing */ ; else if (gnm_xml_attr_double (attrs, "crop-right", &soi->crop_right)) /* Nothing */ ; } }
static void gnm_soi_draw_cairo (SheetObject const *so, cairo_t *cr, double width, double height) { GdkPixbuf *pixbuf; GOImage *img; cairo_pattern_t *cr_pattern; int w, h; cairo_matrix_t cr_matrix; pixbuf = soi_get_pixbuf (SHEET_OBJECT_IMAGE (so), 1.); if (!pixbuf || width == 0. || height == 0.) return; cairo_save (cr); img = go_image_new_from_pixbuf (pixbuf); cr_pattern = go_image_create_cairo_pattern (img); w = gdk_pixbuf_get_width (pixbuf); h = gdk_pixbuf_get_height (pixbuf); cairo_matrix_init_scale (&cr_matrix, w / width, h / height); cairo_pattern_set_matrix (cr_pattern, &cr_matrix); cairo_rectangle (cr, 0., 0., width, height); cairo_set_source (cr, cr_pattern); cairo_fill (cr); /* * We need to unset the source before we destroy the pattern. * cairo_restore will do that. See #632439. */ cairo_restore (cr); cairo_pattern_destroy (cr_pattern); g_object_unref (img); g_object_unref (pixbuf); }
static void gnm_soi_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { SheetObjectImage *soi = SHEET_OBJECT_IMAGE (object); GdkPixbuf *pixbuf; switch (property_id) { case PROP_IMAGE_TYPE: g_value_set_string (value, soi->type); break; case PROP_IMAGE_DATA: g_value_set_pointer (value, &soi->bytes); break; case PROP_PIXBUF: pixbuf = soi_get_pixbuf (soi, 1.0); g_value_set_object (value, pixbuf); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } }
static GtkTargetList * gnm_soi_get_target_list (SheetObject const *so) { SheetObjectImage *soi = SHEET_OBJECT_IMAGE (so); GtkTargetList *tl = gtk_target_list_new (NULL, 0); char *mime_str = go_image_format_to_mime (soi->type); GSList *mimes, *ptr; GdkPixbuf *pixbuf; mimes = go_strsplit_to_slist (mime_str, ','); for (ptr = mimes; ptr != NULL; ptr = ptr->next) { const char *mime = ptr->data; if (mime != NULL && *mime != '\0') gtk_target_list_add (tl, gdk_atom_intern (mime, FALSE), 0, 0); } g_free (mime_str); go_slist_free_custom (mimes, g_free); /* No need to eliminate duplicates. */ if ((pixbuf = soi_get_pixbuf (soi, 1.0)) != NULL) { gtk_target_list_add_image_targets (tl, 0, TRUE); g_object_unref (pixbuf); } return tl; }
static SheetObjectView * gnm_soi_new_view (SheetObject *so, SheetObjectViewContainer *container) { SheetObjectImage *soi = SHEET_OBJECT_IMAGE (so); GocItem *item = NULL; item = goc_item_new ( gnm_pane_object_group (GNM_PANE (container)), so_image_goc_view_get_type (), NULL); if (soi->image) { goc_item_hide (goc_item_new (GOC_GROUP (item), GOC_TYPE_IMAGE, "image", soi->image, "crop-bottom", soi->crop_bottom, "crop-left", soi->crop_left, "crop-right", soi->crop_right, "crop-top", soi->crop_top, NULL)); } else { GdkPixbuf *placeholder = go_gdk_pixbuf_load_from_file ("res:gnm:pixmaps/unknown_image.png"); GdkPixbuf *pixbuf = gdk_pixbuf_copy (placeholder); goc_item_hide (goc_item_new (GOC_GROUP (item), GOC_TYPE_PIXBUF, "pixbuf", pixbuf, NULL)); g_object_unref (pixbuf); g_object_set_data (G_OBJECT (item), "tile", placeholder); } return gnm_pane_object_register (so, item, TRUE); }
static void content_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *unknown) { SheetObject *so = gnm_xml_in_cur_obj (xin); SheetObjectImage *soi = SHEET_OBJECT_IMAGE (so); soi->bytes.len = gsf_base64_decode_simple ( xin->content->str, xin->content->len); soi->bytes.data = g_memdup (xin->content->str, soi->bytes.len); }
static void gnm_soi_finalize (GObject *object) { SheetObjectImage *soi; soi = SHEET_OBJECT_IMAGE (object); g_free (soi->bytes.data); g_free (soi->type); soi->bytes.data = NULL; G_OBJECT_CLASS (gnm_soi_parent_class)->finalize (object); }
static void soi_info_cb (GdkPixbufLoader *loader, int width, int height, gpointer data) { SheetObjectImage *soi = SHEET_OBJECT_IMAGE (data); GdkPixbufFormat *format = gdk_pixbuf_loader_get_format (loader); char *name = gdk_pixbuf_format_get_name (format); g_free (soi->type); soi->type = name; }
static void content_start (GsfXMLIn *xin, xmlChar const **attrs) { SheetObject *so = gnm_xml_in_cur_obj (xin); SheetObjectImage *soi = SHEET_OBJECT_IMAGE (so); char const *image_type = NULL; for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) if (attr_eq (attrs[0], "image-type")) image_type = CXML2C (attrs[1]); soi->type = g_strdup (image_type); }
static void gnm_soi_init (GObject *obj) { SheetObjectImage *soi; SheetObject *so; soi = SHEET_OBJECT_IMAGE (obj); soi->dumped = FALSE; soi->crop_top = soi->crop_bottom = soi->crop_left = soi->crop_right = 0.0; so = SHEET_OBJECT (obj); so->anchor.base.direction = GOD_ANCHOR_DIR_DOWN_RIGHT; }
static void content_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *unknown) { SheetObject *so = gnm_xml_in_cur_obj (xin); SheetObjectImage *soi = SHEET_OBJECT_IMAGE (so); GString *data = xin->content; if (data->len >= 4) { size_t len = gsf_base64_decode_simple (data->str, data->len); soi->bytes.len = len; soi->bytes.data = g_memdup (data->str, len); soi->image = go_image_new_from_data (soi->type, soi->bytes.data, len, NULL, NULL); } }
static void soi_cb_save_as (SheetObject *so, SheetControl *sc) { WBCGtk *wbcg; char *uri; GsfOutput *output; GSList *l = NULL; GOImageFormat sel_fmt; GOImageFormatInfo const *format_info; GdkPixbuf *pixbuf = NULL; GError *err = NULL; SheetObjectImage *soi = SHEET_OBJECT_IMAGE (so); g_return_if_fail (soi != NULL); sel_fmt = go_image_get_format_from_name (soi->type); if ((pixbuf = go_image_get_pixbuf (soi->image)) != NULL) l = go_image_get_formats_with_pixbuf_saver (); /* Move original format first in menu */ if (sel_fmt != GO_IMAGE_FORMAT_UNKNOWN) { l = g_slist_remove (l, GUINT_TO_POINTER (sel_fmt)); l = g_slist_prepend (l, GUINT_TO_POINTER (sel_fmt)); } wbcg = scg_wbcg (SHEET_CONTROL_GUI (sc)); uri = go_gui_get_image_save_info (wbcg_toplevel (wbcg), l, &sel_fmt, NULL); if (!uri) goto out; output = go_file_create (uri, &err); if (!output) goto out; format_info = go_image_get_format_info (sel_fmt); sheet_object_write_image (so, (format_info? format_info->name: NULL), -1.0, output, &err); gsf_output_close (output); g_object_unref (output); if (err != NULL) go_cmd_context_error (GO_CMD_CONTEXT (wbcg), err); out: if (pixbuf) g_object_unref (pixbuf); g_free (uri); g_slist_free (l); }
static void gnm_soi_draw_cairo (SheetObject const *so, cairo_t *cr, double width, double height) { GdkPixbuf *pixbuf; GOImage *img; int w, h; SheetObjectImage *soi = SHEET_OBJECT_IMAGE (so); if (soi->image) { w = go_image_get_width (soi->image); h = go_image_get_height (soi->image); w -= soi->crop_left - soi->crop_right; h -= soi->crop_top - soi->crop_bottom; if (w <= 0 || h <= 0) return; cairo_save (cr); cairo_rectangle (cr, 0, 0, width, height); cairo_clip (cr); cairo_scale (cr, width / w, height / h); cairo_translate (cr, -soi->crop_left, -soi->crop_top); go_image_draw (soi->image, cr); cairo_restore (cr); } else { pixbuf = go_image_get_pixbuf (soi->image); if (!pixbuf || width == 0. || height == 0.) return; cairo_save (cr); img = go_pixbuf_new_from_pixbuf (pixbuf); w = gdk_pixbuf_get_width (pixbuf); h = gdk_pixbuf_get_height (pixbuf); cairo_scale (cr, width / w, height / h); go_image_draw (img, cr); /* * We need to unset the source before we destroy the pattern. * cairo_restore will do that. See #632439. */ cairo_restore (cr); g_object_unref (img); g_object_unref (pixbuf); } }
static void gnm_soi_write_xml_sax (SheetObject const *so, GsfXMLOut *output, GnmConventions const *convs) { SheetObjectImage *soi; g_return_if_fail (IS_SHEET_OBJECT_IMAGE (so)); soi = SHEET_OBJECT_IMAGE (so); gsf_xml_out_add_float (output, "crop-top", soi->crop_top, 3); gsf_xml_out_add_float (output, "crop-bottom", soi->crop_bottom, 3); gsf_xml_out_add_float (output, "crop-left", soi->crop_left, 3); gsf_xml_out_add_float (output, "crop-right", soi->crop_right, 3); gsf_xml_out_start_element (output, "Content"); if (soi->type != NULL) gsf_xml_out_add_cstr (output, "image-type", soi->type); gsf_xml_out_add_uint (output, "size-bytes", soi->bytes.len); gsf_xml_out_add_base64 (output, NULL, soi->bytes.data, soi->bytes.len); gsf_xml_out_end_element (output); }
static gboolean gnm_soi_assign_to_sheet (SheetObject *so, Sheet *sheet) { SheetObjectImage *soi = SHEET_OBJECT_IMAGE (so); if (soi->image/* && !go_image_get_name (soi->image)*/) { GODoc *doc = GO_DOC (sheet->workbook); GOImage *image = go_doc_add_image (doc, soi->name, soi->image); if (soi->image != image) { g_object_unref (soi->image); soi->image = g_object_ref (image); } } else if (soi->name) { GODoc *doc = GO_DOC (sheet->workbook); GType type = go_image_type_for_format (soi->type); if (type != 0) soi->image = g_object_ref (go_doc_image_fetch (doc, soi->name, type)); } else { /* There is nothing we can do */ } return FALSE; }
static void gnm_soi_write_image (SheetObject const *so, char const *format, double resolution, GsfOutput *output, GError **err) { SheetObjectImage *soi = SHEET_OBJECT_IMAGE (so); gboolean res = FALSE; GdkPixbuf *pixbuf = soi_get_pixbuf (soi, 1.0); if (strcmp (format, soi->type) == 0) res = gsf_output_write (output, soi->bytes.len, soi->bytes.data); else if (pixbuf) res = gdk_pixbuf_save_to_callback (pixbuf, soi_gdk_pixbuf_save, output, format, err, NULL); if (pixbuf) g_object_unref (pixbuf); if (!res && err && *err == NULL) *err = g_error_new (gsf_output_error_id (), 0, _("Unknown failure while saving image")); }