[goffice] Add new component helper functions.



commit b0606abbbba32178e7ba161bf862ed29a5c3d75d
Author: Jean Brefort <jean brefort normalesup org>
Date:   Sun Nov 27 17:33:30 2011 +0100

    Add new component helper functions.

 ChangeLog                        |   12 +++
 goffice/component/go-component.c |   60 ++++++++++++++++
 goffice/component/go-component.h |    4 +
 goffice/utils/go-emf.c           |  145 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 221 insertions(+), 0 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 468ac4b..ff136f6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2011-11-27  Jean Brefort  <jean brefort normalesup org>
+
+	* goffice/component/go-component.c (go_component_export_image),
+	(go_component_duplicate): new functions.
+	* goffice/component/go-component.h: ditto.
+	* goffice/utils/go-emf.c (go_wmf_read_spoint),
+	(go_wmf_read_lpoint), (go_emf_setwindowextex),
+	(go_emf_setwindoworgex), (go_emf_setviewportextex),
+	(go_emf_setviewportorgex), (go_emf_setmapmode), (go_emf_setbkmode),
+	(go_emf_setrop2), (go_emf_intersectcliprect), (go_emf_savedc),
+	(go_emf_restoredc), (go_emf_parse): implement some callbacks.
+
 2011-11-25  Morten Welinder  <terra gnome org>
 
 	* goffice/math/go-rangefunc.c (go_range_sumsq, go_range_devsq):
diff --git a/goffice/component/go-component.c b/goffice/component/go-component.c
index 222e4f5..b4d08dd 100644
--- a/goffice/component/go-component.c
+++ b/goffice/component/go-component.c
@@ -796,3 +796,63 @@ void go_component_set_font (GOComponent *component, PangoFontDescription *desc)
 	if (klass->set_font)
 		klass->set_font (component, desc);
 }
+
+/**
+ * go_component_export_image:
+ * @component: a #GOComponent
+ * @format: image format for export
+ * @output: a #GsfOutput stream
+ * @x_dpi: x resolution of exported graph
+ * @y_dpi: y resolution of exported graph
+ *
+ * Exports an image of @graph in given @format, writing results in a #GsfOutput stream.
+ * If export format type is a bitmap one, it computes image size with x_dpi, y_dpi and
+ * @graph size (see @gog_graph_get_size()).
+ *
+ * returns: %TRUE if export succeed.
+ **/
+
+gboolean
+go_component_export_image (GOComponent *component, GOImageFormat format, GsfOutput *output,
+			double x_dpi, double y_dpi)
+{
+	return FALSE;
+}
+
+GOComponent *
+go_component_duplicate (GOComponent const *component)
+{
+	GOComponent *res;
+	char *buf;
+	int length;
+	void (*clearfunc) (gpointer) = NULL;
+	gpointer user_data = NULL;
+	GValue	 value;
+	guint i, nbprops;
+	GType    prop_type;
+	GParamSpec **specs;
+
+	g_return_val_if_fail (GO_IS_COMPONENT (component), NULL);
+
+	res = go_component_new_by_mime_type (component->mime_type);
+	res->width = component->width;
+	res->height = component->height;
+	/* first copy needed component specific properties */
+	specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (component), &nbprops);
+	for (i = 0; i < nbprops; i++)
+		if (specs[i]->flags & GO_PARAM_PERSISTENT) {
+			prop_type = G_PARAM_SPEC_VALUE_TYPE (specs[i]);
+			memset (&value, 0, sizeof (value));
+			g_value_init (&value, prop_type);
+			g_object_get_property  (G_OBJECT (component), specs[i]->name, &value);
+			if (!g_param_value_defaults (specs[i], &value))
+				g_object_set_property (G_OBJECT (res), specs[i]->name, &value);
+			g_value_unset (&value);
+		}
+	/* and now the data */
+	go_component_get_data ((GOComponent *) component, (gpointer) &buf, &length, &clearfunc, &user_data);
+	go_component_set_data (res, buf, length);
+	if (clearfunc)
+		clearfunc ((user_data)? user_data: buf);
+	return res;
+}
diff --git a/goffice/component/go-component.h b/goffice/component/go-component.h
index 26f159a..7a8935d 100644
--- a/goffice/component/go-component.h
+++ b/goffice/component/go-component.h
@@ -121,6 +121,10 @@ void go_component_sax_push_parser (GsfXMLIn *xin, xmlChar const **attrs,
 GOSnapshotType go_component_build_snapshot (GOComponent *component);
 void const *go_component_get_snapshot (GOComponent *component, GOSnapshotType *type, size_t *length);
 
+gboolean go_component_export_image (GOComponent *component, GOImageFormat format,
+                                GsfOutput *output, double x_dpi, double y_dpi);
+GOComponent *go_component_duplicate (GOComponent const *component);
+
 G_END_DECLS
 
 #endif	/* GOFFICE_COMPONENT_H */
diff --git a/goffice/utils/go-emf.c b/goffice/utils/go-emf.c
index a6cc9d8..0846bc8 100644
--- a/goffice/utils/go-emf.c
+++ b/goffice/utils/go-emf.c
@@ -763,6 +763,43 @@ go_wmf_read_rectl (GOWmfRectL *rect, guint8 const *data)
 	rect->bottom = GSF_LE_GET_GINT32 (data + 12);
 }
 
