=== modified file 'src/extension/internal/emf-inout.cpp' --- src/extension/internal/emf-inout.cpp 2012-10-25 08:08:38 +0000 +++ src/extension/internal/emf-inout.cpp 2012-10-31 22:58:47 +0000 @@ -59,7 +59,6 @@ namespace Internal { -static float device_scale = DEVICESCALE; static U_RECTL rc_old; static bool clipset = false; static uint32_t ICMmode=0; // not used yet, but code to read it from EMF implemented @@ -363,8 +362,6 @@ U_SIZEL sizeWnd; U_SIZEL sizeView; - float PixelsInX, PixelsInY; - float PixelsOutX, PixelsOutY; U_POINTL winorg; U_POINTL vieworg; double ScaleInX, ScaleInY; @@ -390,8 +387,12 @@ EMF_DEVICE_CONTEXT dc[EMF_MAX_DC+1]; // FIXME: This should be dynamic.. int level; - 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 + double W2PscaleX,W2PscaleY; // World to Page scale. Y may be negative for MM_LOMETRIC etc. + float MM100InX, MM100InY; // size of the drawing in hundredths of a millimeter + float PixelsInX, PixelsInY; // size of the drawing, in EMF device pixels + float PixelsOutX, PixelsOutY;// size of the drawing, in Inkscape pixels + double ulCornerInX,ulCornerInY; // Upper left corner, from header rclBounds, in logical units + double ulCornerOutX,ulCornerOutY; // Upper left corner, in Inkscape pixels uint32_t mask; // Draw properties int arcdir; //U_AD_COUNTERCLOCKWISE 1 or U_AD_CLOCKWISE 2 @@ -632,10 +633,7 @@ 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 - 0,0, // start position in pixel array in record - width, // Width of extracted pixel array - height // Height of extracted pixel array + invert // If DIB rows are in opposite order from RGBA rows ) && rgba_px) { @@ -890,25 +888,21 @@ static double _pix_x_to_point(PEMF_CALLBACK_DATA d, double px) { - 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; + double scale = (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : d->W2PscaleX); + double tmp; + tmp = ((double) (px - d->dc[d->level].winorg.x))*scale + + d->dc[d->level].vieworg.x - d->ulCornerOutX; + return(tmp); } static double _pix_y_to_point(PEMF_CALLBACK_DATA d, double py) { - 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; + double scale = (d->dc[d->level].ScaleInY ? d->dc[d->level].ScaleInY : d->W2PscaleY); + double tmp; + tmp = ((double) (py - d->dc[d->level].winorg.y))*scale + + d->dc[d->level].vieworg.y - d->ulCornerOutY; + return(tmp); } @@ -917,13 +911,7 @@ { 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; } @@ -933,12 +921,6 @@ 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; @@ -947,13 +929,11 @@ static double pix_to_size_point(PEMF_CALLBACK_DATA d, double px) { - double ppx = px * (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0); - double ppy = 0; + double ppx = px * (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : d->W2PscaleX); + // double ppy = 0; - double dx = ppx * d->dc[d->level].worldTransform.eM11 + ppy * d->dc[d->level].worldTransform.eM21; - dx *= device_scale; - double dy = ppx * d->dc[d->level].worldTransform.eM12 + ppy * d->dc[d->level].worldTransform.eM22; - dy *= device_scale; + double dx = ppx * d->dc[d->level].worldTransform.eM11; // + ppy * d->dc[d->level].worldTransform.eM21 + double dy = ppx * d->dc[d->level].worldTransform.eM12; // + ppy * d->dc[d->level].worldTransform.eM22 double tmp = sqrt(dx * dx + dy * dy); return tmp; @@ -1315,11 +1295,12 @@ int cur_level = d->level; d->level = d->emf_obj[index].level; double font_size = pix_to_size_point( d, pEmr->elfw.elfLogFont.lfHeight ); - /* snap the font_size to the nearest .01. - See the notes where device_scale is set for the reason why. + /* snap the font_size to the nearest 1/32nd of a point. + (The size is converted from Pixels to points, snapped, and converted back.) + See the notes where d->W2Pscale[XY] are set for the reason why. Typically this will set the font to the desired exact size. If some peculiar size - was intended this will, at worst, make it 1% off, which is unlikely to be a problem. */ - font_size = round(100.0 * font_size)/100.0; + was intended this will, at worst, make it .03125 off, which is unlikely to be a problem. */ + font_size = round(20.0 * 0.8 * font_size)/(20.0 * 0.8); d->level = cur_level; d->dc[d->level].style.font_size.computed = font_size; d->dc[d->level].style.font_weight.value = @@ -1392,11 +1373,13 @@ 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); + if(string){ + if((pEmr->nDescription >= 13) && + (0==strcmp("Adobe Systems",string)) && + (nEmr->emr.iType == U_EMR_SETMAPMODE) && + (nEmr->iMode == U_MM_ANISOTROPIC)){ ret=1; } + free(string); + } return(ret); } @@ -1442,6 +1425,7 @@ mempng.buffer = NULL; char *rgba_px=NULL; // RGBA pixels + char *sub_px=NULL; // RGBA pixels, subarray char *px=NULL; // DIB pixels uint32_t width, height, colortype, numCt, invert; PU_RGBQUAD ct = NULL; @@ -1474,17 +1458,24 @@ 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 - sl,st, // starting point in pixel array - sw,sh // columns/rows to extract from the pixel array (output array size) + invert // If DIB rows are in opposite order from RGBA rows ) && rgba_px) { + sub_px = RGBA_to_RGBA( + rgba_px, // full pixel array from DIB + width, // Width of pixel array + height, // Height of pixel array + sl,st, // starting point in pixel array + &sw,&sh // columns/rows to extract from the pixel array (output array size) + ); + + if(!sub_px)sub_px=rgba_px; toPNG( // Get the image from the RGBA px into mempng &mempng, sw, sh, // size of the extracted pixel array - rgba_px); - free(rgba_px); + sub_px); + free(sub_px); } } if(mempng.buffer){ @@ -1606,41 +1597,50 @@ tmp_outdef << " xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\"\n"; // needed for sodipodi:role tmp_outdef << " version=\"1.0\"\n"; - 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; + d->MM100InX = pEmr->rclFrame.right - pEmr->rclFrame.left + 1; + d->MM100InY = pEmr->rclFrame.bottom - pEmr->rclFrame.top + 1; + d->PixelsInX = pEmr->rclBounds.right - pEmr->rclBounds.left + 1; + d->PixelsInY = pEmr->rclBounds.bottom - pEmr->rclBounds.top + 1; + /* calculate ratio of Inkscape dpi/device dpi 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 + EMF might have a final W2Pscale[XY] 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. 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); + if (pEmr->szlMillimeters.cx && pEmr->szlDevice.cy){ + d->W2PscaleX = d->W2PscaleY = + 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->MM100InX *= 25.4/(10.0*3.0); + d->MM100InY *= 25.4/(10.0*3.0); + d->W2PscaleX *= 25.4/(10.0*3.0); + d->W2PscaleY *= 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; + d->MMX = d->MM100InX / 100.0; + d->MMY = d->MM100InY / 100.0; + + d->PixelsOutX = d->MMX * PX_PER_MM; + d->PixelsOutY = d->MMY * PX_PER_MM; + + // Upper left corner, from header rclBounds, in device units, usually both 0, but not always + d->ulCornerInX = pEmr->rclBounds.left; + d->ulCornerInY = pEmr->rclBounds.top; + d->ulCornerOutX = d->ulCornerInX * d->W2PscaleX; + d->ulCornerOutY = d->ulCornerInY * d->W2PscaleY; tmp_outdef << " width=\"" << d->MMX << "mm\"\n" << @@ -1847,8 +1847,8 @@ if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) { d->dc[d->level].sizeWnd = d->dc[d->level].sizeView; if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) { - d->dc[d->level].sizeWnd.cx = d->dc[d->level].PixelsOutX; - d->dc[d->level].sizeWnd.cy = d->dc[d->level].PixelsOutY; + d->dc[d->level].sizeWnd.cx = d->PixelsOutX; + d->dc[d->level].sizeWnd.cy = d->PixelsOutY; } } @@ -1856,17 +1856,17 @@ d->dc[d->level].sizeView = d->dc[d->level].sizeWnd; } - d->dc[d->level].PixelsInX = d->dc[d->level].sizeWnd.cx; - d->dc[d->level].PixelsInY = d->dc[d->level].sizeWnd.cy; - - if (d->dc[d->level].PixelsInX && d->dc[d->level].PixelsInY) { - d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].PixelsInX; - d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].PixelsInY; + if (d->dc[d->level].sizeWnd.cx && d->dc[d->level].sizeWnd.cy) { + d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].sizeWnd.cx; + d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].sizeWnd.cy; } else { d->dc[d->level].ScaleInX = 1; d->dc[d->level].ScaleInY = 1; } + /* scales logical to EMF pixels, but we need logical to Inkscape pixels */ + d->dc[d->level].ScaleInX *= d->PixelsOutX / d->PixelsInX; + d->dc[d->level].ScaleInY *= d->PixelsOutY / d->PixelsInY; break; } @@ -1889,27 +1889,27 @@ if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) { d->dc[d->level].sizeView = d->dc[d->level].sizeWnd; if (!d->dc[d->level].sizeView.cx || !d->dc[d->level].sizeView.cy) { - d->dc[d->level].sizeView.cx = d->dc[d->level].PixelsOutX; - d->dc[d->level].sizeView.cy = d->dc[d->level].PixelsOutY; + d->dc[d->level].sizeView.cx = d->PixelsOutX; + d->dc[d->level].sizeView.cy = d->PixelsOutY; } } if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) { d->dc[d->level].sizeWnd = d->dc[d->level].sizeView; } - - d->dc[d->level].PixelsInX = d->dc[d->level].sizeWnd.cx; - d->dc[d->level].PixelsInY = d->dc[d->level].sizeWnd.cy; - if (d->dc[d->level].PixelsInX && d->dc[d->level].PixelsInY) { - d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].PixelsInX; - d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].PixelsInY; + if (d->dc[d->level].sizeWnd.cx && d->dc[d->level].sizeWnd.cy) { + d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].sizeWnd.cx; + d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].sizeWnd.cy; } else { d->dc[d->level].ScaleInX = 1; d->dc[d->level].ScaleInY = 1; } - + /* scales logical to EMF pixels, but we need logical to Inkscape pixels */ + d->dc[d->level].ScaleInX *= d->PixelsOutX / d->PixelsInX; + d->dc[d->level].ScaleInY *= d->PixelsOutY / d->PixelsInY; + break; } case U_EMR_SETVIEWPORTORGEX: @@ -1940,30 +1940,29 @@ 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 + // Use values from the header. break; case U_MM_LOMETRIC: // 1 LU = 0.1 mm - d->ydir = -1.0; - device_scale = 0.1 * PX_PER_MM; + d->W2PscaleX = 0.1 * PX_PER_MM; + d->W2PscaleY = -d->W2PscaleX; break; case U_MM_HIMETRIC: // 1 LU = 0.01 mm - d->ydir = -1.0; - device_scale = 0.01 * PX_PER_MM; + d->W2PscaleX = 0.01 * PX_PER_MM; + d->W2PscaleY = -d->W2PscaleX; break; case U_MM_LOENGLISH: // 1 LU = 0.1 in - d->ydir = -1.0; - device_scale = 0.1 * PX_PER_IN; + d->W2PscaleX = 0.01 * PX_PER_IN; + d->W2PscaleY = -d->W2PscaleX; break; case U_MM_HIENGLISH: // 1 LU = 0.01 in - d->ydir = -1.0; - device_scale = 0.01 * PX_PER_IN; + d->W2PscaleX = 0.001 * PX_PER_IN; + d->W2PscaleY = -d->W2PscaleX; break; case U_MM_TWIPS: // 1 LU = 1/1440 in - d->ydir = -1.0; - device_scale = (1.0/1440.0) * PX_PER_IN; + d->W2PscaleX = (1.0/1440.0) * PX_PER_IN; + d->W2PscaleY = -d->W2PscaleX; break; - case U_MM_ISOTROPIC: // let scaleX etc. handle it, as set by SETVIEWPORTEXTEX and SETWINDOWEXTEX + case U_MM_ISOTROPIC: // ScaleIn[XY] should be set elsewhere by SETVIEWPORTEXTEX and SETWINDOWEXTEX break; case U_MM_ANISOTROPIC: break; @@ -2710,8 +2709,6 @@ 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); } @@ -2731,8 +2728,6 @@ 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); } @@ -2757,8 +2752,6 @@ 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); @@ -3247,6 +3240,8 @@ d.arcdir = U_AD_COUNTERCLOCKWISE; d.dwRop2 = U_R2_COPYPEN; d.dwRop3 = 0; + d.W2PscaleX = 1.0; + d.W2PscaleY = 1.0; d.hatches.size = 0; d.hatches.count = 0; d.hatches.strings = NULL; === modified file 'src/extension/internal/uemf.c' --- src/extension/internal/uemf.c 2012-10-25 08:08:38 +0000 +++ src/extension/internal/uemf.c 2012-10-29 17:56:05 +0000 @@ -15,7 +15,7 @@ /* File: uemf.c Version: 0.0.9 -Date: 24-OCT-2012 +Date: 26-OCT-2012 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu Copyright: 2012 David Mathog and California Institute of Technology (Caltech) @@ -1081,10 +1081,6 @@ \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, @@ -1095,11 +1091,7 @@ int h, uint32_t colortype, int use_ct, - int invert, - int sl, - int st, - int ew, - int eh + int invert ){ uint32_t cbRgba_px; int stride; @@ -1113,7 +1105,6 @@ 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); @@ -1121,8 +1112,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 = ew * 4; - cbRgba_px = stride * eh; + stride = w * 4; + cbRgba_px = stride * h; bs = colortype/8; if(bs<1){ bs=1; @@ -1139,23 +1130,17 @@ 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){ - if(i>=ilow && i<=ihigh){ rok=1; } - else { rok=0; } - rptr= *rgba_px + (i-ilow)*stride; + rptr= *rgba_px + i*stride; for(j=0; j=sl && j<=sl+ew-1){ - *rptr++ = r; - *rptr++ = g; - *rptr++ = b; - *rptr++ = a; - } + *rptr++ = r; + *rptr++ = g; + *rptr++ = b; + *rptr++ = a; } for(j=0; jw || st >h)return(NULL); // This is hopeless, the start point is outside of the array. + if(sl<0){ + if(sl+ew<=0)return(NULL); // This is hopeless, the start point is outside of the array. + ew += sl; + sl = 0; + } + if(st<0){ + if(st+eh<=0)return(NULL); // This is hopeless, the start point is outside of the array. + eh += st; + st = 0; + } + if(sl+ew > w)ew=w-sl; + if(st+eh > h)eh=h-st; + if(!sl && !st && (ew == w) && (eh == h)){ + sub = rgba_px; + } + else { + sptr = sub = malloc(ew*eh*4); + if(!sub)return(NULL); + for(i=st; i