From b13f78e60a09501e35a3f00c2fe0af27da300442 Mon Sep 17 00:00:00 2001 From: ulferikson Date: Thu, 22 May 2008 14:32:26 +0000 Subject: [PATCH] Improved emf handling --- src/extension/internal/emf-win32-inout.cpp | 817 ++++++++++++++++----- src/extension/internal/emf-win32-inout.h | 2 +- src/extension/internal/emf-win32-print.cpp | 227 +++++- src/extension/internal/emf-win32-print.h | 11 +- 4 files changed, 850 insertions(+), 207 deletions(-) diff --git a/src/extension/internal/emf-win32-inout.cpp b/src/extension/internal/emf-win32-inout.cpp index 3eac9e5fc..7c2aa9192 100644 --- a/src/extension/internal/emf-win32-inout.cpp +++ b/src/extension/internal/emf-win32-inout.cpp @@ -5,7 +5,7 @@ * Authors: * Ulf Erikson * - * Copyright (C) 2006 Authors + * Copyright (C) 2006-2008 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -185,6 +185,7 @@ typedef struct emf_callback_data { bool fill_set; double xDPI, yDPI; bool pathless_stroke; + bool inpath; SIZEL sizeWnd; SIZEL sizeView; @@ -197,6 +198,11 @@ typedef struct emf_callback_data { POINTL winorg; POINTL vieworg; double ScaleX, ScaleY; + COLORREF textColor; + bool textColorSet; + DWORD textAlign; + XFORM worldTransform; + unsigned int id; int n_obj; PEMF_OBJECT emf_obj; @@ -206,6 +212,7 @@ typedef struct emf_callback_data { static void output_style(PEMF_CALLBACK_DATA d, int iType) { + SVGOStringStream tmp_id; SVGOStringStream tmp_style; char tmp[1024] = {0}; @@ -215,6 +222,8 @@ output_style(PEMF_CALLBACK_DATA d, int iType) float stroke_rgb[3]; sp_color_get_rgb_floatv(&(d->style.stroke.value.color), stroke_rgb); + tmp_id << "\n\tid=\"" << (d->id++) << "\""; + *(d->outsvg) += tmp_id.str().c_str(); *(d->outsvg) += "\n\tstyle=\""; if (iType == EMR_STROKEPATH || !d->fill_set) { tmp_style << "fill:none;"; @@ -227,7 +236,7 @@ output_style(PEMF_CALLBACK_DATA d, int iType) tmp_style << tmp; snprintf(tmp, 1023, "fill-rule:%s;", - d->style.fill_rule.value != 0 ? "evenodd" : "nonzero"); + d->style.fill_rule.value == 0 ? "evenodd" : "nonzero"); tmp_style << tmp; tmp_style << "fill-opacity:1;"; @@ -251,6 +260,12 @@ output_style(PEMF_CALLBACK_DATA d, int iType) tmp_style << "stroke-width:" << MAX( 0.001, d->style.stroke_width.value ) << "px;"; + tmp_style << "stroke-linecap:" << + (d->style.stroke_linecap.computed == 0 ? "butt" : + d->style.stroke_linecap.computed == 1 ? "round" : + d->style.stroke_linecap.computed == 2 ? "square" : + "unknown") << ";"; + tmp_style << "stroke-linejoin:" << (d->style.stroke_linejoin.computed == 0 ? "miter" : d->style.stroke_linejoin.computed == 1 ? "round" : @@ -285,30 +300,62 @@ output_style(PEMF_CALLBACK_DATA d, int iType) static double -pix_x_to_point(PEMF_CALLBACK_DATA d, double px) +_pix_x_to_point(PEMF_CALLBACK_DATA d, double px) { double tmp = px - d->winorg.x; - tmp *= (double) PX_PER_IN / d->ScaleX; + tmp *= d->ScaleX ? (double) PX_PER_IN / d->ScaleX : 1.0; tmp += d->vieworg.x; return tmp; } - static double -pix_y_to_point(PEMF_CALLBACK_DATA d, double px) +_pix_y_to_point(PEMF_CALLBACK_DATA d, double px) { double tmp = px - d->winorg.y; - tmp *= (double) PX_PER_IN / d->ScaleY; + tmp *= d->ScaleY ? (double) PX_PER_IN / d->ScaleY : 1.0; tmp += d->vieworg.y; return tmp; } static double -pix_size_to_point(PEMF_CALLBACK_DATA d, double px) +pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py) +{ + double ppx = _pix_x_to_point(d, px); + double ppy = _pix_y_to_point(d, py); + + double x = ppx * d->worldTransform.eM11 + ppy * d->worldTransform.eM21 + d->worldTransform.eDx; + + return x; +} + +static double +pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py) +{ + double ppx = _pix_x_to_point(d, px); + double ppy = _pix_y_to_point(d, py); + + double y = ppx * d->worldTransform.eM12 + ppy * d->worldTransform.eM22 + d->worldTransform.eDy; + + return y; +} + + +static double +_pix_size_to_point(PEMF_CALLBACK_DATA d, double px) { double tmp = px; - tmp *= (double) PX_PER_IN / d->ScaleX; + tmp *= d->ScaleX ? (double) PX_PER_IN / d->ScaleX : 1.0; + return tmp; +} + + +static double +pix_to_size_point(PEMF_CALLBACK_DATA d, double px) +{ + double dx = pix_to_x_point(d, px, 0); + double dy = pix_to_y_point(d, px, 0); + double tmp = sqrt(dx * dx + dy * dy); return tmp; } @@ -324,27 +371,28 @@ select_pen(PEMF_CALLBACK_DATA d, int index) if (!pEmr) return; - switch (pEmr->lopn.lopnStyle) { + switch (pEmr->lopn.lopnStyle & PS_STYLE_MASK) { case PS_DASH: case PS_DOT: case PS_DASHDOT: case PS_DASHDOTDOT: { int i = 0; + int penstyle = (pEmr->lopn.lopnStyle & PS_STYLE_MASK); d->style.stroke_dash.n_dash = - PS_DASHDOTDOT ? 6 : PS_DASHDOT ? 4 : 2; + penstyle == PS_DASHDOTDOT ? 6 : penstyle == PS_DASHDOT ? 4 : 2; if (d->style.stroke_dash.dash) delete[] d->style.stroke_dash.dash; d->style.stroke_dash.dash = new double[d->style.stroke_dash.n_dash]; - if (pEmr->lopn.lopnStyle==PS_DASH || pEmr->lopn.lopnStyle==PS_DASHDOT || pEmr->lopn.lopnStyle==PS_DASHDOTDOT) { + if (penstyle==PS_DASH || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) { d->style.stroke_dash.dash[i++] = 3; d->style.stroke_dash.dash[i++] = 1; } - if (pEmr->lopn.lopnStyle==PS_DOT || pEmr->lopn.lopnStyle==PS_DASHDOT || pEmr->lopn.lopnStyle==PS_DASHDOTDOT) { + if (penstyle==PS_DOT || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) { d->style.stroke_dash.dash[i++] = 1; d->style.stroke_dash.dash[i++] = 1; } - if (pEmr->lopn.lopnStyle==PS_DASHDOTDOT) { + if (penstyle==PS_DASHDOTDOT) { d->style.stroke_dash.dash[i++] = 1; d->style.stroke_dash.dash[i++] = 1; } @@ -361,16 +409,54 @@ select_pen(PEMF_CALLBACK_DATA d, int index) } } + switch (pEmr->lopn.lopnStyle & PS_ENDCAP_MASK) { + case PS_ENDCAP_ROUND: + { + d->style.stroke_linecap.computed = 1; + break; + } + case PS_ENDCAP_SQUARE: + { + d->style.stroke_linecap.computed = 2; + break; + } + case PS_ENDCAP_FLAT: + default: + { + d->style.stroke_linecap.computed = 0; + break; + } + } + + switch (pEmr->lopn.lopnStyle & PS_JOIN_MASK) { + case PS_JOIN_BEVEL: + { + d->style.stroke_linejoin.computed = 2; + break; + } + case PS_JOIN_MITER: + { + d->style.stroke_linejoin.computed = 0; + break; + } + case PS_JOIN_ROUND: + default: + { + d->style.stroke_linejoin.computed = 1; + break; + } + } + d->stroke_set = true; if (pEmr->lopn.lopnStyle == PS_NULL) { d->style.stroke_width.value = 0; d->stroke_set = false; } else if (pEmr->lopn.lopnWidth.x) { - d->style.stroke_width.value = pix_size_to_point( d, pEmr->lopn.lopnWidth.x ); + d->style.stroke_width.value = pix_to_size_point( d, pEmr->lopn.lopnWidth.x ); } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?) //d->style.stroke_width.value = 1.0; - d->style.stroke_width.value = pix_size_to_point( d, 1 ); + d->style.stroke_width.value = pix_to_size_point( d, 1 ); } double r, g, b; @@ -378,8 +464,6 @@ select_pen(PEMF_CALLBACK_DATA d, int index) g = SP_COLOR_U_TO_F( GetGValue(pEmr->lopn.lopnColor) ); b = SP_COLOR_U_TO_F( GetBValue(pEmr->lopn.lopnColor) ); d->style.stroke.value.color.set( r, g, b ); - - d->style.stroke_linejoin.computed = 1; } @@ -403,7 +487,7 @@ select_extpen(PEMF_CALLBACK_DATA d, int index) delete[] d->style.stroke_dash.dash; d->style.stroke_dash.dash = new double[pEmr->elp.elpNumEntries]; for (unsigned int i=0; ielp.elpNumEntries; i++) { - d->style.stroke_dash.dash[i] = pix_size_to_point( d, pEmr->elp.elpStyleEntry[i] ); + d->style.stroke_dash.dash[i] = pix_to_size_point( d, pEmr->elp.elpStyleEntry[i] ); } d->style.stroke_dasharray_set = 1; } else { @@ -411,6 +495,37 @@ select_extpen(PEMF_CALLBACK_DATA d, int index) } break; } + + case PS_DASH: + case PS_DOT: + case PS_DASHDOT: + case PS_DASHDOTDOT: + { + int i = 0; + int penstyle = (pEmr->elp.elpPenStyle & PS_STYLE_MASK); + d->style.stroke_dash.n_dash = + penstyle == PS_DASHDOTDOT ? 6 : penstyle == PS_DASHDOT ? 4 : 2; + if (d->style.stroke_dash.dash) + delete[] d->style.stroke_dash.dash; + d->style.stroke_dash.dash = new double[d->style.stroke_dash.n_dash]; + if (penstyle==PS_DASH || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) { + d->style.stroke_dash.dash[i++] = 3; + d->style.stroke_dash.dash[i++] = 2; + } + if (penstyle==PS_DOT || penstyle==PS_DASHDOT || penstyle==PS_DASHDOTDOT) { + d->style.stroke_dash.dash[i++] = 1; + d->style.stroke_dash.dash[i++] = 2; + } + if (penstyle==PS_DASHDOTDOT) { + d->style.stroke_dash.dash[i++] = 1; + d->style.stroke_dash.dash[i++] = 2; + } + + d->style.stroke_dasharray_set = 1; + break; + } + + case PS_SOLID: default: { d->style.stroke_dasharray_set = 0; @@ -456,7 +571,17 @@ select_extpen(PEMF_CALLBACK_DATA d, int index) } } - d->style.stroke_width.value = pix_size_to_point( d, pEmr->elp.elpWidth ); + d->stroke_set = true; + + if (pEmr->elp.elpPenStyle == PS_NULL) { + d->style.stroke_width.value = 0; + d->stroke_set = false; + } else if (pEmr->elp.elpWidth) { + d->style.stroke_width.value = pix_to_size_point( d, pEmr->elp.elpWidth ); + } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?) + //d->style.stroke_width.value = 1.0; + d->style.stroke_width.value = pix_to_size_point( d, 1 ); + } double r, g, b; r = SP_COLOR_U_TO_F( GetRValue(pEmr->elp.elpColor) ); @@ -464,8 +589,6 @@ select_extpen(PEMF_CALLBACK_DATA d, int index) b = SP_COLOR_U_TO_F( GetBValue(pEmr->elp.elpColor) ); d->style.stroke.value.color.set( r, g, b ); - - d->stroke_set = true; } @@ -503,8 +626,22 @@ select_font(PEMF_CALLBACK_DATA d, int index) if (!pEmr) return; - d->style.font_size.computed = pix_size_to_point( d, pEmr->elfw.elfLogFont.lfHeight ); - d->style.font_weight.value = pEmr->elfw.elfLogFont.lfWeight; + d->style.font_size.computed = pix_to_size_point( d, pEmr->elfw.elfLogFont.lfHeight ); + d->style.font_weight.value = + pEmr->elfw.elfLogFont.lfWeight == FW_THIN ? SP_CSS_FONT_WEIGHT_100 : + pEmr->elfw.elfLogFont.lfWeight == FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_200 : + pEmr->elfw.elfLogFont.lfWeight == FW_LIGHT ? SP_CSS_FONT_WEIGHT_300 : + pEmr->elfw.elfLogFont.lfWeight == FW_NORMAL ? SP_CSS_FONT_WEIGHT_400 : + pEmr->elfw.elfLogFont.lfWeight == FW_MEDIUM ? SP_CSS_FONT_WEIGHT_500 : + pEmr->elfw.elfLogFont.lfWeight == FW_SEMIBOLD ? SP_CSS_FONT_WEIGHT_600 : + pEmr->elfw.elfLogFont.lfWeight == FW_BOLD ? SP_CSS_FONT_WEIGHT_700 : + pEmr->elfw.elfLogFont.lfWeight == FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_800 : + pEmr->elfw.elfLogFont.lfWeight == FW_HEAVY ? SP_CSS_FONT_WEIGHT_900 : + pEmr->elfw.elfLogFont.lfWeight == FW_NORMAL ? SP_CSS_FONT_WEIGHT_NORMAL : + pEmr->elfw.elfLogFont.lfWeight == FW_BOLD ? SP_CSS_FONT_WEIGHT_BOLD : + pEmr->elfw.elfLogFont.lfWeight == FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_LIGHTER : + pEmr->elfw.elfLogFont.lfWeight == FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_BOLDER : + FW_NORMAL; d->style.font_style.value = (pEmr->elfw.elfLogFont.lfItalic ? SP_CSS_FONT_STYLE_ITALIC : SP_CSS_FONT_STYLE_NORMAL); d->style.text_decoration.underline = pEmr->elfw.elfLogFont.lfUnderline; d->style.text_decoration.line_through = pEmr->elfw.elfLogFont.lfStrikeOut; @@ -536,6 +673,27 @@ insert_object(PEMF_CALLBACK_DATA d, int index, int type, ENHMETARECORD *pObj) } } +static void +assert_empty_path(PEMF_CALLBACK_DATA d, const char *fun) +{ + if (!d->path->empty()) { + g_debug("emf-win32-inout: assert_empty_path failed for %s\n", fun); + + *(d->outsvg) += "\n"; + + *(d->path) = ""; + } +} + static int CALLBACK myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nObj, LPARAM lpData) @@ -550,7 +708,9 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb if (d->pathless_stroke) { if (lpEMFR->iType!=EMR_POLYBEZIERTO && lpEMFR->iType!=EMR_POLYBEZIERTO16 && lpEMFR->iType!=EMR_POLYLINETO && lpEMFR->iType!=EMR_POLYLINETO16 && - lpEMFR->iType!=EMR_LINETO && lpEMFR->iType!=EMR_ARCTO) + lpEMFR->iType!=EMR_LINETO && lpEMFR->iType!=EMR_ARCTO && + lpEMFR->iType!=EMR_SETBKCOLOR && lpEMFR->iType!=EMR_SETROP2 && + lpEMFR->iType!=EMR_SETBKMODE) { *(d->outsvg) += " MMX << "mm\"\n" << " height=\"" << d->MMY << "mm\">\n"; + tmp_outsvg << "\n"; if (pEmr->nHandles) { d->n_obj = pEmr->nHandles; @@ -608,26 +769,35 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb if (pEmr->cptl<4) break; - *(d->outsvg) += " outsvg) += "\n\td=\""; + if (!d->inpath) { + assert_empty_path(d, "EMR_POLYBEZIER"); + + *(d->outsvg) += " outsvg) += "\n\td=\""; + } tmp_str << "\n\tM " << - pix_x_to_point( d, pEmr->aptl[0].x ) << " " << - pix_x_to_point( d, pEmr->aptl[0].y) << " "; + pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " << + pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y) << " "; for (i=1; icptl; ) { tmp_str << "\n\tC "; for (j=0; j<3 && icptl; j++,i++) { tmp_str << - pix_x_to_point( d, pEmr->aptl[i].x ) << " " << - pix_y_to_point( d, pEmr->aptl[i].y ) << " "; + pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << + pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; } } - *(d->outsvg) += tmp_str.str().c_str(); - *(d->outsvg) += " \" /> \n"; + if (d->inpath) { + tmp_path << tmp_str.str().c_str(); + } + else { + *(d->outsvg) += tmp_str.str().c_str(); + *(d->outsvg) += " \" /> \n"; + } break; } @@ -639,20 +809,22 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb if (pEmr->cptl < 2) break; + assert_empty_path(d, "EMR_POLYGON"); + *(d->outsvg) += " outsvg) += "\n\td=\""; tmp_str << "\n\tM " << - pix_x_to_point( d, pEmr->aptl[0].x ) << " " << - pix_y_to_point( d, pEmr->aptl[0].y ) << " "; + pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " << + pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " "; for (i=1; icptl; i++) { tmp_str << "\n\tL " << - pix_x_to_point( d, pEmr->aptl[i].x ) << " " << - pix_y_to_point( d, pEmr->aptl[i].y ) << " "; + pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << + pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; } *(d->outsvg) += tmp_str.str().c_str(); @@ -668,24 +840,33 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb if (pEmr->cptl<2) break; - *(d->outsvg) += " outsvg) += "\n\td=\""; + if (!d->inpath) { + assert_empty_path(d, "EMR_POLYLINE"); + + *(d->outsvg) += " outsvg) += "\n\td=\""; + } tmp_str << "\n\tM " << - pix_x_to_point( d, pEmr->aptl[0].x ) << " " << - pix_y_to_point( d, pEmr->aptl[0].y ) << " "; + pix_to_x_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " " << + pix_to_y_point( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " "; for (i=1; icptl; i++) { tmp_str << "\n\tL " << - pix_x_to_point( d, pEmr->aptl[i].x ) << " " << - pix_y_to_point( d, pEmr->aptl[i].y ) << " "; + pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << + pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; } - *(d->outsvg) += tmp_str.str().c_str(); - *(d->outsvg) += " \" /> \n"; + if (d->inpath) { + tmp_path << tmp_str.str().c_str(); + } + else { + *(d->outsvg) += tmp_str.str().c_str(); + *(d->outsvg) += " \" /> \n"; + } break; } @@ -694,15 +875,17 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb PEMRPOLYBEZIERTO pEmr = (PEMRPOLYBEZIERTO) lpEMFR; DWORD i,j; - if (d->path->empty()) + if (d->path->empty()) { + d->pathless_stroke = true; *(d->path) = "d=\""; + } for (i=0; icptl;) { tmp_path << "\n\tC "; for (j=0; j<3 && icptl; j++,i++) { tmp_path << - pix_x_to_point( d, pEmr->aptl[i].x ) << " " << - pix_y_to_point( d, pEmr->aptl[i].y ) << " "; + pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << + pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; } } @@ -713,14 +896,16 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb PEMRPOLYLINETO pEmr = (PEMRPOLYLINETO) lpEMFR; DWORD i; - if (d->path->empty()) + if (d->path->empty()) { + d->pathless_stroke = true; *(d->path) = "d=\""; + } for (i=0; icptl;i++) { tmp_path << "\n\tL " << - pix_x_to_point( d, pEmr->aptl[i].x ) << " " << - pix_y_to_point( d, pEmr->aptl[i].y ) << " "; + pix_to_x_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " " << + pix_to_y_point( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; } break; @@ -731,14 +916,13 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb PEMRPOLYPOLYGON pEmr = (PEMRPOLYPOLYGON) lpEMFR; unsigned int n, i, j; - if (lpEMFR->iType == EMR_POLYPOLYGON) - *(d->outsvg) += "\n"; - else - *(d->outsvg) += "\n"; + if (!d->inpath) { + assert_empty_path(d, lpEMFR->iType == EMR_POLYPOLYGON ? "EMR_POLYPOLYGON" : "EMR_POLYPOLYLINE"); - *(d->outsvg) += "iType==EMR_POLYPOLYGON ? EMR_STROKEANDFILLPATH : EMR_STROKEPATH); - *(d->outsvg) += "\n\td=\""; + *(d->outsvg) += " iType==EMR_POLYPOLYGON ? EMR_STROKEANDFILLPATH : EMR_STROKEPATH); + *(d->outsvg) += "\n\td=\""; + } POINTL *aptl = (POINTL *) &pEmr->aPolyCounts[pEmr->nPolys]; @@ -747,24 +931,31 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb SVGOStringStream poly_path; poly_path << "\n\tM " << - pix_x_to_point( d, aptl[i].x ) << " " << - pix_y_to_point( d, aptl[i].y ) << " "; + pix_to_x_point( d, aptl[i].x, aptl[i].y ) << " " << + pix_to_y_point( d, aptl[i].x, aptl[i].y ) << " "; i++; for (j=1; jaPolyCounts[n] && icptl; j++) { poly_path << "\n\tL " << - pix_x_to_point( d, aptl[i].x ) << " " << - pix_y_to_point( d, aptl[i].y ) << " "; + pix_to_x_point( d, aptl[i].x, aptl[i].y ) << " " << + pix_to_y_point( d, aptl[i].x, aptl[i].y ) << " "; i++; } - *(d->outsvg) += poly_path.str().c_str(); + tmp_str << poly_path.str().c_str(); if (lpEMFR->iType == EMR_POLYPOLYGON) - *(d->outsvg) += " z"; - *(d->outsvg) += " \n"; + tmp_str << " z"; + tmp_str << " \n"; + } + + if (d->inpath) { + tmp_path << tmp_str.str().c_str(); + } + else { + *(d->outsvg) += tmp_str.str().c_str(); + *(d->outsvg) += " \" /> \n"; } - *(d->outsvg) += " \" /> \n"; break; } case EMR_SETWINDOWEXTEX: @@ -797,6 +988,7 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb d->sizeView = pEmr->szlExtent; if (d->sizeWnd.cx && d->sizeWnd.cy) { + /* HDC hScreenDC = GetDC( NULL ); float scrPixelsX = (float)GetDeviceCaps( hScreenDC, HORZRES ); @@ -810,7 +1002,7 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb d->dwInchesY = d->sizeView.cy / (25.4f*scrPixelsY/scrMMY); d->xDPI = d->sizeWnd.cx / d->dwInchesX; d->yDPI = d->sizeWnd.cy / d->dwInchesY; - + */ if (1) { d->xDPI = 2540; d->yDPI = 2540; @@ -837,6 +1029,8 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb break; case EMR_EOF: { + assert_empty_path(d, "EMR_EOF"); + tmp_outsvg << "\n"; tmp_outsvg << "\n"; break; } @@ -856,8 +1050,8 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb { PEMRSETPOLYFILLMODE pEmr = (PEMRSETPOLYFILLMODE) lpEMFR; d->style.fill_rule.value = - (pEmr->iMode == WINDING ? 0 : - pEmr->iMode == ALTERNATE ? 1 : 0); + (pEmr->iMode == ALTERNATE ? 0 : + pEmr->iMode == WINDING ? 1 : 0); break; } case EMR_SETROP2: @@ -867,14 +1061,21 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb *(d->outsvg) += "\n"; break; case EMR_SETTEXTALIGN: - *(d->outsvg) += "\n"; + { + PEMRSETTEXTALIGN pEmr = (PEMRSETTEXTALIGN) lpEMFR; + d->textAlign = pEmr->iMode; break; + } case EMR_SETCOLORADJUSTMENT: *(d->outsvg) += "\n"; break; case EMR_SETTEXTCOLOR: - *(d->outsvg) += "\n"; + { + PEMRSETTEXTCOLOR pEmr = (PEMRSETTEXTCOLOR) lpEMFR; + d->textColor = pEmr->crColor; + d->textColorSet = true; break; + } case EMR_SETBKCOLOR: *(d->outsvg) += "\n"; break; @@ -892,8 +1093,8 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb tmp_path << "\n\tM " << - pix_x_to_point( d, pEmr->ptl.x ) << " " << - pix_y_to_point( d, pEmr->ptl.y ) << " "; + pix_to_x_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " " << + pix_to_y_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " "; break; } case EMR_SETMETARGN: @@ -918,11 +1119,117 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb *(d->outsvg) += "\n"; break; case EMR_SETWORLDTRANSFORM: - *(d->outsvg) += "\n"; + { + PEMRSETWORLDTRANSFORM pEmr = (PEMRSETWORLDTRANSFORM) lpEMFR; + d->worldTransform = pEmr->xform; break; + } case EMR_MODIFYWORLDTRANSFORM: - *(d->outsvg) += "\n"; + { + PEMRMODIFYWORLDTRANSFORM pEmr = (PEMRMODIFYWORLDTRANSFORM) lpEMFR; + switch (pEmr->iMode) + { + case MWT_IDENTITY: + d->worldTransform.eM11 = 1.0; + d->worldTransform.eM12 = 0.0; + d->worldTransform.eM21 = 0.0; + d->worldTransform.eM22 = 1.0; + d->worldTransform.eDx = 0.0; + d->worldTransform.eDy = 0.0; + break; + case MWT_LEFTMULTIPLY: + { +// d->worldTransform = pEmr->xform * worldTransform; + + float a11 = pEmr->xform.eM11; + float a12 = pEmr->xform.eM12; + float a13 = 0.0; + float a21 = pEmr->xform.eM21; + float a22 = pEmr->xform.eM22; + float a23 = 0.0; + float a31 = pEmr->xform.eDx; + float a32 = pEmr->xform.eDy; + float a33 = 1.0; + + float b11 = d->worldTransform.eM11; + float b12 = d->worldTransform.eM12; + //float b13 = 0.0; + float b21 = d->worldTransform.eM21; + float b22 = d->worldTransform.eM22; + //float b23 = 0.0; + float b31 = d->worldTransform.eDx; + float b32 = d->worldTransform.eDy; + //float b33 = 1.0; + + float c11 = a11*b11 + a12*b21 + a13*b31;; + float c12 = a11*b12 + a12*b22 + a13*b32;; + //float c13 = a11*b13 + a12*b23 + a13*b33;; + float c21 = a21*b11 + a22*b21 + a23*b31;; + float c22 = a21*b12 + a22*b22 + a23*b32;; + //float c23 = a21*b13 + a22*b23 + a23*b33;; + float c31 = a31*b11 + a32*b21 + a33*b31;; + float c32 = a31*b12 + a32*b22 + a33*b32;; + //float c33 = a31*b13 + a32*b23 + a33*b33;; + + d->worldTransform.eM11 = c11;; + d->worldTransform.eM12 = c12;; + d->worldTransform.eM21 = c21;; + d->worldTransform.eM22 = c22;; + d->worldTransform.eDx = c31; + d->worldTransform.eDy = c32; + + break; + } + case MWT_RIGHTMULTIPLY: + { +// d->worldTransform = worldTransform * pEmr->xform; + + float a11 = d->worldTransform.eM11; + float a12 = d->worldTransform.eM12; + float a13 = 0.0; + float a21 = d->worldTransform.eM21; + float a22 = d->worldTransform.eM22; + float a23 = 0.0; + float a31 = d->worldTransform.eDx; + float a32 = d->worldTransform.eDy; + float a33 = 1.0; + + float b11 = pEmr->xform.eM11; + float b12 = pEmr->xform.eM12; + //float b13 = 0.0; + float b21 = pEmr->xform.eM21; + float b22 = pEmr->xform.eM22; + //float b23 = 0.0; + float b31 = pEmr->xform.eDx; + float b32 = pEmr->xform.eDy; + //float b33 = 1.0; + + float c11 = a11*b11 + a12*b21 + a13*b31;; + float c12 = a11*b12 + a12*b22 + a13*b32;; + //float c13 = a11*b13 + a12*b23 + a13*b33;; + float c21 = a21*b11 + a22*b21 + a23*b31;; + float c22 = a21*b12 + a22*b22 + a23*b32;; + //float c23 = a21*b13 + a22*b23 + a23*b33;; + float c31 = a31*b11 + a32*b21 + a33*b31;; + float c32 = a31*b12 + a32*b22 + a33*b32;; + //float c33 = a31*b13 + a32*b23 + a33*b33;; + + d->worldTransform.eM11 = c11;; + d->worldTransform.eM12 = c12;; + d->worldTransform.eM21 = c21;; + d->worldTransform.eM22 = c22;; + d->worldTransform.eDx = c31; + d->worldTransform.eDy = c32; + + break; + } +// case MWT_SET: + default: + d->worldTransform = pEmr->xform; + break; + } break; + } case EMR_SELECTOBJECT: { PEMRSELECTOBJECT pEmr = (PEMRSELECTOBJECT) lpEMFR; @@ -980,7 +1287,7 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb } } } else { - if (index >= 0 && index < (unsigned int) d->n_obj) { + if ( /*index >= 0 &&*/ index < (unsigned int) d->n_obj) { switch (d->emf_obj[index].type) { case EMR_CREATEPEN: @@ -1006,7 +1313,7 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb int index = pEmr->ihPen; EMRCREATEPEN *pPen = - (EMRCREATEPEN *) malloc( sizeof(EMREXTCREATEPEN) ); + (EMRCREATEPEN *) malloc( sizeof(EMRCREATEPEN) ); pPen->lopn = pEmr->lopn; insert_object(d, index, EMR_CREATEPEN, (ENHMETARECORD *) pPen); @@ -1030,11 +1337,64 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb *(d->outsvg) += "\n"; break; case EMR_ELLIPSE: - *(d->outsvg) += "\n"; + { + PEMRELLIPSE pEmr = (PEMRELLIPSE) lpEMFR; + RECTL rclBox = pEmr->rclBox; + + double l = pix_to_x_point( d, pEmr->rclBox.left, pEmr->rclBox.top ); + double t = pix_to_y_point( d, pEmr->rclBox.left, pEmr->rclBox.top ); + double r = pix_to_x_point( d, pEmr->rclBox.right, pEmr->rclBox.bottom ); + double b = pix_to_y_point( d, pEmr->rclBox.right, pEmr->rclBox.bottom ); + + double cx = (l + r) / 2.0; + double cy = (t + b) / 2.0; + double rx = fabs(l - r) / 2.0; + double ry = fabs(t - b) / 2.0; + + SVGOStringStream tmp_ellipse; + tmp_ellipse << "cx=\"" << cx << "\" "; + tmp_ellipse << "cy=\"" << cy << "\" "; + tmp_ellipse << "rx=\"" << rx << "\" "; + tmp_ellipse << "ry=\"" << ry << "\" "; + + assert_empty_path(d, "EMR_ELLIPSE"); + + *(d->outsvg) += " iType); + *(d->outsvg) += "\n\t"; + *(d->outsvg) += tmp_ellipse.str().c_str(); + *(d->outsvg) += "/> \n"; + *(d->path) = ""; break; + } case EMR_RECTANGLE: - *(d->outsvg) += "\n"; + { + PEMRRECTANGLE pEmr = (PEMRRECTANGLE) lpEMFR; + RECTL rc = pEmr->rclBox; + + double l = pix_to_x_point( d, rc.left, rc.top ); + double t = pix_to_y_point( d, rc.left, rc.top ); + double r = pix_to_x_point( d, rc.right, rc.bottom ); + double b = pix_to_y_point( d, rc.right, rc.bottom ); + + SVGOStringStream tmp_rectangle; + tmp_rectangle << "d=\""; + tmp_rectangle << "\n\tM " << l << " " << t << " "; + tmp_rectangle << "\n\tL " << r << " " << t << " "; + tmp_rectangle << "\n\tL " << r << " " << b << " "; + tmp_rectangle << "\n\tL " << l << " " << b << " "; + tmp_rectangle << "\n\tz"; + + assert_empty_path(d, "EMR_RECTANGLE"); + + *(d->outsvg) += " iType); + *(d->outsvg) += "\n\t"; + *(d->outsvg) += tmp_rectangle.str().c_str(); + *(d->outsvg) += " \" /> \n"; + *(d->path) = ""; break; + } case EMR_ROUNDRECT: *(d->outsvg) += "\n"; break; @@ -1069,13 +1429,15 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb { PEMRLINETO pEmr = (PEMRLINETO) lpEMFR; - if (d->path->empty()) + if (d->path->empty()) { + d->pathless_stroke = true; *(d->path) = "d=\""; + } tmp_path << "\n\tL " << - pix_x_to_point( d, pEmr->ptl.x ) << " " << - pix_y_to_point( d, pEmr->ptl.y ) << " "; + pix_to_x_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " " << + pix_to_y_point( d, pEmr->ptl.x, pEmr->ptl.y ) << " "; break; } case EMR_ARCTO: @@ -1090,7 +1452,7 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb case EMR_SETMITERLIMIT: { PEMRSETMITERLIMIT pEmr = (PEMRSETMITERLIMIT) lpEMFR; - d->style.stroke_miterlimit.value = pix_size_to_point( d, pEmr->eMiterLimit ); + d->style.stroke_miterlimit.value = pix_to_size_point( d, pEmr->eMiterLimit ); if (d->style.stroke_miterlimit.value < 1) d->style.stroke_miterlimit.value = 1.0; @@ -1101,11 +1463,13 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb { tmp_path << "d=\""; *(d->path) = ""; + d->inpath = true; break; } case EMR_ENDPATH: { tmp_path << "\""; + d->inpath = false; break; } case EMR_CLOSEFIGURE: @@ -1194,69 +1558,81 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb { PEMREXTTEXTOUTW pEmr = (PEMREXTTEXTOUTW) lpEMFR; - double x = pEmr->emrtext.ptlReference.x; - double y = pEmr->emrtext.ptlReference.y; + double x1 = pEmr->emrtext.ptlReference.x; + double y1 = pEmr->emrtext.ptlReference.y; + + if (!(d->textAlign & TA_BOTTOM)) + y1 += fabs(d->style.font_size.computed); + + double x = pix_to_x_point(d, x1, y1); + double y = pix_to_y_point(d, x1, y1); - x = pix_x_to_point(d, x); - y = pix_y_to_point(d, y); + wchar_t *wide_text = (wchar_t *) ((char *) pEmr + pEmr->emrtext.offString); - wchar_t *text = (wchar_t *) ((char *) pEmr + pEmr->emrtext.offString); -/* - int i; - for (i=0; iemrtext.nChars; i++) { - if (text[i] < L' ' || text[i] > L'z') - text[i] = L'?'; - } -*/ - gchar *t = - (gchar *) g_utf16_to_utf8( (gunichar2 *) text, pEmr->emrtext.nChars, NULL, NULL, NULL ); + gchar *ansi_text = + (gchar *) g_utf16_to_utf8( (gunichar2 *) wide_text, pEmr->emrtext.nChars, NULL, NULL, NULL ); - if (t) { - SVGOStringStream ts; + if (ansi_text) { + gchar *p = ansi_text; + while (*p) { + if (*p < 32 || *p >= 127) { + g_free(ansi_text); + ansi_text = g_strdup(""); + break; + } + p++; + } - gchar *escaped = g_markup_escape_text(t, -1); + SVGOStringStream ts; - int j; - for (j=0; j 127) - escaped[j] = '?'; - } + gchar *escaped_text = g_markup_escape_text(ansi_text, -1); float text_rgb[3]; sp_color_get_rgb_floatv( &(d->style.fill.value.color), text_rgb ); + if (!d->textColorSet) { + d->textColor = RGB(SP_COLOR_F_TO_U(text_rgb[0]), + SP_COLOR_F_TO_U(text_rgb[1]), + SP_COLOR_F_TO_U(text_rgb[2])); + } + char tmp[128]; snprintf(tmp, 127, "fill:#%02x%02x%02x;", - SP_COLOR_F_TO_U(text_rgb[0]), - SP_COLOR_F_TO_U(text_rgb[1]), - SP_COLOR_F_TO_U(text_rgb[2])); + GetRValue(d->textColor), + GetGValue(d->textColor), + GetBValue(d->textColor)); bool i = (d->style.font_style.value == SP_CSS_FONT_STYLE_ITALIC); - bool o = (d->style.font_style.value == SP_CSS_FONT_STYLE_OBLIQUE); + //bool o = (d->style.font_style.value == SP_CSS_FONT_STYLE_OBLIQUE); bool b = (d->style.font_weight.value == SP_CSS_FONT_WEIGHT_BOLD) || (d->style.font_weight.value >= SP_CSS_FONT_WEIGHT_500 && d->style.font_weight.value <= SP_CSS_FONT_WEIGHT_900); + int lcr = ((d->textAlign & TA_CENTER) == TA_CENTER) ? 2 : ((d->textAlign & TA_RIGHT) == TA_RIGHT) ? 1 : 0; + + assert_empty_path(d, "EMR_EXTTEXTOUTW"); ts << " id++) << "\"\n"; ts << " xml:space=\"preserve\"\n"; ts << " x=\"" << x << "\"\n"; ts << " y=\"" << y << "\"\n"; ts << " style=\"" - << "font-size:" << d->style.font_size.computed << "px;" + << "font-size:" << fabs(d->style.font_size.computed) << "px;" << tmp << "font-style:" << (i ? "italic" : "normal") << ";" << "font-weight:" << (b ? "bold" : "normal") << ";" -// << "text-align:" << (b ? "start" : "center" : "end") << ";" + << "text-align:" << (lcr==2 ? "center" : lcr==1 ? "end" : "start") << ";" + << "text-anchor:" << (lcr==2 ? "middle" : lcr==1 ? "end" : "start") << ";" << "font-family:" << d->tstyle.font_family.value << ";" << "\"\n"; ts << " >"; - ts << escaped; + ts << escaped_text; ts << "\n"; *(d->outsvg) += ts.str().c_str(); - g_free(escaped); - g_free(t); + g_free(escaped_text); + g_free(ansi_text); } break; @@ -1270,26 +1646,35 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb if (pEmr->cpts<4) break; - *(d->outsvg) += " outsvg) += "\n\td=\""; + if (!d->inpath) { + assert_empty_path(d, "EMR_POLYBEZIER16"); + + *(d->outsvg) += " outsvg) += "\n\td=\""; + } tmp_str << "\n\tM " << - pix_x_to_point( d, apts[0].x ) << " " << - pix_y_to_point( d, apts[0].y ) << " "; + pix_to_x_point( d, apts[0].x, apts[0].y ) << " " << + pix_to_y_point( d, apts[0].x, apts[0].y ) << " "; for (i=1; icpts; ) { tmp_str << "\n\tC "; for (j=0; j<3 && icpts; j++,i++) { tmp_str << - pix_x_to_point( d, apts[i].x ) << " " << - pix_y_to_point( d, apts[i].y ) << " "; + pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << + pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; } } - *(d->outsvg) += tmp_str.str().c_str(); - *(d->outsvg) += " \" /> \n"; + if (d->inpath) { + tmp_path << tmp_str.str().c_str(); + } + else { + *(d->outsvg) += tmp_str.str().c_str(); + *(d->outsvg) += " \" /> \n"; + } break; } @@ -1297,24 +1682,28 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb { PEMRPOLYGON16 pEmr = (PEMRPOLYGON16) lpEMFR; POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ? + SVGOStringStream tmp_poly; unsigned int i; + unsigned int first = 0; - *(d->outsvg) += "outsvg) += " outsvg) += "\n\td=\""; - + // skip the first point? - tmp_path << "\n\tM " << - pix_x_to_point( d, apts[1].x ) << " " << - pix_y_to_point( d, apts[1].y ) << " "; - - for (i=2; icpts; i++) { - tmp_path << "\n\tL " << - pix_x_to_point( d, apts[i].x ) << " " << - pix_y_to_point( d, apts[i].y ) << " "; + tmp_poly << "\n\tM " << + pix_to_x_point( d, apts[first].x, apts[first].y ) << " " << + pix_to_y_point( d, apts[first].x, apts[first].y ) << " "; + + for (i=first+1; icpts; i++) { + tmp_poly << "\n\tL " << + pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << + pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; } - *(d->outsvg) += tmp_path.str().c_str(); + *(d->outsvg) += tmp_poly.str().c_str(); *(d->outsvg) += " z \" /> \n"; break; @@ -1328,24 +1717,33 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb if (pEmr->cpts<2) break; - *(d->outsvg) += " outsvg) += "\n\td=\""; + if (!d->inpath) { + assert_empty_path(d, "EMR_POLYLINE16"); + + *(d->outsvg) += " outsvg) += "\n\td=\""; + } tmp_str << "\n\tM " << - pix_x_to_point( d, apts[0].x ) << " " << - pix_y_to_point( d, apts[0].y ) << " "; + pix_to_x_point( d, apts[0].x, apts[0].y ) << " " << + pix_to_y_point( d, apts[0].x, apts[0].y ) << " "; for (i=1; icpts; i++) { tmp_str << "\n\tL " << - pix_x_to_point( d, apts[i].x ) << " " << - pix_y_to_point( d, apts[i].y ) << " "; + pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << + pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; } - *(d->outsvg) += tmp_str.str().c_str(); - *(d->outsvg) += " \" /> \n"; + if (d->inpath) { + tmp_path << tmp_str.str().c_str(); + } + else { + *(d->outsvg) += tmp_str.str().c_str(); + *(d->outsvg) += " \" /> \n"; + } break; } @@ -1355,15 +1753,17 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ? DWORD i,j; - if (d->path->empty()) + if (d->path->empty()) { + d->pathless_stroke = true; *(d->path) = "d=\""; + } for (i=0; icpts;) { tmp_path << "\n\tC "; for (j=0; j<3 && icpts; j++,i++) { tmp_path << - pix_x_to_point( d, apts[i].x ) << " " << - pix_y_to_point( d, apts[i].y ) << " "; + pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << + pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; } } @@ -1375,14 +1775,16 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb POINTS *apts = (POINTS *) pEmr->apts; // Bug in MinGW wingdi.h ? DWORD i; - if (d->path->empty()) + if (d->path->empty()) { + d->pathless_stroke = true; *(d->path) = "d=\""; + } for (i=0; icpts;i++) { tmp_path << "\n\tL " << - pix_x_to_point( d, apts[i].x ) << " " << - pix_y_to_point( d, apts[i].y ) << " "; + pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << + pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; } break; @@ -1393,14 +1795,13 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb PEMRPOLYPOLYGON16 pEmr = (PEMRPOLYPOLYGON16) lpEMFR; unsigned int n, i, j; - if (lpEMFR->iType == EMR_POLYPOLYGON16) - *(d->outsvg) += "\n"; - else - *(d->outsvg) += "\n"; + if (!d->inpath) { + assert_empty_path(d, lpEMFR->iType == EMR_POLYPOLYGON16 ? "EMR_POLYPOLYGON16" : "EMR_POLYPOLYLINE16"); - *(d->outsvg) += "iType==EMR_POLYPOLYGON16 ? EMR_STROKEANDFILLPATH : EMR_STROKEPATH); - *(d->outsvg) += "\n\td=\""; + *(d->outsvg) += " iType==EMR_POLYPOLYGON16 ? EMR_STROKEANDFILLPATH : EMR_STROKEPATH); + *(d->outsvg) += "\n\td=\""; + } POINTS *apts = (POINTS *) &pEmr->aPolyCounts[pEmr->nPolys]; @@ -1409,24 +1810,31 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb SVGOStringStream poly_path; poly_path << "\n\tM " << - pix_x_to_point( d, apts[i].x ) << " " << - pix_y_to_point( d, apts[i].y ) << " "; + pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << + pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; i++; for (j=1; jaPolyCounts[n] && icpts; j++) { poly_path << "\n\tL " << - pix_x_to_point( d, apts[i].x ) << " " << - pix_y_to_point( d, apts[i].y ) << " "; + pix_to_x_point( d, apts[i].x, apts[i].y ) << " " << + pix_to_y_point( d, apts[i].x, apts[i].y ) << " "; i++; } - *(d->outsvg) += poly_path.str().c_str(); + tmp_str << poly_path.str().c_str(); if (lpEMFR->iType == EMR_POLYPOLYGON16) - *(d->outsvg) += " z"; - *(d->outsvg) += " \n"; + tmp_str << " z"; + tmp_str << " \n"; + } + + if (d->inpath) { + tmp_path << tmp_str.str().c_str(); + } + else { + *(d->outsvg) += tmp_str.str().c_str(); + *(d->outsvg) += " \" /> \n"; } - *(d->outsvg) += " \" /> \n"; break; } case EMR_POLYDRAW16: @@ -1494,6 +1902,12 @@ myEnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, ENHMETARECORD *lpEMFR, int nOb return 1; } +static int CALLBACK +myMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, METARECORD *lpMFR, int nObj, LPARAM lpData) +{ + g_warning("Unable to import Windows Meta File.\n"); + return 0; +} // Aldus Placeable Header =================================================== // Since we are a 32bit app, we have to be sure this structure compiles to @@ -1517,8 +1931,17 @@ typedef struct SPDocument * EmfWin32::open( Inkscape::Extension::Input *mod, const gchar *uri ) { - EMF_CALLBACK_DATA d = {0}; + EMF_CALLBACK_DATA d; + + memset(&d, 0, sizeof(d)); + d.worldTransform.eM11 = 1.0; + d.worldTransform.eM12 = 0.0; + d.worldTransform.eM21 = 0.0; + d.worldTransform.eM22 = 1.0; + d.worldTransform.eDx = 0.0; + d.worldTransform.eDy = 0.0; + gsize bytesRead = 0; gsize bytesWritten = 0; GError* error = NULL; @@ -1536,8 +1959,25 @@ EmfWin32::open( Inkscape::Extension::Input *mod, const gchar *uri ) gunichar2 *unicode_fn = g_utf8_to_utf16( local_fn, -1, NULL, NULL, NULL ); WCHAR *unicode_uri = (WCHAR *) unicode_fn; - // Try open as Enhanced Metafile + DWORD filesize = 0; + HANDLE fp = NULL; + + HMETAFILE hmf; HENHMETAFILE hemf; + + if (PrintWin32::is_os_wide()) { + fp = CreateFileW(unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + } + else { + fp = CreateFileA(ansi_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + } + + if ( fp != INVALID_HANDLE_VALUE ) { + filesize = GetFileSize(fp, NULL); + CloseHandle(fp); + } + + // Try open as Enhanced Metafile if (PrintWin32::is_os_wide()) hemf = GetEnhMetaFileW(unicode_uri); else @@ -1545,7 +1985,6 @@ EmfWin32::open( Inkscape::Extension::Input *mod, const gchar *uri ) if (!hemf) { // Try open as Windows Metafile - HMETAFILE hmf; if (PrintWin32::is_os_wide()) hmf = GetMetaFileW(unicode_uri); else @@ -1574,6 +2013,10 @@ EmfWin32::open( Inkscape::Extension::Input *mod, const gchar *uri ) if (hmf) { DWORD nSize = GetMetaFileBitsEx( hmf, 0, NULL ); + + if (!nSize) + nSize = filesize; + if (nSize) { BYTE *lpvData = new BYTE[nSize]; if (lpvData) { @@ -1590,18 +2033,32 @@ EmfWin32::open( Inkscape::Extension::Input *mod, const gchar *uri ) hemf = SetWinMetaFileBits( nSize, lpvData, hDC, &mp ); // Clean up ReleaseDC( NULL, hDC ); + DeleteMetaFile( hmf ); + hmf = NULL; + } + else { + // EnumMetaFile } delete[] lpvData; } + else { + DeleteMetaFile( hmf ); + hmf = NULL; + } + } + else { DeleteMetaFile( hmf ); + hmf = NULL; } - } else { + } + else { // Try open as Aldus Placeable Metafile HANDLE hFile; if (PrintWin32::is_os_wide()) hFile = CreateFileW( unicode_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); else hFile = CreateFileA( ansi_uri, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + if (hFile != INVALID_HANDLE_VALUE) { DWORD nSize = GetFileSize( hFile, NULL ); if (nSize) { @@ -1633,20 +2090,30 @@ EmfWin32::open( Inkscape::Extension::Input *mod, const gchar *uri ) } } - if (!hemf || !d.outsvg || !d.path) { + if ((!hemf && !hmf) || !d.outsvg || !d.path) { if (d.outsvg) delete d.outsvg; if (d.path) delete d.path; - if (local_fn) + if (local_fn) g_free(local_fn); - if (unicode_fn) + if (unicode_fn) g_free(unicode_fn); + if (hemf) + DeleteEnhMetaFile(hemf); + if (hmf) + DeleteMetaFile(hmf); return NULL; } - EnumEnhMetaFile(NULL, hemf, myEnhMetaFileProc, (LPVOID) &d, NULL); - DeleteEnhMetaFile(hemf); + if (hemf) { + EnumEnhMetaFile(NULL, hemf, myEnhMetaFileProc, (LPVOID) &d, NULL); + DeleteEnhMetaFile(hemf); + } + else { + EnumMetaFile(NULL, hmf, myMetaFileProc, (LPARAM) &d); + DeleteMetaFile(hmf); + } // std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl; diff --git a/src/extension/internal/emf-win32-inout.h b/src/extension/internal/emf-win32-inout.h index 3ec81b6b5..6220c2190 100644 --- a/src/extension/internal/emf-win32-inout.h +++ b/src/extension/internal/emf-win32-inout.h @@ -4,7 +4,7 @@ * Authors: * Ulf Erikson * - * Copyright (C) 2006 Authors + * Copyright (C) 2006-2008 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ diff --git a/src/extension/internal/emf-win32-print.cpp b/src/extension/internal/emf-win32-print.cpp index 1616d5d86..5ee4b2f58 100644 --- a/src/extension/internal/emf-win32-print.cpp +++ b/src/extension/internal/emf-win32-print.cpp @@ -5,7 +5,7 @@ * Authors: * Ulf Erikson * - * Copyright (C) 2006 Authors + * Copyright (C) 2006-2008 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -35,6 +35,11 @@ #include "libnr/nr-point-matrix-ops.h" #include "libnr/nr-rect.h" #include "libnr/nr-matrix.h" +#include "libnr/nr-matrix-ops.h" +#include "libnr/nr-matrix-scale-ops.h" +#include "libnr/nr-matrix-translate-ops.h" +#include "libnr/nr-scale-translate-ops.h" +#include "libnr/nr-translate-scale-ops.h" #include "libnr/nr-matrix-fns.h" #include "libnr/nr-path.h" #include "libnr/nr-pixblock.h" @@ -85,7 +90,10 @@ PrintEmfWin32::PrintEmfWin32 (void): hbrush(NULL), hbrushOld(NULL), hpen(NULL), - fill_path(NULL) + fill_path(NULL), + stroke_and_fill(false), + fill_only(false), + simple_shape(false) { } @@ -164,12 +172,6 @@ PrintEmfWin32::begin (Inkscape::Extension::Print *mod, SPDocument *doc) // Get a Reference DC HDC hScreenDC = GetDC( NULL ); - // Get the physical characteristics of the reference DC - float PixelsX = (float) GetDeviceCaps( hScreenDC, HORZRES ); - float PixelsY = (float) GetDeviceCaps( hScreenDC, VERTRES ); - float MMX = (float) GetDeviceCaps( hScreenDC, HORZSIZE ); - float MMY = (float) GetDeviceCaps( hScreenDC, VERTSIZE ); - // Create the Metafile if (PrintWin32::is_os_wide()) hdc = CreateEnhMetaFileW( hScreenDC, unicode_uri, &rc, NULL ); @@ -196,8 +198,8 @@ PrintEmfWin32::begin (Inkscape::Extension::Print *mod, SPDocument *doc) // Set the viewport extent to reflect // dwInchesX" x dwInchesY" in device units SetViewportExtEx( hdc, - (int) ((float) dwInchesX*25.4f*PixelsX/MMX), - (int) ((float) dwInchesY*25.4f*PixelsY/MMY), + (int) ((float) dwInchesX*25.4f*PX_PER_MM), + (int) ((float) dwInchesY*25.4f*PX_PER_MM), NULL ); SetRect( &rc, 0, 0, (int) ceil(dwInchesX*dwDPI), (int) ceil(dwInchesY*dwDPI) ); @@ -205,6 +207,7 @@ PrintEmfWin32::begin (Inkscape::Extension::Print *mod, SPDocument *doc) g_free(local_fn); g_free(unicode_fn); + m_tr_stack.push( NR::scale(1, -1) * NR::translate(0, sp_document_height(doc))); return 0; } @@ -412,8 +415,12 @@ void PrintEmfWin32::flush_fill() { if (fill_path) { + stroke_and_fill = false; + fill_only = true; print_bpath(fill_path, &fill_transform, &fill_pbox); - FillPath( hdc ); + fill_only = false; + if (!simple_shape) + FillPath( hdc ); destroy_brush(); delete[] fill_path; fill_path = NULL; @@ -473,14 +480,23 @@ PrintEmfWin32::cmp_bpath(const NArtBpath *bp1, const NArtBpath *bp2) unsigned int PrintEmfWin32::bind(Inkscape::Extension::Print *mod, NR::Matrix const *transform, float opacity) { - text_transform = *transform; - return 0; + NR::Matrix tr = *transform; + + if (m_tr_stack.size()) { + NR::Matrix tr_top = m_tr_stack.top(); + m_tr_stack.push(tr * tr_top); + } else { + m_tr_stack.push(tr); + } + + return 1; } unsigned int PrintEmfWin32::release(Inkscape::Extension::Print *mod) { - return 0; + m_tr_stack.pop(); + return 1; } unsigned int @@ -490,6 +506,8 @@ PrintEmfWin32::fill(Inkscape::Extension::Print *mod, { if (!hdc) return 0; + NR::Matrix tf = m_tr_stack.top(); + flush_fill(); // flush any pending fills if (style->fill.isColor()) { @@ -501,7 +519,7 @@ PrintEmfWin32::fill(Inkscape::Extension::Print *mod, } fill_path = copy_bpath( bpath->path ); - fill_transform = *transform; + fill_transform = tf; fill_pbox = *pbox; // postpone fill in case of stroke-and-fill @@ -517,28 +535,32 @@ PrintEmfWin32::stroke (Inkscape::Extension::Print *mod, { if (!hdc) return 0; - bool stroke_and_fill = ( cmp_bpath( bpath->path, fill_path ) == 0 ); + NR::Matrix tf = m_tr_stack.top(); + + stroke_and_fill = ( cmp_bpath( bpath->path, fill_path ) == 0 ); if (!stroke_and_fill) { flush_fill(); // flush any pending fills } if (style->stroke.isColor()) { - create_pen(style, transform); + create_pen(style, &tf); } else { - // create_pen(NULL, transform); + // create_pen(NULL, &tf); return 0; } - print_bpath(bpath->path, transform, pbox); + print_bpath(bpath->path, &tf, pbox); if (stroke_and_fill) { - StrokeAndFillPath( hdc ); + if (!simple_shape) + StrokeAndFillPath( hdc ); destroy_brush(); delete[] fill_path; fill_path = NULL; } else { - StrokePath( hdc ); + if (!simple_shape) + StrokePath( hdc ); } destroy_pen(); @@ -547,12 +569,157 @@ PrintEmfWin32::stroke (Inkscape::Extension::Print *mod, } +bool +PrintEmfWin32::print_simple_shape(const NArtBpath *bpath, const NR::Matrix *transform, NRRect const *pbox) +{ + NR::Matrix tf = *transform; + const NArtBpath *bp = bpath; + + int nodes = 0; + int moves = 0; + int lines = 0; + int curves = 0; + + while (bp->code != NR_END) { + nodes++; + switch (bp->code) { + case NR_MOVETO: + case NR_MOVETO_OPEN: + moves++; + break; + case NR_LINETO: + lines++; + break; + case NR_CURVETO: + curves++; + break; + } + bp += 1; + } + + if (!nodes) + return false; + + POINT *lpPoints = new POINT[moves + lines + curves*3]; + int i = 0; + bp = bpath; + while (bp->code != NR_END) + { + using NR::X; + using NR::Y; + + NR::Point p1(bp->c(1) * tf); + NR::Point p2(bp->c(2) * tf); + NR::Point p3(bp->c(3) * tf); + + p1[X] = (p1[X] * IN_PER_PX * dwDPI); + p2[X] = (p2[X] * IN_PER_PX * dwDPI); + p3[X] = (p3[X] * IN_PER_PX * dwDPI); + p1[Y] = (p1[Y] * IN_PER_PX * dwDPI); + p2[Y] = (p2[Y] * IN_PER_PX * dwDPI); + p3[Y] = (p3[Y] * IN_PER_PX * dwDPI); + + LONG const x1 = (LONG) round(p1[X]); + LONG const y1 = (LONG) round(rc.bottom-p1[Y]); + LONG const x2 = (LONG) round(p2[X]); + LONG const y2 = (LONG) round(rc.bottom-p2[Y]); + LONG const x3 = (LONG) round(p3[X]); + LONG const y3 = (LONG) round(rc.bottom-p3[Y]); + + switch (bp->code) { + case NR_MOVETO: + case NR_MOVETO_OPEN: + case NR_LINETO: + lpPoints[i].x = x3; + lpPoints[i].y = y3; + i = i + 1; + break; + case NR_CURVETO: + lpPoints[i].x = x1; + lpPoints[i].y = y1; + lpPoints[i+1].x = x2; + lpPoints[i+1].y = y2; + lpPoints[i+2].x = x3; + lpPoints[i+2].y = y3; + i = i + 3; + break; + } + + bp += 1; + } + + bool done = false; + bool circular = (lpPoints[0].x == lpPoints[i-1].x) && (lpPoints[0].y == lpPoints[i-1].y); + bool polygon = false; + bool ellipse = false; + + if (moves == 1 && moves+lines == nodes && circular) { + polygon = true; + } + else if (moves == 1 && nodes == 5 && moves+curves == nodes && circular) { + if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x && + lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x && + lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x && + lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y && + lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y && + lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y) + { + ellipse = true; + } + } + + if (polygon || ellipse) { + HPEN hpenTmp = NULL; + HPEN hpenOld = NULL; + HBRUSH hbrushTmp = NULL; + HBRUSH hbrushOld = NULL; + + if (!stroke_and_fill) { + if (fill_only) { + hpenTmp = (HPEN) GetStockObject(NULL_PEN); + hpenOld = (HPEN) SelectObject( hdc, hpenTmp ); + } + else { // if (stroke_only) + hbrushTmp = (HBRUSH) GetStockObject(NULL_BRUSH); + hbrushOld = (HBRUSH) SelectObject( hdc, hbrushTmp ); + } + } + + if (polygon) { + Polygon( hdc, lpPoints, nodes ); + } + else if (ellipse) { + Ellipse( hdc, lpPoints[6].x, lpPoints[3].y, lpPoints[0].x, lpPoints[9].y); + } + + done = true; + + if (hpenOld) + SelectObject( hdc, hpenOld ); + if (hpenTmp) + DeleteObject( hpenTmp ); + if (hbrushOld) + SelectObject( hdc, hbrushOld ); + if (hbrushTmp) + DeleteObject( hbrushTmp ); + } + + delete[] lpPoints; + + return done; +} + unsigned int PrintEmfWin32::print_bpath(const NArtBpath *bp, const NR::Matrix *transform, NRRect const *pbox) { unsigned int closed; NR::Matrix tf = *transform; + simple_shape = print_simple_shape(bp, &tf, pbox); + + if (simple_shape) + return TRUE; + BeginPath( hdc ); closed = FALSE; while (bp->code != NR_END) { @@ -728,7 +895,7 @@ PrintEmfWin32::text(Inkscape::Extension::Print *mod, char const *text, NR::Point g_free(lf); } } - + HFONT hfontOld = (HFONT) SelectObject(hdc, hfont); float rgb[3]; @@ -739,26 +906,28 @@ PrintEmfWin32::text(Inkscape::Extension::Print *mod, char const *text, NR::Point style->text_align.value == SP_CSS_TEXT_ALIGN_RIGHT ? TA_RIGHT : style->text_align.value == SP_CSS_TEXT_ALIGN_CENTER ? TA_CENTER : TA_LEFT; SetTextAlign(hdc, TA_BASELINE | align); + SetBkMode(hdc, TRANSPARENT); + + NR::Matrix tf = m_tr_stack.top(); - p = p * text_transform; + p = p * tf; p[NR::X] = (p[NR::X] * IN_PER_PX * dwDPI); p[NR::Y] = (p[NR::Y] * IN_PER_PX * dwDPI); + LONG const xpos = (LONG) round(p[NR::X]); + LONG const ypos = (LONG) round(rc.bottom-p[NR::Y]); + if (PrintWin32::is_os_wide()) { gunichar2 *unicode_text = g_utf8_to_utf16( text, -1, NULL, NULL, NULL ); - TextOutW(hdc, p[NR::X], p[NR::Y], (WCHAR*)unicode_text, wcslen((wchar_t*)unicode_text)); + TextOutW(hdc, xpos, ypos, (WCHAR*)unicode_text, wcslen((wchar_t*)unicode_text)); } else { - TextOutA(hdc, p[NR::X], p[NR::Y], (CHAR*)text, strlen((char*)text)); + TextOutA(hdc, xpos, ypos, (CHAR*)text, strlen((char*)text)); } SelectObject(hdc, hfontOld); DeleteObject(hfont); - return 0; - - - return 0; } diff --git a/src/extension/internal/emf-win32-print.h b/src/extension/internal/emf-win32-print.h index c0eb58481..b885efbe1 100644 --- a/src/extension/internal/emf-win32-print.h +++ b/src/extension/internal/emf-win32-print.h @@ -7,7 +7,7 @@ * Author: * Ulf Erikson * - * Copyright (C) 2006 Authors + * Copyright (C) 2006-2008 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -28,6 +28,8 @@ #define WIN32_LEAN_AND_MEAN #include +#include + namespace Inkscape { namespace Extension { namespace Internal { @@ -42,13 +44,18 @@ class PrintEmfWin32 : public Inkscape::Extension::Implementation::Implementation HBRUSH hbrush, hbrushOld; HPEN hpen, hpenOld; + std::stack m_tr_stack; NArtBpath *fill_path; NArtBpath *fill_path_copy; NR::Matrix fill_transform; NRRect fill_pbox; - NR::Matrix text_transform; +// NR::Matrix text_transform; + bool stroke_and_fill; + bool fill_only; + bool simple_shape; unsigned int print_bpath (const NArtBpath *bp, const NR::Matrix *transform, NRRect const *pbox); + bool print_simple_shape (const NArtBpath *bp, const NR::Matrix *transform, NRRect const *pbox); public: PrintEmfWin32 (void); -- 2.30.2