+typedef enum {
+MM_TEXT = 0x01,
+MM_LOMETRIC = 0x02,
+MM_HIMETRIC = 0x03,
+MM_LOENGLISH = 0x04,
+MM_HIENGLISH = 0x05,
+MM_TWIPS = 0x06,
+MM_ISOTROPIC = 0x07,
+MM_ANISOTROPIC = 0x08
+} GOEmfMapMode;
+
+typedef enum
+{
+R2_BLACK = 0x0001,
+R2_NOTMERGEPEN = 0x0002,
+R2_MASKNOTPEN = 0x0003,
+R2_NOTCOPYPEN = 0x0004,
+R2_MASKPENNOT = 0x0005,
+R2_NOT = 0x0006,
+R2_XORPEN = 0x0007,
+R2_NOTMASKPEN = 0x0008,
+R2_MASKPEN = 0x0009,
+R2_NOTXORPEN = 0x000A,
+R2_NOP = 0x000B,
+R2_MERGENOTPEN = 0x000C,
+R2_COPYPEN = 0x000D,
+R2_MERGEPENNOT = 0x000E,
+R2_MERGEPEN = 0x000F,
+R2_WHITE = 0x0010
+} GOWmfOperation;
+
+typedef struct {
+	GOWmfOperation op;
+	gboolean fill_bg;
+	GocGroup *group;
+} GOEmfDC;
+
 typedef struct {
 	GocCanvas *canvas;
 	GError **error;
@@ -770,9 +807,15 @@ typedef struct {
 	unsigned length;
 	GOWmfRectL dubounds; /* bounds in device units */
 	GOWmfRectL mmbounds; /* bounds in mm/100 */
+	double dx, dy, dw, dh; /* view port in device units */
+	double wx, wy, ww, wh; /* window rectangle in logical unit */
+	GOEmfMapMode map_mode;
 	gboolean is_emf;	/* FIXME: might be EPS or WMF */
+	GOEmfDC *curDC;
+	GSList *dc_stack;
 } GOEmfState;
 
+#define CMM2PTS(x) (((double) x) * 72. / 254.)
 
 static char *
 go_wmf_mtextra_to_utf (char *txt)
@@ -945,6 +988,20 @@ go_wmf_mr_convcoord (double* x, double* y, GOWmfPage* pg)
 }
 
 static void
