[goffice] Fix import of an emf image containing a screenshot. [#653667]



commit 7c991a113ba64427cec3446c0c7241d1095075f9
Author: Jean Brefort <jean brefort normalesup org>
Date:   Sun Oct 30 18:26:07 2011 +0100

    Fix import of an emf image containing a screenshot. [#653667]

 ChangeLog                 |    9 +
 goffice/canvas/goc-item.c |   13 ++
 goffice/canvas/goc-item.h |    4 +
 goffice/utils/go-emf.c    |  425 ++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 442 insertions(+), 9 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index c928f81..1f5b45c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2011-10-30  Jean Brefort  <jean brefort normalesup org>
+
+	* goffice/canvas/goc-item.c (goc_item_set_operator),
+	(goc_item_get_operator): add a cairo_operator_t member for future use.
+	* goffice/canvas/goc-item.h: ditto.
+	* goffice/utils/go-emf.c (go_dib_read_header),
+	(go_dib_create_pixbuf_from_data), (go_emf_header),
+	(go_emf_stretchdibits): import a simple image. [#653667]
+
 2011-10-29  Jean Brefort  <jean brefort normalesup org>
 
 	* goffice/Makefile.am: allow the canvas in the without gtk build.
diff --git a/goffice/canvas/goc-item.c b/goffice/canvas/goc-item.c
index 4811816..46e97a2 100644
--- a/goffice/canvas/goc-item.c
+++ b/goffice/canvas/goc-item.c
@@ -745,3 +745,16 @@ goc_item_get_window (GocItem *item)
 	return (klass->get_window)? klass->get_window (item): NULL;
 }
 #endif
+
+void
+goc_item_set_operator  (GocItem *item, cairo_operator_t op)
+{
+	item->op = op;
+	goc_item_invalidate (item);
+}
+
+cairo_operator_t
+goc_item_get_operator  (GocItem *item)
+{
+	return item->op;
+}
diff --git a/goffice/canvas/goc-item.h b/goffice/canvas/goc-item.h
index 7aab5b4..7feac3a 100644
--- a/goffice/canvas/goc-item.h
+++ b/goffice/canvas/goc-item.h
@@ -35,6 +35,7 @@ struct _GocItem {
 	gboolean		 visible;
 	gboolean		 realized;
 	double			 x0, y0, x1, y1; /* the bounds */
+	cairo_operator_t	 op;
 	gpointer		 priv;
 };
 
@@ -107,6 +108,9 @@ void		 goc_item_raise_to_top	(GocItem *item);
 void		 _goc_item_realize      (GocItem *item);
 void		 _goc_item_unrealize    (GocItem *item);
 
+void		 goc_item_set_operator  (GocItem *item, cairo_operator_t op);
+cairo_operator_t goc_item_get_operator  (GocItem *item);
+
 G_END_DECLS
 
 #endif  /* GOC_ITEM_H */
diff --git a/goffice/utils/go-emf.c b/goffice/utils/go-emf.c
index 485996e..95bb786 100644
--- a/goffice/utils/go-emf.c
+++ b/goffice/utils/go-emf.c
@@ -245,8 +245,116 @@ go_emf_new_from_data (char const *data, size_t length, GError **error)
 #endif
 }
 
-
 #ifdef GOFFICE_EMF_SUPPORT
+
+/******************************************************************************
+ * DIB support, might go to a separate file
+ ******************************************************************************/
+typedef struct {
+	guint8 type; /* 0: BitmapCoreHeader, 1: BitmapInfoHeader */
+	unsigned width, height, planes, bit_count, compression,
+		 image_size, x_pixels_per_m, y_pixels_per_m,
+		 color_used, color_important;
+} GODibHeader;
+
+static void
+go_dib_read_header (GODibHeader *header, guint8 const *data)
+{
+	guint32 size = GSF_LE_GET_GUINT32 (data);
+	header->type = (size == 12)? 0: 1;
+	if (header->type == 0) {
+		header->width = GSF_LE_GET_GUINT16 (data + 4);
+		header->height = GSF_LE_GET_GUINT16 (data + 6);
+		header->planes = GSF_LE_GET_GUINT16 (data + 8);
+		header->bit_count = GSF_LE_GET_GUINT16 (data + 10);
+		/* other fields are unused */
+		header->compression = 0;
+		header->image_size = 0;
+		header->x_pixels_per_m = 0;
+		header->y_pixels_per_m = 0;
+		header->color_used = 0;
+		header->color_important = 0;
+	} else {
+		if (size != 40) {
+			/* Invalid header */
+			header->type = 255;
+			return;
+		}
+		header->width = GSF_LE_GET_GUINT32 (data + 4);
+		header->height = GSF_LE_GET_GUINT32 (data + 8);
+		header->planes = GSF_LE_GET_GUINT16 (data + 12);
+		header->bit_count = GSF_LE_GET_GUINT16 (data + 14);
+		header->compression = GSF_LE_GET_GUINT32 (data + 16);
+		header->image_size = GSF_LE_GET_GUINT32 (data + 20);
+		header->x_pixels_per_m = GSF_LE_GET_GUINT32 (data + 24);
+		header->y_pixels_per_m = GSF_LE_GET_GUINT32 (data + 28);
+		header->color_used = GSF_LE_GET_GUINT32 (data + 32);
+		header->color_important = GSF_LE_GET_GUINT32 (data + 36);
+	}
+}
+
+static GdkPixbuf *
+go_dib_create_pixbuf_from_data (GODibHeader const *header, guint8 const *data)
+{
+	GdkPixbuf *pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, header->width, header->height);
+	unsigned i, j;
+	unsigned dst_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+	guint8 *row, *cur;
+	/* FIXME, this implementation is very incomplete */
+	switch (header->bit_count) {
+	case 0:
+		break;
+	case 1:
+		break;
+	case 4:
+		break;
+	case 8:
+		break;
+	case 16:
+		break;
+	case 24:
+		break;
+	case 32:
+		switch (header->compression) {
+		case 0:
+			if (header->type == 1 && header->width * header->height * 4 != header->image_size)
+				g_warning ("Invalid bitmap");
+			row = gdk_pixbuf_get_pixels (pixbuf) + header->height * dst_rowstride;
+			for (i = 0; i < header->height; i++) {
+				row -= dst_rowstride;
+				cur = row;
+				for (j = 0; j < header->width; j++) {
+					cur[0] = data[2];
+					cur[1] = data[1];
+					cur[2] = data[0];
+					cur[3] = 0xff;
+					data += 4;
+					cur += 4;
+				}
+			}
+			break;
+		case 1:
+			break;
+		case 2:
+			break;
+		case 3:
+			break;
+		case 4:
+			break;
+		case 5:
+			break;
+		case 11:
+			break;
+		case 12:
+			break;
+		case 13:
+			break;
+		}
+		break;
+	}
+	return pixbuf;
+}
+
 /******************************************************************************
  * Parsing code                                                               
  *
@@ -270,6 +378,272 @@ go_emf_new_from_data (char const *data, size_t length, GError **error)
 
 #ifdef DEBUG_EMF_SUPPORT
 #       define d_(x)     g_print x
+
+char const *go_emf_dib_colors[] = {
+	"DIB_RGB_COLORS",
+	"DIB_PAL_COLORS",
+	"DIB_PAL_INDICES"
+};
+
+char const *go_emf_ternary_raster_operation[] = {
+	"BLACKNESS",
+	"DPSOON",
+	"DPSONA",
+	"PSON",
+	"SDPONA",
+	"DPON",
+	"PDSXNON",
+	"PDSAON",
+	"SDPNAA",
+	"PDSXON",
+	"DPNA",
+	"PSDNAON",
+	"SPNA",
+	"PDSNAON",
+	"PDSONON",
+	"PN",
+	"PDSONA",
+	"NOTSRCERASE",
+	"SDPXNON",
+	"SDPAON",
+	"DPSXNON",
+	"DPSAON",
+	"PSDPSANAXX",
+	"SSPXDSXAXN",
+	"SPXPDXA",
+	"SDPSANAXN",
+	"PDSPAOX",
+	"SDPSXAXN",
+	"PSDPAOX",
+	"DSPDXAXN",
+	"PDSOX",
+	"PDSOAN",
+	"DPSNAA",
+	"SDPXON",
+	"DSNA",
+	"SPDNAON",
+	"SPXDSXA",
+	"PDSPANAXN",
+	"SDPSAOX",
+	"SDPSXNOX",
+	"DPSXA",
+	"PSDPSAOXXN",
+	"DPSANA",
+	"SSPXPDXAXN",
+	"SPDSOAX",
+	"PSDNOX",
+	"PSDPXOX",
+	"PSDNOAN",
+	"PSNA",
+	"SDPNAON",
+	"SDPSOOX",
+	"NOTSRCCOPY",
+	"SPDSAOX",
+	"SPDSXNOX",
+	"SDPOX",
+	"SDPOAN",
+	"PSDPOAX",
+	"SPDNOX",
+	"SPDSXOX",
+	"SPDNOAN",
+	"PSX",
+	"SPDSONOX",
+	"SPDSNAOX",
+	"PSAN",
+	"PSDNAA",
+	"DPSXON",
+	"SDXPDXA",
+	"SPDSANAXN",
+	"SRCERASE",
+	"DPSNAON",
+	"DSPDAOX",
+	"PSDPXAXN",
+	"SDPXA",
+	"PDSPDAOXXN",
+	"DPSDOAX",
+	"PDSNOX",
+	"SDPANA",
+	"SSPXDSXOXN",
+	"PDSPXOX",
+	"PDSNOAN",
+	"PDNA",
+	"DSPNAON",
+	"DPSDAOX",
+	"SPDSXAXN",
+	"DPSONON",
+	"DSTINVERT",
+	"DPSOX",
+	"DPSOAN",
+	"PDSPOAX",
+	"DPSNOX",
+	"PATINVERT",
+	"DPSDONOX",
+	"DPSDXOX",
+	"DPSNOAN",
+	"DPSDNAOX",
+	"DPAN",
+	"PDSXA",
+	"DSPDSAOXXN",
+	"DSPDOAX",
+	"SDPNOX",
+	"SDPSOAX",
+	"DSPNOX",
+	"SRCINVERT",
+	"SDPSONOX",
+	"DSPDSONOXXN",
+	"PDSXXN",
+	"DPSAX",
+	"PSDPSOAXXN",
+	"SDPAX",
+	"PDSPDOAXXN",
+	"SDPSNOAX",
+	"PDXNAN",
+	"PDSANA",
+	"SSDXPDXAXN",
+	"SDPSXOX",
+	"SDPNOAN",
+	"DSPDXOX",
+	"DSPNOAN",
+	"SDPSNAOX",
+	"DSAN",
+	"PDSAX",
+	"DSPDSOAXXN",
+	"DPSDNOAX",
+	"SDPXNAN",
+	"SPDSNOAX",
+	"DPSXNAN",
+	"SPXDSXO",
+	"DPSAAN",
+	"DPSAA",
+	"SPXDSXON",
+	"DPSXNA",
+	"SPDSNOAXN",
+	"SDPXNA",
+	"PDSPNOAXN",
+	"DSPDSOAXX",
+	"PDSAXN",
+	"SRCAND",
+	"SDPSNAOXN",
+	"DSPNOA",
+	"DSPDXOXN",
+	"SDPNOA",
+	"SDPSXOXN",
+	"SSDXPDXAX",
+	"PDSANAN",
+	"PDSXNA",
+	"SDPSNOAXN",
+	"DPSDPOAXX",
+	"SPDAXN",
+	"PSDPSOAXX",
+	"DPSAXN",
+	"DPSXX",
+	"PSDPSONOXX",
+	"SDPSONOXN",
+	"DSXN",
+	"DPSNAX",
+	"SDPSOAXN",
+	"SPDNAX",
+	"DSPDOAXN",
+	"DSPDSAOXX",
+	"PDSXAN",
+	"DPA",
+	"PDSPNAOXN",
+	"DPSNOA",
+	"DPSDXOXN",
+	"PDSPONOXN",
+	"PDXN",
+	"DSPNAX",
+	"PDSPOAXN",
+	"DPSOA",
+	"DPSOXN",
+	"D",
+	"DPSONO",
+	"SPDSXAX",
+	"DPSDAOXN",
+	"DSPNAO",
+	"DPNO",
+	"PDSNOA",
+	"PDSPXOXN",
+	"SSPXDSXOX",
+	"SDPANAN",
+	"PSDNAX",
+	"DPSDOAXN",
+	"DPSDPAOXX",
+	"SDPXAN",
+	"PSDPXAX",
+	"DSPDAOXN",
+	"DPSNAO",
+	"MERGEPAINT",
+	"SPDSANAX",
+	"SDXPDXAN",
+	"DPSXO",
+	"DPSANO",
+	"MERGECOPY",
+	"SPDSNAOXN",
+	"SPDSONOXN",
+	"PSXN",
+	"SPDNOA",
+	"SPDSXOXN",
+	"SDPNAX",
+	"PSDPOAXN",
+	"SDPOA",
+	"SPDOXN",
+	"DPSDXAX",
+	"SPDSAOXN",
+	"SRCCOPY",
+	"SDPONO",
+	"SDPNAO",
+	"SPNO",
+	"PSDNOA",
+	"PSDPXOXN",
+	"PDSNAX",
+	"SPDSOAXN",
+	"SSPXPDXAX",
+	"DPSANAN",
+	"PSDPSAOXX",
+	"DPSXAN",
+	"PDSPXAX",
+	"SDPSAOXN",
+	"DPSDANAX",
+	"SPXDSXAN",
+	"SPDNAO",
+	"SDNO",
+	"SDPXO",
+	"SDPANO",
+	"PDSOA",
+	"PDSOXN",
+	"DSPDXAX",
+	"PSDPAOXN",
+	"SDPSXAX",
+	"PDSPAOXN",
+	"SDPSANAX",
+	"SPXPDXAN",
+	"SSPXDSXAX",
+	"DSPDSANAXXN",
+	"DPSAO",
+	"DPSXNO",
+	"SDPAO",
+	"SDPXNO",
+	"SRCPAINT",
+	"SDPNOO",
+	"PATCOPY",
+	"PDSONO",
+	"PDSNAO",
+	"PSNO",
+	"PSDNAO",
+	"PDNO",
+	"PDSXO",
+	"PDSANO",
+	"PDSAO",
+	"PDSXNO",
+	"DPO",
+	"PATPAINT",
+	"PSO",
+	"PSDNOO",
+	"DPSOO",
+	"WHITENESS"
+};
+
 #else
 #       define d_(x)
 #endif
@@ -1941,10 +2315,10 @@ go_emf_header (GOEmfState *state)
 		break;
 	}
 	
-	d_(("header with %u bytes\n", state->length));
+	d_(("\theader with %u bytes\n", state->length));
 	go_wmf_read_rectl (&state->dubounds, state->data);
 	go_wmf_read_rectl (&state->mmbounds, state->data + 16);
-	d_(("bounds are (mm): left=%g top=%g right=%g bottom=%g\n",
+	d_(("\tbounds are (mm): left=%g top=%g right=%g bottom=%g\n",
 	    (double) state->mmbounds.left / 100., (double) state->mmbounds.top / 100.,
 	    (double) state->mmbounds.right / 100., (double) state->mmbounds.bottom / 100.));
 
@@ -2500,14 +2874,47 @@ go_emf_setdibitstodevice (GOEmfState *state)
 static gboolean
 go_emf_stretchdibits (GOEmfState *state)
 {
-	GOEmfRectL rect;
-	gint32 x, y, cx, cy;
+	GOWmfRectL rect;
+	gint32 dst_x, dst_y, dst_cx, dst_cy;
+	gint32 src_x, src_y, src_cx, src_cy;
+	guint32 usage_src, op; 
+	guint32 header_pos, header_size, buffer_pos, buffer_size;
+	GODibHeader header;
+	GdkPixbuf *pixbuf;
+
 	d_(("stretchdibits\n"));
 	go_wmf_read_rectl (&rect, state->data);
-	x = GSF_LE_GET_GINT32 (data + 16);
-	y = GSF_LE_GET_GINT32 (data + 20);
-	cx = GSF_LE_GET_GINT32 (data + 24);
-	cy = GSF_LE_GET_GINT32 (data + 28);
+	dst_x = GSF_LE_GET_GINT32 (state->data + 16);
+	dst_y = GSF_LE_GET_GINT32 (state->data + 20);
+	src_x = GSF_LE_GET_GINT32 (state->data + 24);
+	src_y = GSF_LE_GET_GINT32 (state->data + 28);
+	src_cx = GSF_LE_GET_GINT32 (state->data + 32);
+	src_cy = GSF_LE_GET_GINT32 (state->data + 36);
+	header_pos = GSF_LE_GET_GUINT32 (state->data + 40) - 8; /* because data does not contain the id and size */
+	header_size = GSF_LE_GET_GUINT32 (state->data + 44);
+	buffer_pos = GSF_LE_GET_GUINT32 (state->data + 48) - 8;
+	buffer_size = GSF_LE_GET_GUINT32 (state->data + 52);
+	d_ (("\tbits header at %u (%u bytes), pixels at %u (%u bytes)\n",
+	     header_pos, header_size, buffer_pos, buffer_size));
+	usage_src = GSF_LE_GET_GUINT32 (state->data + 56);
+	op = GSF_LE_GET_GUINT32 (state->data + 60);
+	dst_cx = GSF_LE_GET_GINT32 (state->data + 64);
+	dst_cy = GSF_LE_GET_GINT32 (state->data + 68);
+	d_ (("\tsource format: %s, operation: %s\n", go_emf_dib_colors[usage_src], go_emf_ternary_raster_operation[op >> 16]));
+	d_ (("\tsource: x=%d y=%d cx=%d cy=%d\n",src_x, src_y, src_cx, src_cy));
+	d_ (("\tdestination: x=%d y=%d cx=%d cy=%d\n",dst_x, dst_y, dst_cx, dst_cy));
+	go_dib_read_header (&header, state->data + header_pos);
+	if (header.type == 0xff)
+		return FALSE;
+	pixbuf = go_dib_create_pixbuf_from_data (&header, state->data + buffer_pos);
+	if (src_x != 0 || src_y != 0 || src_cx != dst_cx || src_cy != dst_cy) {
+		/* FIXME: take src coordinates into account */
+	}
+	goc_item_new (goc_canvas_get_root (state->canvas),
+	              GOC_TYPE_PIXBUF, "pixbuf", pixbuf,
+	              "x", (double) dst_x, "y", (double) dst_y,
+		      "width", (double) dst_cx, "height", (double) dst_cy,
+	              NULL);
 	return TRUE;
 }
 



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