=== modified file 'src/extension/internal/emf-inout.cpp' --- src/extension/internal/emf-inout.cpp 2012-10-12 23:00:15 +0000 +++ src/extension/internal/emf-inout.cpp 2012-10-24 21:34:55 +0000 @@ -390,17 +390,16 @@ EMF_DEVICE_CONTEXT dc[EMF_MAX_DC+1]; // FIXME: This should be dynamic.. int level; - double xDPI, yDPI; - uint32_t mask; // Draw properties - int arcdir; //U_AD_COUNTERCLOCKWISE 1 or U_AD_CLOCKWISE 2 + double ulCornerX,ulCornerY; // Upper left corner, from header rclBounds, in logical units + double ydir; // 1.0 if y is positive DOWN (usual case), -1.0 if y is negative DOWN + uint32_t mask; // Draw properties + int arcdir; //U_AD_COUNTERCLOCKWISE 1 or U_AD_CLOCKWISE 2 - uint32_t dwRop2; // Binary raster operation, 0 if none (use brush/pen unmolested) - uint32_t dwRop3; // Ternary raster operation, 0 if none (use brush/pen unmolested) + uint32_t dwRop2; // Binary raster operation, 0 if none (use brush/pen unmolested) + uint32_t dwRop3; // Ternary raster operation, 0 if none (use brush/pen unmolested) float MMX; float MMY; - float dwInchesX; - float dwInchesY; unsigned int id; unsigned int drawtype; // one of 0 or U_EMR_FILLPATH, U_EMR_STROKEPATH, U_EMR_STROKEANDFILLPATH @@ -629,17 +628,20 @@ ct, // DIB color table numCt, // DIB color table number of entries &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free. - width, // Width of pixel array - height, // Height of pixel array + width, // Width of pixel array in record + height, // Height of pixel array in record colortype, // DIB BitCount Enumeration numCt, // Color table used if not 0 - invert // If DIB rows are in opposite order from RGBA rows + invert, // If DIB rows are in opposite order from RGBA rows + 0,0, // start position in pixel array in record + width, // Width of extracted pixel array + height // Height of extracted pixel array ) && rgba_px) { toPNG( // Get the image from the RGBA px into mempng &mempng, - width, height, + width, height, // of the SRC bitmap rgba_px); free(rgba_px); } @@ -888,17 +890,23 @@ static double _pix_x_to_point(PEMF_CALLBACK_DATA d, double px) { - double tmp = px - d->dc[d->level].winorg.x; - tmp *= d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0; + double scale = (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0); + double tmp = px; + tmp -= d->dc[d->level].winorg.x; + tmp *= scale; + tmp -= d->ulCornerX; tmp += d->dc[d->level].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 py) { - double tmp = px - d->dc[d->level].winorg.y; - tmp *= d->dc[d->level].ScaleInY ? d->dc[d->level].ScaleInY : 1.0; + double scale = (d->dc[d->level].ScaleInY ? d->dc[d->level].ScaleInY : 1.0); + double tmp = py; + tmp -= d->dc[d->level].winorg.y; + tmp *= scale; + tmp += d->ydir*d->ulCornerY; tmp += d->dc[d->level].vieworg.y; return tmp; } @@ -907,10 +915,13 @@ static double pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py) { + double wpx = px * d->dc[d->level].worldTransform.eM11 + py * d->dc[d->level].worldTransform.eM21 + d->dc[d->level].worldTransform.eDx; + double x = _pix_x_to_point(d, wpx); +/* double ppx = _pix_x_to_point(d, px); double ppy = _pix_y_to_point(d, py); - double x = ppx * d->dc[d->level].worldTransform.eM11 + ppy * d->dc[d->level].worldTransform.eM21 + d->dc[d->level].worldTransform.eDx; +*/ x *= device_scale; return x; @@ -919,13 +930,18 @@ static double pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py) { + + double wpy = px * d->dc[d->level].worldTransform.eM12 + py * d->dc[d->level].worldTransform.eM22 + d->dc[d->level].worldTransform.eDy; + double y = _pix_y_to_point(d, wpy); +/* double ppx = _pix_x_to_point(d, px); double ppy = _pix_y_to_point(d, py); - double y = ppx * d->dc[d->level].worldTransform.eM12 + ppy * d->dc[d->level].worldTransform.eM22 + d->dc[d->level].worldTransform.eDy; +*/ y *= device_scale; return y; + } static double @@ -1123,8 +1139,13 @@ d->dc[d->level].style.stroke_dasharray_set = 1; break; } - case U_PS_SOLID: +/* includes these for now, some should maybe not be in here + case U_PS_NULL: + case U_PS_INSIDEFRAME: + case U_PS_ALTERNATE: + case U_PS_STYLE_MASK: +*/ default: { d->dc[d->level].style.stroke_dasharray_set = 0; @@ -1172,51 +1193,60 @@ d->dc[d->level].stroke_set = true; - if (pEmr->elp.elpPenStyle == U_PS_NULL) { + if (pEmr->elp.elpPenStyle == U_PS_NULL) { // draw nothing, but fill out all the values with something + double r, g, b; + r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor)); + g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor)); + b = SP_COLOR_U_TO_F( U_RGBAGetB(d->dc[d->level].textColor)); + d->dc[d->level].style.stroke.value.color.set( r, g, b ); d->dc[d->level].style.stroke_width.value = 0; d->dc[d->level].stroke_set = false; - } else if (pEmr->elp.elpWidth) { - int cur_level = d->level; - d->level = d->emf_obj[index].level; - double pen_width = pix_to_size_point( d, pEmr->elp.elpWidth ); - d->level = cur_level; - d->dc[d->level].style.stroke_width.value = pen_width; - } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?) - //d->dc[d->level].style.stroke_width.value = 1.0; - int cur_level = d->level; - d->level = d->emf_obj[index].level; - double pen_width = pix_to_size_point( d, 1 ); - d->level = cur_level; - d->dc[d->level].style.stroke_width.value = pen_width; + d->dc[d->level].stroke_mode = DRAW_PAINT; } + else { + if (pEmr->elp.elpWidth) { + int cur_level = d->level; + d->level = d->emf_obj[index].level; + double pen_width = pix_to_size_point( d, pEmr->elp.elpWidth ); + d->level = cur_level; + d->dc[d->level].style.stroke_width.value = pen_width; + } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?) + //d->dc[d->level].style.stroke_width.value = 1.0; + int cur_level = d->level; + d->level = d->emf_obj[index].level; + double pen_width = pix_to_size_point( d, 1 ); + d->level = cur_level; + d->dc[d->level].style.stroke_width.value = pen_width; + } - if( pEmr->elp.elpBrushStyle == U_BS_SOLID){ - double r, g, b; - r = SP_COLOR_U_TO_F( U_RGBAGetR(pEmr->elp.elpColor) ); - g = SP_COLOR_U_TO_F( U_RGBAGetG(pEmr->elp.elpColor) ); - b = SP_COLOR_U_TO_F( U_RGBAGetB(pEmr->elp.elpColor) ); - d->dc[d->level].style.stroke.value.color.set( r, g, b ); - d->dc[d->level].stroke_mode = DRAW_PAINT; - d->dc[d->level].stroke_set = true; - } - else if(pEmr->elp.elpBrushStyle == U_BS_HATCHED){ - d->dc[d->level].stroke_idx = add_hatch(d, pEmr->elp.elpHatch, pEmr->elp.elpColor); - d->dc[d->level].stroke_mode = DRAW_PATTERN; - d->dc[d->level].stroke_set = true; - } - else if(pEmr->elp.elpBrushStyle == U_BS_DIBPATTERN || pEmr->elp.elpBrushStyle == U_BS_DIBPATTERNPT){ - d->dc[d->level].stroke_idx = add_image(d, pEmr, pEmr->cbBits, pEmr->cbBmi, *(uint32_t *) &(pEmr->elp.elpColor), pEmr->offBits, pEmr->offBmi); - d->dc[d->level].stroke_mode = DRAW_IMAGE; - d->dc[d->level].stroke_set = true; - } - else { // U_BS_PATTERN and anything strange that falls in, stroke is solid textColor - double r, g, b; - r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor)); - g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor)); - b = SP_COLOR_U_TO_F( U_RGBAGetB(d->dc[d->level].textColor)); - d->dc[d->level].style.stroke.value.color.set( r, g, b ); - d->dc[d->level].stroke_mode = DRAW_PAINT; - d->dc[d->level].stroke_set = true; + if( pEmr->elp.elpBrushStyle == U_BS_SOLID){ + double r, g, b; + r = SP_COLOR_U_TO_F( U_RGBAGetR(pEmr->elp.elpColor) ); + g = SP_COLOR_U_TO_F( U_RGBAGetG(pEmr->elp.elpColor) ); + b = SP_COLOR_U_TO_F( U_RGBAGetB(pEmr->elp.elpColor) ); + d->dc[d->level].style.stroke.value.color.set( r, g, b ); + d->dc[d->level].stroke_mode = DRAW_PAINT; + d->dc[d->level].stroke_set = true; + } + else if(pEmr->elp.elpBrushStyle == U_BS_HATCHED){ + d->dc[d->level].stroke_idx = add_hatch(d, pEmr->elp.elpHatch, pEmr->elp.elpColor); + d->dc[d->level].stroke_mode = DRAW_PATTERN; + d->dc[d->level].stroke_set = true; + } + else if(pEmr->elp.elpBrushStyle == U_BS_DIBPATTERN || pEmr->elp.elpBrushStyle == U_BS_DIBPATTERNPT){ + d->dc[d->level].stroke_idx = add_image(d, pEmr, pEmr->cbBits, pEmr->cbBmi, *(uint32_t *) &(pEmr->elp.elpColor), pEmr->offBits, pEmr->offBmi); + d->dc[d->level].stroke_mode = DRAW_IMAGE; + d->dc[d->level].stroke_set = true; + } + else { // U_BS_PATTERN and anything strange that falls in, stroke is solid textColor + double r, g, b; + r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor)); + g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor)); + b = SP_COLOR_U_TO_F( U_RGBAGetB(d->dc[d->level].textColor)); + d->dc[d->level].style.stroke.value.color.set( r, g, b ); + d->dc[d->level].stroke_mode = DRAW_PAINT; + d->dc[d->level].stroke_set = true; + } } } @@ -1352,6 +1382,24 @@ } } +/* Identify probable Adobe Illustrator produced EMF files, which do strange things with the scaling. + The few so far observed all had this format. +*/ +int AI_hack(PU_EMRHEADER pEmr){ + int ret=0; + char *ptr; + ptr = (char *)pEmr; + PU_EMRSETMAPMODE nEmr = (PU_EMRSETMAPMODE) (ptr + pEmr->emr.nSize); + char *string = NULL; + if(pEmr->nDescription)string = U_Utf16leToUtf8((uint16_t *)((char *) pEmr + pEmr->offDescription), pEmr->nDescription, NULL); + if((pEmr->nDescription >= 13) && + (0==strcmp("Adobe Systems",string)) && + (nEmr->emr.iType == U_EMR_SETMAPMODE) && + (nEmr->iMode == U_MM_ANISOTROPIC)){ ret=1; } + if(string)free(string); + return(ret); +} + /** \fn create a UTF-32LE buffer and fill it with UNICODE unknown character \param count number of copies of the Unicode unknown character to fill with @@ -1364,10 +1412,27 @@ return res; } -void common_image_extraction(PEMF_CALLBACK_DATA d, void *pEmr, double l, double t, double r, double b, +/** + \fn store SVG for an image given the pixmap and various coordinate information + \param d + \param pEmr + \param dl (double) destination left in inkscape pixels + \param dt (double) destination top in inkscape pixels + \param dr (double) destination right in inkscape pixels + \param db (double) destination bottom in inkscape pixels + \param sl (int) source left in pixels in the src image + \param st (int) source top in pixels in the src image + \param iUsage + \param offBits + \param cbBits + \param offBmi + \param cbBmi +*/ +void common_image_extraction(PEMF_CALLBACK_DATA d, void *pEmr, + double dl, double dt, double dr, double db, int sl, int st, int sw, int sh, uint32_t iUsage, uint32_t offBits, uint32_t cbBits, uint32_t offBmi, uint32_t cbBmi){ SVGOStringStream tmp_image; - tmp_image << " y=\"" << t << "\"\n x=\"" << l <<"\"\n "; + tmp_image << " y=\"" << dt << "\"\n x=\"" << dl <<"\"\n "; // The image ID is filled in much later when tmp_image is converted @@ -1395,6 +1460,10 @@ &colortype, &invert )){ + if(sw == 0 || sl == 0){ + sw = width; + sh = height; + } if(!DIB_to_RGBA( px, // DIB pixel array @@ -1405,13 +1474,15 @@ height, // Height of pixel array colortype, // DIB BitCount Enumeration numCt, // Color table used if not 0 - invert // If DIB rows are in opposite order from RGBA rows + invert, // If DIB rows are in opposite order from RGBA rows + sl,st, // starting point in pixel array + sw,sh // columns/rows to extract from the pixel array (output array size) ) && rgba_px) { toPNG( // Get the image from the RGBA px into mempng &mempng, - width, height, + sw, sh, // size of the extracted pixel array rgba_px); free(rgba_px); } @@ -1427,7 +1498,7 @@ tmp_image << "iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII="; } - tmp_image << "\"\n height=\"" << b-t+1 << "\"\n width=\"" << r-l+1 << "\"\n"; + tmp_image << "\"\n height=\"" << db-dt+1 << "\"\n width=\"" << dr-dl+1 << "\"\n"; *(d->outsvg) += "\n\t outsvg) += tmp_image.str().c_str(); @@ -1535,29 +1606,42 @@ tmp_outdef << " xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\"\n"; // needed for sodipodi:role tmp_outdef << " version=\"1.0\"\n"; - d->xDPI = 2540; - d->yDPI = 2540; - - d->dc[d->level].PixelsInX = pEmr->rclFrame.right; // - pEmr->rclFrame.left; - d->dc[d->level].PixelsInY = pEmr->rclFrame.bottom; // - pEmr->rclFrame.top; - - d->MMX = d->dc[d->level].PixelsInX / 100.0; - d->MMY = d->dc[d->level].PixelsInY / 100.0; - - d->dc[d->level].PixelsOutX = d->MMX * PX_PER_MM; - d->dc[d->level].PixelsOutY = d->MMY * PX_PER_MM; - + d->ulCornerX = pEmr->rclBounds.left; // Upper left corner, from header rclBounds, in logical units, usually both 0, but not always + d->ulCornerY = pEmr->rclBounds.top;; + + if(pEmr->rclFrame.bottom < 0 || pEmr->rclFrame.top < 0){ d->ydir = -1.0; } + else { d->ydir = 1.0; } + + /* inclusive-inclusive, so the size is 1 more than the difference */ + d->dc[d->level].PixelsInX = pEmr->rclFrame.right - pEmr->rclFrame.left + 1; + d->dc[d->level].PixelsInY = pEmr->rclFrame.bottom - pEmr->rclFrame.top + 1; /* calculate ratio of Inkscape dpi/device dpi - This can cause problems later due to accuracy limits in the EMF. A super high resolution + This can cause problems later due to accuracy limits in the EMF. A high resolution EMF might have a final device_scale of 0.074998, and adjusting the (integer) device size by 1 will still not get it exactly to 0.075. Later when the font size is calculated it can end up as 29.9992 or 22.4994 instead of the intended 30 or 22.5. This is handled by - snapping font sizes to the nearest .01. - */ - if (pEmr->szlMillimeters.cx && pEmr->szlDevice.cx) - device_scale = PX_PER_MM*pEmr->szlMillimeters.cx/pEmr->szlDevice.cx; - + snapping font sizes to the nearest .01. The best estimate is made by using both values. + */ + if (pEmr->szlMillimeters.cx && pEmr->szlDevice.cx) device_scale = PX_PER_MM * + (pEmr->szlMillimeters.cx + pEmr->szlMillimeters.cy)/( pEmr->szlDevice.cx + pEmr->szlDevice.cy); + + /* Adobe Illustrator files set mapmode to MM_ANISOTROPIC and somehow or other this + converts the rclFrame values from MM_HIMETRIC to MM_HIENGLISH, with another factor of 3 thrown + in for good measure. Ours not to question why... + */ + if(AI_hack(pEmr)){ + d->dc[d->level].PixelsInX *= 25.4/(10.0*3.0); + d->dc[d->level].PixelsInY *= 25.4/(10.0*3.0); + device_scale *= 25.4/(10.0*3.0); + } + + d->MMX = d->dc[d->level].PixelsInX / 100.0; + d->MMY = d->dc[d->level].PixelsInY / 100.0; + + d->dc[d->level].PixelsOutX = d->MMX * PX_PER_MM; + d->dc[d->level].PixelsOutY = d->MMY * PX_PER_MM; + tmp_outdef << " width=\"" << d->MMX << "mm\"\n" << " height=\"" << d->MMY << "mm\">\n"; @@ -1849,7 +1933,43 @@ } case U_EMR_SETPIXELV: dbg_str << "\n"; break; case U_EMR_SETMAPPERFLAGS: dbg_str << "\n"; break; - case U_EMR_SETMAPMODE: dbg_str << "\n"; break; + case U_EMR_SETMAPMODE: + { + dbg_str << "\n"; + PU_EMRSETMAPMODE pEmr = (PU_EMRSETMAPMODE) lpEMFR; + switch (pEmr->iMode){ + case U_MM_TEXT: + default: + d->ydir = 1.0; + // leave device_scale as is, device_scale maps LU pixels to inkscape pixels as set in the EMF header + break; + case U_MM_LOMETRIC: // 1 LU = 0.1 mm + d->ydir = -1.0; + device_scale = 0.1 * PX_PER_MM; + break; + case U_MM_HIMETRIC: // 1 LU = 0.01 mm + d->ydir = -1.0; + device_scale = 0.01 * PX_PER_MM; + break; + case U_MM_LOENGLISH: // 1 LU = 0.1 in + d->ydir = -1.0; + device_scale = 0.1 * PX_PER_IN; + break; + case U_MM_HIENGLISH: // 1 LU = 0.01 in + d->ydir = -1.0; + device_scale = 0.01 * PX_PER_IN; + break; + case U_MM_TWIPS: // 1 LU = 1/1440 in + d->ydir = -1.0; + device_scale = (1.0/1440.0) * PX_PER_IN; + break; + case U_MM_ISOTROPIC: // let scaleX etc. handle it, as set by SETVIEWPORTEXTEX and SETWINDOWEXTEX + break; + case U_MM_ANISOTROPIC: + break; + } + break; + } case U_EMR_SETBKMODE: dbg_str << "\n"; break; case U_EMR_SETPOLYFILLMODE: { @@ -2540,20 +2660,27 @@ dbg_str << "\n"; PU_EMRBITBLT pEmr = (PU_EMRBITBLT) lpEMFR; - double l = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y); - double t = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y); - double r = pix_to_x_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y); - double b = pix_to_y_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y); + double dl = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y); + double dt = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y); + double dr = pix_to_x_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y); + double db = pix_to_y_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y); + //source position within the bitmap, in pixels + int sl = pEmr->Src.x + pEmr->xformSrc.eDx; + int st = pEmr->Src.y + pEmr->xformSrc.eDy; + int sw = 0; // extract all of the image + int sh = 0; + if(sl<0)sl=0; + if(st<0)st=0; // Treat all nonImage bitblts as a rectangular write. Definitely not correct, but at // least it leaves objects where the operations should have been. if (!pEmr->cbBmiSrc) { // should be an application of a DIBPATTERNBRUSHPT, use a solid color instead SVGOStringStream tmp_rectangle; - 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\tM " << dl << " " << dt << " "; + tmp_rectangle << "\n\tL " << dr << " " << dt << " "; + tmp_rectangle << "\n\tL " << dr << " " << db << " "; + tmp_rectangle << "\n\tL " << dl << " " << db << " "; tmp_rectangle << "\n\tz"; d->mask |= emr_mask; @@ -2563,7 +2690,7 @@ tmp_path << tmp_rectangle.str().c_str(); } else { - common_image_extraction(d,pEmr,l,t,r,b, + common_image_extraction(d,pEmr,dl,dt,dr,db,sl,st,sw,sh, pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc); } break; @@ -2574,11 +2701,18 @@ PU_EMRSTRETCHBLT pEmr = (PU_EMRSTRETCHBLT) lpEMFR; // Always grab image, ignore modes. if (pEmr->cbBmiSrc) { - double l = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y); - double t = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y); - double r = pix_to_x_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y); - double b = pix_to_y_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y); - common_image_extraction(d,pEmr,l,t,r,b, + double dl = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y); + double dt = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y); + double dr = pix_to_x_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y); + double db = pix_to_y_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y); + //source position within the bitmap, in pixels + int sl = pEmr->Src.x + pEmr->xformSrc.eDx; + int st = pEmr->Src.y + pEmr->xformSrc.eDy; + int sw = pEmr->cSrc.x; // extract the specified amount of the image + int sh = pEmr->cSrc.y; + if(sl<0)sl=0; + if(st<0)st=0; + common_image_extraction(d,pEmr,dl,dt,dr,db,sl,st,sw,sh, pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc); } break; @@ -2589,11 +2723,17 @@ PU_EMRMASKBLT pEmr = (PU_EMRMASKBLT) lpEMFR; // Always grab image, ignore masks and modes. if (pEmr->cbBmiSrc) { - double l = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y); - double t = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y); - double r = pix_to_x_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y); - double b = pix_to_y_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y); - common_image_extraction(d,pEmr,l,t,r,b, + double dl = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y); + double dt = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y); + double dr = pix_to_x_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y); + double db = pix_to_y_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y); + int sl = pEmr->Src.x + pEmr->xformSrc.eDx; //source position within the bitmap, in pixels + int st = pEmr->Src.y + pEmr->xformSrc.eDy; + int sw = 0; // extract all of the image + int sh = 0; + if(sl<0)sl=0; + if(st<0)st=0; + common_image_extraction(d,pEmr,dl,dt,dr,db,sl,st,sw,sh, pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc); } break; @@ -2609,11 +2749,17 @@ // user can sort out transparency later using Gimp, if need be. PU_EMRSTRETCHDIBITS pEmr = (PU_EMRSTRETCHDIBITS) lpEMFR; - double l = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y ); - double t = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y ); - double r = pix_to_x_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y ); - double b = pix_to_y_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y ); - common_image_extraction(d,pEmr,l,t,r,b, + double dl = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y ); + double dt = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y ); + double dr = pix_to_x_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y ); + double db = pix_to_y_point( d, pEmr->Dest.x + pEmr->cDest.x, pEmr->Dest.y + pEmr->cDest.y ); + int sl = pEmr->Src.x; //source position within the bitmap, in pixels + int st = pEmr->Src.y; + int sw = pEmr->cSrc.x; // extract the specified amount of the image + int sh = pEmr->cSrc.y; + if(sl<0)sl=0; + if(st<0)st=0; + common_image_extraction(d,pEmr,dl,dt,dr,db,sl,st,sw,sh, pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc); dbg_str << "\n"; @@ -2708,7 +2854,7 @@ ansi_text = (char *) U_Utf32leToUtf8((uint32_t *)dup_wt, 0, NULL); free(dup_wt); // Empty string or starts with an invalid escape/control sequence, which is bogus text. Throw it out before g_markup_escape_text can make things worse - if(*ansi_text <= 0x1F){ + if(*((uint8_t *)ansi_text) <= 0x1F){ free(ansi_text); ansi_text=NULL; } === modified file 'src/extension/internal/emf-print.cpp' --- src/extension/internal/emf-print.cpp 2012-10-04 08:04:48 +0000 +++ src/extension/internal/emf-print.cpp 2012-10-24 21:24:06 +0000 @@ -344,10 +344,10 @@ // 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); - // set up the device as A4 horizontal, 47.244094 dpmm (1200 dpi) - int MMX = 216; - int MMY = 279; - (void) device_size(MMX, MMY, 47.244094, &szlDev, &szlMm); // Drawing: A4 horizontal, 42744 dpm (1200 dpi) + // 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; + (void) device_size(MMX, MMY, 1200.0/25.4, &szlDev, &szlMm); int PixelsX = szlDev.cx; int PixelsY = szlDev.cy; @@ -381,17 +381,15 @@ } - // Correct for dpi in EMF vs dpi in Inkscape (always 90?) - // Also correct for the scaling in PX2WORLD, which is set to 20. Doesn't hurt for high resolution, - // helps prevent rounding errors for low resolution EMF. Low resolution EMF is possible if there - // are no print devices and the screen resolution is low. + // Correct for dpi in EMF (1200) vs dpi in Inkscape (always 90). + // Also correct for the scaling in PX2WORLD, which is set to 20. - worldTransform.eM11 = ((float)PixelsX * 25.4f)/((float)MMX*90.0f*PX2WORLD); - worldTransform.eM12 = 0.0f; - worldTransform.eM21 = 0.0f; - worldTransform.eM22 = ((float)PixelsY * 25.4f)/((float)MMY*90.0f*PX2WORLD); - worldTransform.eDx = 0; - worldTransform.eDy = 0; + worldTransform.eM11 = 1200./(90.0*PX2WORLD); + worldTransform.eM12 = 0.0; + worldTransform.eM21 = 0.0; + worldTransform.eM22 = 1200./(90.0*PX2WORLD); + worldTransform.eDx = 0; + worldTransform.eDy = 0; rec = U_EMRMODIFYWORLDTRANSFORM_set(worldTransform, U_MWT_LEFTMULTIPLY); if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){ @@ -785,7 +783,7 @@ int linecap = 0; int linejoin = 0; uint32_t pen; - uint32_t penStyle; + uint32_t brushStyle; GdkPixbuf *pixbuf; int hatchType; U_COLORREF hatchColor; @@ -803,7 +801,7 @@ if (!et) return 0; // set a default stroke in case we can't figure out a better way to do it - penStyle = U_BS_SOLID; + brushStyle = U_BS_SOLID; hatchColor = U_RGB(0, 0, 0); hatchType = U_HS_HORIZONTAL; @@ -819,7 +817,7 @@ height = dheight; brush_classify(pat,0,&pixbuf,&hatchType,&hatchColor); if(pixbuf){ - penStyle = U_BS_DIBPATTERN; + brushStyle = U_BS_DIBPATTERN; rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // Do NOT free this!!! colortype = U_BCBM_COLOR32; (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width*4, colortype, 0, 1); @@ -830,7 +828,7 @@ Bmi = bitmapinfo_set(Bmih, ct); } else { // pattern - penStyle = U_BS_HATCHED; + brushStyle = U_BS_HATCHED; if(hatchType == -1){ // Not a standard hatch, so force it to something hatchType = U_HS_CROSS; hatchColor = U_RGB(0xFF,0xC3,0xC3); @@ -838,7 +836,7 @@ } if(FixPPTPatternAsHatch){ if(hatchType == -1){ // image or unclassified - penStyle = U_BS_HATCHED; + brushStyle = U_BS_HATCHED; hatchType = U_HS_DIAGCROSS; hatchColor = U_RGB(0xFF,0xC3,0xC3); } @@ -886,7 +884,7 @@ } else if(style->stroke.isColor()){ // test last, always seems to be set, even for other types above sp_color_get_rgb_floatv( &style->stroke.value.color, rgb ); - penStyle = U_BS_SOLID; + brushStyle = U_BS_SOLID; hatchColor = U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]); hatchType = U_HS_SOLIDCLR; } @@ -934,7 +932,7 @@ style->stroke_dash.dash ) { if(FixPPTDashLine){ // will break up line into many smaller lines. Override gradient if that was set, cannot do both. - penStyle = U_BS_SOLID; + brushStyle = U_BS_SOLID; hatchType = U_HS_HORIZONTAL; } else { @@ -959,7 +957,7 @@ elp = extlogpen_set( U_PS_GEOMETRIC | linestyle | linecap | linejoin, linewidth, - penStyle, + brushStyle, hatchColor, hatchType, n_dash, === modified file 'src/extension/internal/uemf.c' --- src/extension/internal/uemf.c 2012-10-04 23:44:26 +0000 +++ src/extension/internal/uemf.c 2012-10-24 21:19:23 +0000 @@ -15,7 +15,7 @@ /* File: uemf.c Version: 0.0.9 -Date: 04-OCT-2012 +Date: 24-OCT-2012 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu Copyright: 2012 David Mathog and California Institute of Technology (Caltech) @@ -472,7 +472,8 @@ size_t max, size_t *len ){ - char *dst, *dst2, *ret; + char *dst, *dst2; + char *ret=NULL; size_t srclen,dstlen,status; if(max){ srclen = 2*max; } else { srclen = 2*(1 +wchar16len(src)); } //include terminator, length in BYTES @@ -482,10 +483,11 @@ iconv_t conv = iconv_open("UTF-8", "UTF-16LE"); status = iconv(conv, ICONV_CAST &src, &srclen, &dst, &dstlen); iconv_close(conv); - if(status == (size_t) -1)return(NULL); - if(len)*len=strlen(dst2); - ret=U_strdup(dst2); // make a string of exactly the right size - free(dst2); // free the one which was probably too big + if(status != (size_t) -1){ + if(len)*len=strlen(dst2); + ret=U_strdup(dst2); // make a string of exactly the right size + } + free(dst2); // free the one which was probably too big return(ret); } @@ -1074,11 +1076,15 @@ \param ct DIB color table \param numCt DIB color table number of entries \param rgba_px U_RGBA pixel array (32 bits), created by this routine, caller must free. - \param w Width of pixel array - \param h Height of pixel array + \param w Width of pixel array in the record + \param h Height of pixel array in the record \param colortype DIB BitCount Enumeration \param use_ct Kept for symmetry with RGBA_to_DIB, should be set to numCt \param invert If DIB rows are in opposite order from RGBA rows + \param sl start left position in the pixel array in the record to start extracting + \param st start top position in the pixel array in the record to start extracting + \param ew Width of pixel array to extract + \param eh Height of pixel array to extract */ int DIB_to_RGBA( char *px, @@ -1089,7 +1095,11 @@ int h, uint32_t colortype, int use_ct, - int invert + int invert, + int sl, + int st, + int ew, + int eh ){ uint32_t cbRgba_px; int stride; @@ -1103,6 +1113,7 @@ int usedbytes; U_RGBQUAD color; int32_t index; + int ilow,ihigh,rok; // For figuring out OK row when not entire array is converted // sanity checking if(!w || !h || !colortype || !px)return(1); @@ -1110,8 +1121,8 @@ if(!use_ct && colortype < U_BCBM_COLOR16)return(3); //color tables mandatory for < 16 bit if(use_ct && !numCt)return(4); //color table not adequately described - stride = w * 4; - cbRgba_px = stride * h; + stride = ew * 4; + cbRgba_px = stride * eh; bs = colortype/8; if(bs<1){ bs=1; @@ -1121,24 +1132,30 @@ usedbytes = w*bs; } pad = UP4(usedbytes) - usedbytes; // DIB rows must be aligned on 4 byte boundaries, they are padded at the end to accomplish this.; - *rgba_px = (char *) malloc(cbRgba_px); + *rgba_px = (char *) malloc(cbRgba_px); if(!rgba_px)return(4); if(invert){ istart = h-1; iend = -1; iinc = -1; + ihigh = istart - st; + ilow = ihigh - eh + 1; } else { istart = 0; iend = h; iinc = 1; + ilow = st; + ihigh = st + eh -1; } pxptr = px; tmp8 = 0; // silences a compiler warning, tmp8 always sets when j=0, so never used uninitialized for(i=istart; i!=iend; i+=iinc){ - rptr= *rgba_px + i*stride; + if(i>=ilow && i<=ihigh){ rok=1; } + else { rok=0; } + rptr= *rgba_px + (i-ilow)*stride; for(j=0; j=sl && j<=sl+ew-1){ + *rptr++ = r; + *rptr++ = g; + *rptr++ = b; + *rptr++ = a; + } } for(j=0; j 0,29699. \return 0 for success, >=1 for failure. \param xmm Drawing width in millimeters \param ymm Drawing height in millimeters @@ -1622,12 +1642,12 @@ if(xmm < 0 || ymm < 0 || dpmm < 0)return(1); rclBounds->left = 0; rclBounds->top = 0; - rclBounds->right = U_ROUND((float) xmm * dpmm); // because coordinate system is 0,0 in upper left, N,M in lower right - rclBounds->bottom = U_ROUND((float) ymm * dpmm); + rclBounds->right = U_ROUND((float) xmm * dpmm) - 1; // because coordinate system is 0,0 in upper left, N,M in lower right + rclBounds->bottom = U_ROUND((float) ymm * dpmm) - 1; rclFrame->left = 0; rclFrame->top = 0; - rclFrame->right = U_ROUND((float) xmm * 100.); - rclFrame->bottom = U_ROUND((float) ymm * 100.); + rclFrame->right = U_ROUND((float) xmm * 100.) - 1; + rclFrame->bottom = U_ROUND((float) ymm * 100.) - 1; return(0); } === modified file 'src/extension/internal/uemf.h' --- src/extension/internal/uemf.h 2012-10-08 23:22:53 +0000 +++ src/extension/internal/uemf.h 2012-10-24 19:20:34 +0000 @@ -14,7 +14,7 @@ /* File: uemf.h Version: 0.0.9 -Date: 04-OCT-2012 +Date: 24-OCT-2012 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu Copyright: 2012 David Mathog and California Institute of Technology (Caltech) @@ -2701,8 +2701,9 @@ char **px, PU_RGBQUAD *ct, uint32_t *numCt, uint32_t *width, uint32_t *height, uint32_t *colortype, uint32_t *invert ); int DIB_to_RGBA(char *px, PU_RGBQUAD ct, int numCt, - char **rgba_px, int w, int h, uint32_t colortype, int use_ct, int invert); - + char **rgba_px, int w, int h, uint32_t colortype, int use_ct, int invert, + int sl, int st, int ew, int eh ); + int device_size(const int xmm, const int ymm, const float dpmm, U_SIZEL *szlDev, U_SIZEL *szlMm); int drawing_size(const int xmm, const int yum, const float dpmm, U_RECTL *rclBounds, U_RECTL *rclFrame); === modified file 'src/extension/internal/uemf_endian.c' --- src/extension/internal/uemf_endian.c 2012-10-04 08:04:48 +0000 +++ src/extension/internal/uemf_endian.c 2012-10-19 18:05:05 +0000 @@ -18,7 +18,7 @@ /* File: uemf_endian.h Version: 0.0.9 -Date: 27-SEP-2012 +Date: 19-SEP-2012 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu Copyright: 2012 David Mathog and California Institute of Technology (Caltech) @@ -642,24 +642,52 @@ // U_EMRHEADER 1 void U_EMRHEADER_swap(char *record, int torev){ - core5_swap(record, torev); - + int nDesc,offDesc,nSize,cbPix,offPix; PU_EMRHEADER pEmr = (PU_EMRHEADER)(record); + if(torev){ + nSize = pEmr->emr.nSize; + } + core5_swap(record, torev); + if(!torev){ + nSize = pEmr->emr.nSize; + } + rectl_swap(&(pEmr->rclBounds),2); // rclBounds rclFrame U_swap4(&(pEmr->dSignature), 4); // dSignature nVersion nBytes nRecords U_swap2(&(pEmr->nHandles), 2); // nHandlessReserved + if(torev){ + nDesc = pEmr->nDescription; + offDesc = pEmr->offDescription; + } U_swap4(&(pEmr->nDescription), 3); // nDescription offDescription nPalEntries + if(!torev){ + nDesc = pEmr->nDescription; + offDesc = pEmr->offDescription; + } // UTF16-LE Description sizel_swap(&(pEmr->szlDevice), 2); // szlDevice szlMillimeters - if(torev && pEmr->cbPixelFormat){ - pixelformatdescriptor_swap( (PU_PIXELFORMATDESCRIPTOR) (record + pEmr->offPixelFormat)); - } - U_swap4(&(pEmr->cbPixelFormat), 2); // cbPixelFormat offPixelFormat - if(!torev && pEmr->cbPixelFormat){ - pixelformatdescriptor_swap( (PU_PIXELFORMATDESCRIPTOR) (record + pEmr->offPixelFormat)); - } - U_swap4(&(pEmr->bOpenGL), 1); // bOpenGL - sizel_swap(&(pEmr->szlMicrometers), 1); // szlMicrometers + if((nDesc && (offDesc >= 100)) || + (!offDesc && nSize >= 100) + ){ + if(torev){ + cbPix = pEmr->cbPixelFormat; + offPix = pEmr->offPixelFormat; + if(cbPix)pixelformatdescriptor_swap( (PU_PIXELFORMATDESCRIPTOR) (record + pEmr->offPixelFormat)); + } + U_swap4(&(pEmr->cbPixelFormat), 2); // cbPixelFormat offPixelFormat + if(!torev){ + cbPix = pEmr->cbPixelFormat; + offPix = pEmr->offPixelFormat; + if(cbPix)pixelformatdescriptor_swap( (PU_PIXELFORMATDESCRIPTOR) (record + pEmr->offPixelFormat)); + } + U_swap4(&(pEmr->bOpenGL), 1); // bOpenGL + if((nDesc && (offDesc >= 108)) || + (cbPix && (offPix >=108)) || + (!offDesc && !cbPix && nSize >= 108) + ){ + sizel_swap(&(pEmr->szlMicrometers), 1); // szlMicrometers + } + } } // U_EMRPOLYBEZIER 2 === modified file 'src/extension/internal/uemf_print.c' --- src/extension/internal/uemf_print.c 2012-10-08 23:22:53 +0000 +++ src/extension/internal/uemf_print.c 2012-10-19 18:04:39 +0000 @@ -5,7 +5,7 @@ /* File: uemf_print.c Version: 0.0.9 -Date: 19-SEP-2012 +Date: 19-OCT-2012 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu Copyright: 2012 David Mathog and California Institute of Technology (Caltech) @@ -860,15 +860,24 @@ printf(" nPalEntries: %d\n", pEmr->nPalEntries ); printf(" szlDevice: {%d,%d} \n", pEmr->szlDevice.cx,pEmr->szlDevice.cy); printf(" szlMillimeters: {%d,%d} \n", pEmr->szlMillimeters.cx,pEmr->szlMillimeters.cy); - printf(" cbPixelFormat: %d\n", pEmr->cbPixelFormat ); - printf(" offPixelFormat: %d\n", pEmr->offPixelFormat); - if(pEmr->cbPixelFormat){ - printf(" PFD:"); - pixelformatdescriptor_print( *(PU_PIXELFORMATDESCRIPTOR) (contents + off + pEmr->offPixelFormat)); - printf("\n"); + if((pEmr->nDescription && (pEmr->offDescription >= 100)) || + (!pEmr->offDescription && pEmr->emr.nSize >= 100) + ){ + printf(" cbPixelFormat: %d\n", pEmr->cbPixelFormat ); + printf(" offPixelFormat: %d\n", pEmr->offPixelFormat); + if(pEmr->cbPixelFormat){ + printf(" PFD:"); + pixelformatdescriptor_print( *(PU_PIXELFORMATDESCRIPTOR) (contents + off + pEmr->offPixelFormat)); + printf("\n"); + } + printf(" bOpenGL: %d\n",pEmr->bOpenGL ); + if((pEmr->nDescription && (pEmr->offDescription >= 108)) || + (pEmr->cbPixelFormat && (pEmr->offPixelFormat >=108)) || + (!pEmr->offDescription && !pEmr->cbPixelFormat && pEmr->emr.nSize >= 108) + ){ + printf(" szlMicrometers: {%d,%d} \n", pEmr->szlMicrometers.cx,pEmr->szlMicrometers.cy); + } } - printf(" bOpenGL: %d\n",pEmr->bOpenGL ); - printf(" szlMicrometers: {%d,%d} \n", pEmr->szlMicrometers.cx,pEmr->szlMicrometers.cy); } // U_EMRPOLYBEZIER 2 === modified file 'src/sp-image.cpp' --- src/sp-image.cpp 2012-10-04 16:06:34 +0000 +++ src/sp-image.cpp 2012-10-18 16:54:36 +0000 @@ -1119,6 +1119,7 @@ t = ti * t; sp_print_image_R8G8B8A8_N(ctx, px + trimx*pixskip + trimy*rs, trimwidth, trimheight, rs, t, item->style); } + free(px); // else big memory leak on each image print! } } === modified file 'src/style.cpp' --- src/style.cpp 2012-10-04 16:06:34 +0000 +++ src/style.cpp 2012-10-18 16:54:36 +0000 @@ -1236,7 +1236,9 @@ case SP_PROP_COLOR_INTERPOLATION_FILTERS: // We read it but issue warning SPS_READ_IENUM_IF_UNSET(&style->color_interpolation_filters, val, enum_color_interpolation, true); - if( style->color_interpolation_filters.value != SP_CSS_COLOR_INTERPOLATION_SRGB ) { + static bool blab=true; // eliminate annoying repeated messages to console + if( blab && style->color_interpolation_filters.value != SP_CSS_COLOR_INTERPOLATION_SRGB ) { + blab = false; g_warning("Inkscape currently only supports color-interpolation-filters = sRGB"); } break;