+go_wmf_read_spoint (guint8 const *src, double* y, double* x)
+{
+	*x = GSF_LE_GET_GINT16 (src);
+	*y = GSF_LE_GET_GINT16 (src + 2);
+}
+
+static void
+go_wmf_read_lpoint (guint8 const *src, double* y, double* x)
+{
+	*x = GSF_LE_GET_GINT32 (src);
+	*y = GSF_LE_GET_GINT32 (src + 4);
+}
+
+static void
 go_wmf_read_point (GsfInput* input, double* y, double* x)
 {
 	const guint8  *data = {0};
@@ -2383,28 +2440,40 @@ go_emf_polypolygon (GOEmfState *state)
 static gboolean
 go_emf_setwindowextex (GOEmfState *state)
 {
+	double dw, dh;
 	d_(("setwindowextex\n"));
+	go_wmf_read_lpoint (state->data, &dw, &dh);
+	d_(("\twindow size: %g x %g\n", dw, dh));
 	return TRUE;
 }
 
 static gboolean
 go_emf_setwindoworgex (GOEmfState *state)
 {
+	double dw, dh;
 	d_(("setwindoworgex\n"));
+	go_wmf_read_lpoint (state->data, &dw, &dh);
+	d_(("\twindow origin: %g x %g\n", dw, dh));
 	return TRUE;
 }
 
 static gboolean
 go_emf_setviewportextex (GOEmfState *state)
 {
+	double dw, dh;
 	d_(("setviewportextex\n"));
+	go_wmf_read_lpoint (state->data, &dw, &dh);
+	d_(("\tview port size: %g x %g\n", dw, dh));
 	return TRUE;
 }
 
 static gboolean
 go_emf_setviewportorgex (GOEmfState *state)
 {
+	double dw, dh;
 	d_(("setviewportorgex\n"));
+	go_wmf_read_lpoint (state->data, &dw, &dh);
+	d_(("\tview port origin: %g x %g\n", dw, dh));
 	return TRUE;
 }
 
@@ -2439,7 +2508,21 @@ go_emf_setmapperflags (GOEmfState *state)
 static gboolean
 go_emf_setmapmode (GOEmfState *state)
 {
+#ifdef DEBUG_EMF_SUPPORT
+char const *map_modes[] = {
+	"MM_TEXT",
+"MM_LOMETRIC",
+"MM_HIMETRIC",
+"MM_LOENGLISH",
+"MM_HIENGLISH",
+"MM_TWIPS",
+"MM_ISOTROPIC",
+"MM_ANISOTROPIC"
+};
+#endif
 	d_(("setmapmode\n"));
+	state->map_mode = GSF_LE_GET_GUINT32 (state->data);
+	d_(("\tmap mode is %s\n", map_modes[state->map_mode-1]));
 	return TRUE;
 }
 
@@ -2447,6 +2530,8 @@ static gboolean
 go_emf_setbkmode (GOEmfState *state)
 {
 	d_(("setbkmode\n"));
+	state->curDC->fill_bg = GSF_LE_GET_GINT32 (state->data) - 1;
+	d_(("\tbackground is %s\n", state->curDC->fill_bg? "filled": "transparent"));
 	return TRUE;
 }
 
@@ -2460,7 +2545,30 @@ go_emf_setpolyfillmode (GOEmfState *state)
 static gboolean
 go_emf_setrop2 (GOEmfState *state)
 {
+#ifdef DEBUG_EMF_SUPPORT
+char const *ops[] = {
+NULL,
+"R2_BLACK",
+"R2_NOTMERGEPEN",
+"R2_MASKNOTPEN",
+"R2_NOTCOPYPEN",
+"R2_MASKPENNOT",
+"R2_NOT",
+"R2_XORPEN",
+"R2_NOTMASKPEN",
+"R2_MASKPEN",
+"R2_NOTXORPEN",
+"R2_NOP",
+"R2_MERGENOTPEN",
+"R2_COPYPEN",
+"R2_MERGEPENNOT",
+"R2_MERGEPEN",
+"R2_WHITE"
+};
+#endif
 	d_(("setrop2\n"));
+	state->curDC->op = GSF_LE_GET_GINT32 (state->data);
+	d_(("\toperator is %x i.e. %s\n", state->curDC->op, ops[state->curDC->op]));
 	return TRUE;
 }
 
@@ -2530,7 +2638,18 @@ go_emf_excludecliprect (GOEmfState *state)
 static gboolean
 go_emf_intersectcliprect (GOEmfState *state)
 {
+	GOWmfRectL rect;
+	GOPath *path;
 	d_(("intersectcliprect\n"));
+	go_wmf_read_rectl (&rect, state->data);
+	d_(("clipping rectangle: left=%d top=%d right=%d bottom=%d\n",
+	    rect.left, rect.top, rect.right, rect.bottom));
+	state->curDC->group = GOC_GROUP (goc_item_new (state->curDC->group, GOC_TYPE_GROUP, NULL));
+	path = state->curDC->group->clip_path = go_path_new ();
+	/* FIXME adjust the coordinates */
+	go_path_rectangle (path, CMM2PTS(rect.left), CMM2PTS(rect.top),
+	                   CMM2PTS(rect.right - rect.left),
+	                   CMM2PTS(rect.bottom - rect.top));
 	return TRUE;
 }
 
@@ -2552,13 +2671,27 @@ static gboolean
 go_emf_savedc (GOEmfState *state)
 {
 	d_(("savedc\n"));
+	state->dc_stack = g_slist_prepend (state->dc_stack, state->curDC);
+	state->curDC = g_new (GOEmfDC, 1);
+	memcpy (state->curDC, state->dc_stack->data, sizeof (GOEmfDC));
 	return TRUE;
 }
 
 static gboolean
 go_emf_restoredc (GOEmfState *state)
 {
+	int n = GSF_LE_GET_GINT32 (state->data);
 	d_(("restoredc\n"));
+	d_(("\tpoping %d %s\n", -n, n == -1? "context": "contexts"));
+	if (n >= 0)
+		return FALSE;
+	while (n++ < 0) {
+		if (state->dc_stack == NULL)
+			return FALSE;
+		g_free (state->curDC);
+		state->curDC = state->dc_stack->data;
+		state->dc_stack = g_slist_delete_link (state->dc_stack, state->dc_stack);
+	}
 	return TRUE;
 }
 
@@ -3280,6 +3413,10 @@ go_emf_parse (GOEmf *emf, GsfInput *input, GError **error)
 		GOEmfState state;
 		state.canvas = emf->canvas;
 		state.error = error;
+		state.map_mode = 0;
+		state.dc_stack = NULL;
+		state.curDC = g_new0 (GOEmfDC, 1);
+		state.curDC->group = state.canvas->root; 
 		offset = 4;
 		while ((offset += 4) < fsize && rid != 0xe) { /* EOF */
 			data = gsf_input_read (input, 4, NULL);
@@ -3299,6 +3436,14 @@ go_emf_parse (GOEmf *emf, GsfInput *input, GError **error)
 				break;
 			rid = GSF_LE_GET_GUINT32 (data);
 		}
+		g_free (state.curDC);
+		if (state.dc_stack != NULL) {
+			g_slist_free_full (state.dc_stack, g_free);
+			if (error)
+				if (*error == NULL)
+					*error = g_error_new (go_error_invalid (), 0,
+					                      _("Invalid image data\n"));
+		}
 		if (rid != 0xe) {
 			if (error) {
 				if (*error == NULL)



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