summaryrefslogtreecommitdiffstats
path: root/src/extension/internal/emf-print.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/extension/internal/emf-print.cpp')
-rw-r--r--src/extension/internal/emf-print.cpp417
1 files changed, 356 insertions, 61 deletions
diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp
index 0df643130..3c27ac1b8 100644
--- a/src/extension/internal/emf-print.cpp
+++ b/src/extension/internal/emf-print.cpp
@@ -70,9 +70,8 @@ namespace Internal {
/* globals */
-static double PX2WORLD = 20.0f;
-static U_XFORM worldTransform;
-static bool FixPPTCharPos, FixPPTDashLine, FixPPTGrad2Polys, FixPPTPatternAsHatch, FixImageRot;
+static double PX2WORLD;
+static bool FixPPTCharPos, FixPPTDashLine, FixPPTGrad2Polys, FixPPTLinGrad, FixPPTPatternAsHatch, FixImageRot;
static EMFTRACK *et = NULL;
static EMFHANDLES *eht = NULL;
@@ -125,9 +124,12 @@ unsigned int PrintEmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc)
char *rec;
gchar const *utf8_fn = mod->get_param_string("destination");
+ // Typially PX2WORLD is 1200/90, using inkscape's default dpi
+ PX2WORLD = 1200.0 / Inkscape::Util::Quantity::convert(1.0, "in", "px");
FixPPTCharPos = mod->get_param_bool("FixPPTCharPos");
FixPPTDashLine = mod->get_param_bool("FixPPTDashLine");
FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys");
+ FixPPTLinGrad = mod->get_param_bool("FixPPTLinGrad");
FixPPTPatternAsHatch = mod->get_param_bool("FixPPTPatternAsHatch");
FixImageRot = mod->get_param_bool("FixImageRot");
@@ -179,12 +181,12 @@ unsigned int PrintEmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc)
float dwInchesX = d.width();
float dwInchesY = d.height();
- // dwInchesX x dwInchesY in micrometer units, dpi=90 -> 3543.3 dpm
- (void) drawing_size((int) ceil(dwInchesX * 25.4), (int) ceil(dwInchesY * 25.4), 3.543307, &rclBounds, &rclFrame);
+ // dwInchesX x dwInchesY in micrometer units, 1200 dpi/25.4 -> dpmm
+ (void) drawing_size((int) ceil(dwInchesX * 25.4), (int) ceil(dwInchesY * 25.4),1200.0/25.4, &rclBounds, &rclFrame);
// set up the reference device as 100 X A4 horizontal, (1200 dpi/25.4 -> dpmm). Extra digits maintain dpi better in EMF
- int MMX = 21600;
- int MMY = 27900;
+ int MMX = 216;
+ int MMY = 279;
(void) device_size(MMX, MMY, 1200.0 / 25.4, &szlDev, &szlMm);
int PixelsX = szlDev.cx;
int PixelsY = szlDev.cy;
@@ -220,13 +222,16 @@ unsigned int PrintEmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc)
}
- // Correct for dpi in EMF (1200) vs dpi in Inkscape (always 90).
- // Also correct for the scaling in PX2WORLD, which is set to 20.
+ // In earlier versions this was used to scale from inkscape's dpi of 90 to
+ // the files 1200 dpi, taking into account PX2WORLD which was 20. Now PX2WORLD
+ // is set so that this matrix is unitary. The usual value of PX2WORLD is 1200/90,
+ // but might be different if the internal dpi is changed.
- worldTransform.eM11 = 1200. / (90.0 * PX2WORLD);
+ U_XFORM worldTransform;
+ worldTransform.eM11 = 1.0;
worldTransform.eM12 = 0.0;
worldTransform.eM21 = 0.0;
- worldTransform.eM22 = 1200. / (90.0 * PX2WORLD);
+ worldTransform.eM22 = 1.0;
worldTransform.eDx = 0;
worldTransform.eDy = 0;
@@ -420,7 +425,7 @@ int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor)
hatchColor = avg_stop_color(rg);
}
} else if (lg) {
- if (FixPPTGrad2Polys) {
+ if (FixPPTGrad2Polys || FixPPTLinGrad) {
return hold_gradient(lg, fill_mode);
} else {
hatchColor = avg_stop_color(lg);
@@ -696,7 +701,7 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform)
n_dash = style->stroke_dash.n_dash;
dash = new uint32_t[n_dash];
for (i = 0; i < style->stroke_dash.n_dash; i++) {
- dash[i] = (uint32_t)(style->stroke_dash.dash[i]);
+ dash[i] = (uint32_t)(Inkscape::Util::Quantity::convert(1, "mm", "px") * style->stroke_dash.dash[i]);
}
}
}
@@ -780,6 +785,182 @@ void PrintEmf::destroy_pen()
}
}
+/* Return a Path consisting of just the corner points of the single path in a a PathVector. If the
+PathVector has more than one path, or that one path is open, or any of its segments are curved, then the
+returned PathVector is . If the input path is already just straight lines and vertices the output will be the
+same as the sole path in the input. */
+
+Geom::Path PrintEmf::pathv_to_simple_polygon(Geom::PathVector const &pathv, int *vertices)
+{
+ Geom::Point P1_trail;
+ Geom::Point P1;
+ Geom::Point P1_lead;
+ Geom::Point v1,v2;
+ Geom::Path output;
+ Geom::Path bad;
+ Geom::PathVector pv = pathv_to_linear_and_cubic_beziers(pathv);
+ Geom::PathVector::const_iterator pit = pv.begin();
+ Geom::PathVector::const_iterator pit2 = pv.begin();
+ ++pit2;
+ *vertices = 0;
+ if(pit->end_closed() != pit->end_default())return(bad); // path must be closed
+ if(pit2 != pv.end())return(bad); // there may only be one path
+ P1_trail = pit->finalPoint();
+ Geom::Path::const_iterator cit = pit->begin();
+ P1 = cit->initialPoint();
+ for(;cit != pit->end_closed();++cit) {
+ if (!is_straight_curve(*cit)) {
+ *vertices = 0;
+ return(bad);
+ }
+ P1_lead = cit->finalPoint();
+ if(Geom::are_near(P1_lead,P1))continue; // duplicate points at the same coordinate
+ v1 = unit_vector(P1 - P1_trail);
+ v2 = unit_vector(P1_lead - P1 );
+ if(Geom::are_near(dot(v1,v2),1.0)){ // P1 is within a straight line
+ P1 = P1_lead;
+ continue;
+ }
+ // P1 is the center point of a turn of some angle
+ if(!*vertices){
+ output.start( P1 );
+ output.close( pit->closed() );
+ }
+ *vertices += 1;
+ Geom::LineSegment ls(P1_trail, P1);
+ output.append(ls);
+ P1_trail = P1;
+ P1 = P1_lead;
+ }
+ return(output);
+}
+
+/* Returns the simplified PathVector (no matter what).
+ Sets is_rect if it is a rectangle.
+ Sets angle that will rotate side closest to horizontal onto horizontal.
+*/
+Geom::Path PrintEmf::pathv_to_rect(Geom::PathVector const &pathv, bool *is_rect, double *angle)
+{
+ Geom::Point P1_trail;
+ Geom::Point P1;
+ Geom::Point P1_lead;
+ Geom::Point v1,v2;
+ int vertices;
+ Geom::Path pR = pathv_to_simple_polygon(pathv, &vertices);
+ *is_rect = false;
+ if(vertices==4){ // or else it cannot be a rectangle rectangle
+ int vertex_count=0;
+ /* Get the ends of the LAST line segment.
+ Find minimum rotation to align rectangle with X,Y axes. (Very degenerate if it is rotated 45 degrees.) */
+ *angle = 10.0; /* must be > than the actual angle in radians. */
+ for(Geom::Path::const_iterator cit = pR.begin(); cit != pR.end_open(); ++cit){
+ P1_trail = cit->initialPoint();
+ P1 = cit->finalPoint();
+ v1 = unit_vector(P1 - P1_trail);
+ if(v1[Geom::X] > 0){ // only check the 1 or 2 points on vectors aimed the same direction as unit X
+ double ang = asin(v1[Geom::Y]); // because component is rotation by ang of {1,0| vector
+ if(fabs(ang) < fabs(*angle))*angle = -ang; // y increases down, flips sign on angle
+ }
+ }
+
+ for(Geom::Path::const_iterator cit = pR.begin(); cit != pR.end_open();++cit) {
+ P1_lead = cit->finalPoint();
+ v1 = unit_vector(P1 - P1_trail);
+ v2 = unit_vector(P1_lead - P1 );
+ if(!Geom::are_near(dot(v1,v2),0.0))break; // P1 is center of a turn that is not 90 degrees
+ P1_trail = P1;
+ P1 = P1_lead;
+ vertex_count++;
+ }
+ if(vertex_count == 4){
+ *is_rect=true;
+ }
+ }
+ return(pR);
+}
+
+/* Compare a vector with a rectangle's orientation (angle needed to rotate side(s)
+ closest to horizontal to exactly horizontal) and return:
+ 0 none of the following
+ 1 parallel to horizontal
+ 2 parallel to vertical
+ 3 antiparallel to horizontal
+ 4 antiparallel to vertical
+*/
+int PrintEmf::vector_rect_alignment(double angle, Geom::Point vtest){
+ int stat = 0;
+ Geom::Point v1 = Geom::unit_vector(vtest); // unit vector to test alignment
+ Geom::Point v2 = Geom::Point(1,0) * Geom::Rotate(-angle); // unit horizontal side (sign change because Y increases DOWN)
+ if( Geom::are_near(dot(v1,v2), 1.0)){ stat = 1; }
+ else if(Geom::are_near(dot(v1,v2),-1.0)){ stat = 2; }
+ if(!stat){
+ v2 = Geom::Point(0,1) * Geom::Rotate(-angle); // unit vertical side
+ if( Geom::are_near(dot(v1,v2), 1.0)){ stat = 3; }
+ else if(Geom::are_near(dot(v1,v2),-1.0)){ stat = 4; }
+ }
+ return(stat);
+}
+
+/* retrieve the point at the indicated corner:
+ 0 UL (and default)
+ 1 UR
+ 2 LR
+ 3 LL
+ Needed because the start can be any point, and the direction could run either
+ clockwise or counterclockwise. This should work even if the corners of the rectangle
+ are slightly displaced.
+*/
+Geom::Point PrintEmf::get_pathrect_corner(Geom::Path pathRect, double angle, int corner){
+ Geom::Point v1 = Geom::Point(1,0) * Geom::Rotate(-angle); // unit horizontal side (sign change because Y increases DOWN)
+ Geom::Point v2 = Geom::Point(0,1) * Geom::Rotate(-angle); // unit vertical side (sign change because Y increases DOWN)
+ Geom::Point center, P1;
+ int LR; // 1 if Left, 0 if Right
+ int UL; // 1 if Lower, 0 if Upper (as viewed on screen, y coordinates increase downwards)
+ center = Geom::Point(0,0);
+ Geom::Path::const_iterator cit = pathRect.begin();
+ for(; cit != pathRect.end_open();++cit) {
+ center += cit->initialPoint()/4.0;
+ }
+
+ switch(corner){
+ case 1: //UR
+ LR = 0;
+ UL = 0;
+ break;
+ case 2: //LR
+ LR = 0;
+ UL = 1;
+ break;
+ case 3: //LL
+ LR = 1;
+ UL = 1;
+ break;
+ default: //UL
+ LR = 1;
+ UL = 0;
+ break;
+ }
+ cit = pathRect.begin();
+ for(int i; cit != pathRect.end_open();++cit,i++) {
+ P1 = cit->initialPoint();
+ if((LR == (dot(P1 - center,v1)> 0 ? 0 : 1)) &&
+ (UL == (dot(P1 - center,v2)> 0 ? 1 : 0)))break;
+ }
+ return(P1);
+}
+
+U_TRIVERTEX PrintEmf::make_trivertex(Geom::Point Pt, U_COLORREF uc){
+ U_TRIVERTEX tv;
+ using Geom::X;
+ using Geom::Y;
+ tv.x = (int32_t) round(Pt[X]);
+ tv.y = (int32_t) round(Pt[Y]);
+ tv.Red = uc.Red << 8;
+ tv.Green = uc.Green << 8;
+ tv.Blue = uc.Blue << 8;
+ tv.Alpha = uc.Reserved << 8; // EMF will ignore this
+ return(tv);
+}
unsigned int PrintEmf::fill(
Inkscape::Extension::Print * /*mod*/,
@@ -795,8 +976,27 @@ unsigned int PrintEmf::fill(
use_stroke = false;
fill_transform = tf;
+
+ int brush_stat = create_brush(style, NULL);
+
+ /* native linear gradients are only used if the object is a rectangle AND the gradient is parallel to the sides of the object */
+ bool is_Rect = false;
+ double angle;
+ int rectDir=0;
+ Geom::Path pathRect;
+ if(FixPPTLinGrad && brush_stat && gv.mode == DRAW_LINEAR_GRADIENT){
+ pathRect = pathv_to_rect(pathv, &is_Rect, &angle);
+ if(is_Rect){
+ /* Gradientfill records can only be used if the gradient is parallel to the sides of the rectangle.
+ That must be checked here so that we can fall back to another form of gradient fill if it is not
+ the case. */
+ rectDir = vector_rect_alignment(angle, gv.p2 - gv.p1);
+ if(!rectDir)is_Rect = false;
+ }
+ if(!is_Rect && !FixPPTGrad2Polys)brush_stat=0; // fall all the way back to a solid fill
+ }
- if (create_brush(style, NULL)) { // only happens if the style is a gradient
+ if (brush_stat) { // only happens if the style is a gradient
/*
Handle gradients. Uses modified livarot as 2geom boolops is currently broken.
Can handle gradients with multiple stops.
@@ -819,10 +1019,10 @@ unsigned int PrintEmf::fill(
SPRadialGradient *tg = (SPRadialGradient *)(gv.grad); // linear/radial are the same here
nstops = tg->vector.stops.size();
sp_color_get_rgb_floatv(&tg->vector.stops[0].color, rgb);
- opa = tg->vector.stops[0].opacity;
+ opa = tg->vector.stops[0].opacity; // first stop
c1 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
sp_color_get_rgb_floatv(&tg->vector.stops[nstops - 1].color, rgb);
- opa = tg->vector.stops[nstops - 1].opacity;
+ opa = tg->vector.stops[nstops - 1].opacity; // last stop
c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
doff = 0.0;
@@ -868,9 +1068,10 @@ unsigned int PrintEmf::fill(
pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb);
print_pathv(pathvr, fill_transform); // show the intersection
- if (doff >= doff_range - doff_base) {
+ if (doff >= doff_range) {
istop++;
if (istop >= nstops) {
+ istop = nstops - 1;
continue; // could happen on a rounding error
}
doff_base = doff_range;
@@ -882,56 +1083,145 @@ unsigned int PrintEmf::fill(
}
}
} else if (gv.mode == DRAW_LINEAR_GRADIENT) {
- Geom::Point uv = Geom::unit_vector(gv.p2 - gv.p1); // unit vector
- Geom::Point puv = uv.cw(); // perp. to unit vector
- double range = Geom::distance(gv.p1, gv.p2); // length along the gradient
- double step = range / divisions; // adequate approximation for gradient
- double overlap = step / 4.0; // overlap slices slightly
- double start;
- double stop;
- Geom::PathVector pathvc, pathvr;
-
- /* before lower end of gradient, overlap first slice position */
- wc = weight_opacity(c1);
- (void) create_brush(style, &wc);
- pathvc = rect_cutter(gv.p1, uv * (overlap), uv * (-50000.0), puv * 50000.0);
- pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb);
- print_pathv(pathvr, fill_transform);
-
- /* after high end of gradient, overlap last slice poosition */
- wc = weight_opacity(c2);
- (void) create_brush(style, &wc);
- pathvc = rect_cutter(gv.p2, uv * (-overlap), uv * (50000.0), puv * 50000.0);
- pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb);
- print_pathv(pathvr, fill_transform);
+ if(is_Rect){
+ char *rec;
+ int gMode;
+ Geom::Point ul, ur, lr;
+ Geom::Point outUL, outLR; // UL,LR corners of a stop rectangle, in OUTPUT coordinates
+ U_TRIVERTEX ut[2];
+ U_GRADIENT4 ug4;
+ U_RECTL rcb;
+ Geom::Affine tf2;
+ U_XFORM tmpTransform;
+ double wRect, hRect;
+
+ /* coordinates, w,h and transform for the ENTIRE retangle */
+ ul = get_pathrect_corner(pathRect, angle, 0) * fill_transform * PX2WORLD;
+ ur = get_pathrect_corner(pathRect, angle, 1) * fill_transform * PX2WORLD;
+ lr = get_pathrect_corner(pathRect, angle, 2) * fill_transform * PX2WORLD;
+ wRect = Geom::distance(ul,ur);
+ hRect = Geom::distance(ur,lr);
+
+ /* The basic rectangle for all of these is placed with its UL corner at 0,0 with a size wRect,hRect.
+ Apply a world transform to place/scale it into the appropriate position on the drawing.
+ Actual gradientfill records are either this entire rectangle or slices of it as defined by the stops.
+ */
+
+ tf2 = Geom::Rotate(-angle);
+ tmpTransform.eM11 = tf2[0];
+ tmpTransform.eM12 = tf2[1];
+ tmpTransform.eM21 = tf2[2];
+ tmpTransform.eM22 = tf2[3];
+ tmpTransform.eDx = (ul)[Geom::X];
+ tmpTransform.eDy = (ul)[Geom::Y];
+
+ rec = U_EMRSAVEDC_set();
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::image at U_EMRSAVEDC_set");
+ }
- sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb);
- opa = tg->vector.stops[istop].opacity;
- c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
+ rec = U_EMRMODIFYWORLDTRANSFORM_set(tmpTransform, U_MWT_LEFTMULTIPLY);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::image at EMRMODIFYWORLDTRANSFORM");
+ }
+
+ for(;istop<nstops;istop++){
+ doff_range = tg->vector.stops[istop].offset; // next or last stop
+ if(rectDir == 1 || rectDir == 2){
+ outUL = Geom::Point(doff_base *wRect, 0 );
+ outLR = Geom::Point(doff_range*wRect, hRect);
+ gMode = U_GRADIENT_FILL_RECT_H;
+ }
+ else {
+ outUL = Geom::Point(0, doff_base *hRect);
+ outLR = Geom::Point(wRect,doff_range*hRect);
+ gMode = U_GRADIENT_FILL_RECT_V;
+ }
+ doff_base = doff_range;
+ rcb.left = outUL[X];
+ rcb.top = outUL[Y];
+ rcb.right = outLR[X];
+ rcb.bottom = outLR[Y];
+ sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb);
+ opa = tg->vector.stops[istop].opacity;
+ c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
+
+ if(rectDir == 2 || rectDir == 4){ // gradient is reversed, so swap colors
+ ut[0] = make_trivertex(outUL, c2);
+ ut[1] = make_trivertex(outLR, c1);
+ }
+ else {
+ ut[0] = make_trivertex(outUL, c1);
+ ut[1] = make_trivertex(outLR, c2);
+ }
+ c1 = c2; // for next stop
+ ug4.UpperLeft = 0;
+ ug4.LowerRight= 1;
+ /* NEED to push world transform here for rotations */
+ rec = U_EMRGRADIENTFILL_set(rcb, 2, 1, gMode, ut, (uint32_t *) &ug4 );
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::fill at U_EMRGRADIENTFILL_set");
+ }
+ }
- for (start = 0.0; start < range; start += step, doff += 1. / divisions) {
- stop = start + step + overlap;
- if (stop > range) {
- stop = range;
+ rec = U_EMRRESTOREDC_set(-1);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::fill at U_EMRRESTOREDC_set");
}
- pathvc = rect_cutter(gv.p1, uv * start, uv * stop, puv * 50000.0);
+ }
+ else {
+ Geom::Point uv = Geom::unit_vector(gv.p2 - gv.p1); // unit vector
+ Geom::Point puv = uv.cw(); // perp. to unit vector
+ double range = Geom::distance(gv.p1, gv.p2); // length along the gradient
+ double step = range / divisions; // adequate approximation for gradient
+ double overlap = step / 4.0; // overlap slices slightly
+ double start;
+ double stop;
+ Geom::PathVector pathvc, pathvr;
+
+ /* before lower end of gradient, overlap first slice position */
+ wc = weight_opacity(c1);
+ (void) create_brush(style, &wc);
+ pathvc = rect_cutter(gv.p1, uv * (overlap), uv * (-50000.0), puv * 50000.0);
+ pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb);
+ print_pathv(pathvr, fill_transform);
- wc = weight_colors(c1, c2, (doff - doff_base) / (doff_range - doff_base));
+ /* after high end of gradient, overlap last slice position */
+ wc = weight_opacity(c2);
(void) create_brush(style, &wc);
- Geom::PathVector pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb);
- print_pathv(pathvr, fill_transform); // show the intersection
+ pathvc = rect_cutter(gv.p2, uv * (-overlap), uv * (50000.0), puv * 50000.0);
+ pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb);
+ print_pathv(pathvr, fill_transform);
- if (doff >= doff_range - doff_base) {
- istop++;
- if (istop >= nstops) {
- continue; // could happen on a rounding error
+ sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb);
+ opa = tg->vector.stops[istop].opacity;
+ c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
+
+ for (start = 0.0; start < range; start += step, doff += 1. / divisions) {
+ stop = start + step + overlap;
+ if (stop > range) {
+ stop = range;
+ }
+ pathvc = rect_cutter(gv.p1, uv * start, uv * stop, puv * 50000.0);
+
+ wc = weight_colors(c1, c2, (doff - doff_base) / (doff_range - doff_base));
+ (void) create_brush(style, &wc);
+ Geom::PathVector pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb);
+ print_pathv(pathvr, fill_transform); // show the intersection
+
+ if (doff >= doff_range) {
+ istop++;
+ if (istop >= nstops) {
+ istop = nstops - 1;
+ continue; // could happen on a rounding error
+ }
+ doff_base = doff_range;
+ doff_range = tg->vector.stops[istop].offset; // next or last stop
+ c1 = c2;
+ sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb);
+ opa = tg->vector.stops[istop].opacity;
+ c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
}
- doff_base = doff_range;
- doff_range = tg->vector.stops[istop].offset; // next or last stop
- c1 = c2;
- sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb);
- opa = tg->vector.stops[istop].opacity;
- c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa);
}
}
} else {
@@ -1301,6 +1591,10 @@ unsigned int PrintEmf::image(
U_POINTL cDest = pointl_set(round(dw * PX2WORLD), round(dh * PX2WORLD));
U_POINTL Src = pointl_set(0, 0);
U_POINTL cSrc = pointl_set(w, h);
+ /* map the integer Dest coordinates back into pLL2, so that the rounded part does not destabilize the transform offset below */
+ pLL2[Geom::X] = Dest.x;
+ pLL2[Geom::Y] = Dest.y;
+ pLL2 /= PX2WORLD;
if (!FixImageRot) { /* Rotate images - some programs cannot read them in correctly if they are rotated */
tf[4] = tf[5] = 0.0; // get rid of the offset in the transform
Geom::Point pLL2prime = pLL2 * tf;
@@ -1309,7 +1603,7 @@ unsigned int PrintEmf::image(
tmpTransform.eM12 = tf[1];
tmpTransform.eM21 = tf[2];
tmpTransform.eM22 = tf[3];
- tmpTransform.eDx = (pLL2[Geom::X] - pLL2prime[Geom::X]) * PX2WORLD; //map pLL2 (now in EMF coordinates) back onto itself after the rotation
+ tmpTransform.eDx = (pLL2[Geom::X] - pLL2prime[Geom::X]) * PX2WORLD;
tmpTransform.eDy = (pLL2[Geom::Y] - pLL2prime[Geom::Y]) * PX2WORLD;
rec = U_EMRSAVEDC_set();
@@ -1734,6 +2028,7 @@ void PrintEmf::init(void)
"<param name=\"FixPPTCharPos\" type=\"boolean\">false</param>\n"
"<param name=\"FixPPTDashLine\" type=\"boolean\">false</param>\n"
"<param name=\"FixPPTGrad2Polys\" type=\"boolean\">false</param>\n"
+ "<param name=\"FixPPTLinGrad\" type=\"boolean\">false</param>\n"
"<param name=\"FixPPTPatternAsHatch\" type=\"boolean\">false</param>\n"
"<param name=\"FixImageRot\" type=\"boolean\">false</param>\n"
"<print/>\n"