// // OdWmf.cpp // #include "OdaCommon.h" #ifdef USE_UEMF #undef USE_UEMF #endif #include "OdWmf.h" #pragma pack(1) // cross-platform /////////////////////////////////////////////////////////////////////////////// // Macros #define takeWmfRecordAndSize(pRecord, size) \ const OdWmfRecord* pRecord = (const OdWmfRecord*)contents; \ OdUInt32 size = 2 * (*(const OdUInt32*)pRecord); \ if (size < sizeof(OdWmfRecord)) \ return 0; \ contents += sizeof(OdWmfRecord) //#define takeEmfRecordAndSize(pRecord, size) \ // const OdEmfObject* pRecord = (const OdEmfObject*)contents; \ // OdUInt32 size = pRecord->nSize; \ // if (size < sizeof(OdEmfObject)) \ // return 0; \ // contents += sizeof(OdEmfObject) #define skipType(type) contents += sizeof(type) #define takeType(type) *(const type*)contents, skipType(type) #define takeString(len) (const char*)contents, contents += (len & 1) ? (len + 1) : len /////////////////////////////////////////////////////////////////////////////// #define OdWmfBitBltSizeMin OdWmfBitBltNopxSize #define OdWmfStretchBltSizeMin OdWmfStretchBltNopxSize #define OdWmfDibStretchBltSizeMin OdWmfDibStretchBltNopxSize #define OdWmfPolygonSize 8 #define OdWmfEscapeSize 10 inline bool testNoPxb(OdUInt32 recordSize, OdUInt8 xb) { // Test if no bitmap is associated with the structure // Used with some BLT records to determine if pixel data is present // recordSize is Size16_4 (extracted and aligned) * 2 // xb is extra high order byte from record type // Returns true when recordSize/2 == xb + 3 (no pixel data present) return (recordSize / 2 == (OdUInt32)(xb + 3)); } //*************************************************************************** // full numeric type of a WMR record by index(type) int indexToWmr(int idx) { static int WMR_VALUES[256]={ 0x0000, //WMR_EOF 0x0201, //WMR_SETBKCOLOR 0x0102, //WMR_SETBKMODE 0x0103, //WMR_SETMAPMODE 0x0104, //WMR_SETROP2 0x0105, //WMR_SETRELABS 0x0106, //WMR_SETPOLYFILLMODE 0x0107, //WMR_SETSTRETCHBLTMODE 0x0108, //WMR_SETTEXTCHAREXTRA 0x0209, //WMR_SETTEXTCOLOR 0x020A, //WMR_SETTEXTJUSTIFICATION 0x020B, //WMR_SETWINDOWORG 0x020C, //WMR_SETWINDOWEXT 0x020D, //WMR_SETVIEWPORTORG 0x020E, //WMR_SETVIEWPORTEXT 0x020F, //WMR_OFFSETWINDOWORG 0x0410, //WMR_SCALEWINDOWEXT 0x0211, //WMR_OFFSETVIEWPORTORG 0x0412, //WMR_SCALEVIEWPORTEXT 0x0213, //WMR_LINETO 0x0214, //WMR_MOVETO 0x0415, //WMR_EXCLUDECLIPRECT 0x0416, //WMR_INTERSECTCLIPRECT 0x0817, //WMR_ARC 0x0418, //WMR_ELLIPSE 0x0419, //WMR_FLOODFILL 0x081A, //WMR_PIE 0x041B, //WMR_RECTANGLE 0x061C, //WMR_ROUNDRECT 0x061D, //WMR_PATBLT 0x001E, //WMR_SAVEDC 0x041F, //WMR_SETPIXEL 0x0220, //WMR_OFFSETCLIPRGN 0x0521, //WMR_TEXTOUT 0x0922, //WMR_BITBLT 0x0B23, //WMR_STRETCHBLT 0x0324, //WMR_POLYGON 0x0325, //WMR_POLYLINE 0x0626, //WMR_ESCAPE 0x0127, //WMR_RESTOREDC 0x0228, //WMR_FILLREGION 0x0429, //WMR_FRAMEREGION 0x012A, //WMR_INVERTREGION 0x012B, //WMR_PAINTREGION 0x012C, //WMR_SELECTCLIPREGION 0x012D, //WMR_SELECTOBJECT 0x012E, //WMR_SETTEXTALIGN 0x062F, //WMR_DRAWTEXT 0x0830, //WMR_CHORD 0x0231, //WMR_SETMAPPERFLAGS 0x0A32, //WMR_EXTTEXTOUT 0x0D33, //WMR_SETDIBTODEV 0x0234, //WMR_SELECTPALETTE 0x0035, //WMR_REALIZEPALETTE 0x0436, //WMR_ANIMATEPALETTE 0x0037, //WMR_SETPALENTRIES 0x0538, //WMR_POLYPOLYGON 0x0139, //WMR_RESIZEPALETTE 0x003A, //WMR_3A 0x003B, //WMR_3B 0x003C, //WMR_3C 0x003D, //WMR_3D 0x003E, //WMR_3E 0x003F, //WMR_3F 0x0940, //WMR_DIBBITBLT 0x0B41, //WMR_DIBSTRETCHBLT 0x0142, //WMR_DIBCREATEPATTERNBRUSH 0x0F43, //WMR_STRETCHDIB 0x0044, //WMR_44 0x0045, //WMR_45 0x0046, //WMR_46 0x0047, //WMR_47 0x0548, //WMR_EXTFLOODFILL 0x0049, //WMR_49 0x004A, //WMR_4A 0x004B, //WMR_4B 0x014C, //WMR_4C 0x014D, //WMR_4D 0x004E, //WMR_4E 0x004F, //WMR_4F 0x0050, //WMR_50 0x0051, //WMR_51 0x0052, //WMR_52 0x0053, //WMR_53 0x0054, //WMR_54 0x0055, //WMR_55 0x0056, //WMR_56 0x0057, //WMR_57 0x0058, //WMR_58 0x0059, //WMR_59 0x005A, //WMR_5A 0x005B, //WMR_5B 0x005C, //WMR_5C 0x005D, //WMR_5D 0x005E, //WMR_5E 0x005F, //WMR_5F 0x0060, //WMR_60 0x0061, //WMR_61 0x0062, //WMR_62 0x0063, //WMR_63 0x0064, //WMR_64 0x0065, //WMR_65 0x0066, //WMR_66 0x0067, //WMR_67 0x0068, //WMR_68 0x0069, //WMR_69 0x006A, //WMR_6A 0x006B, //WMR_6B 0x006C, //WMR_6C 0x006D, //WMR_6D 0x006E, //WMR_6E 0x006F, //WMR_6F 0x0070, //WMR_70 0x0071, //WMR_71 0x0072, //WMR_72 0x0073, //WMR_73 0x0074, //WMR_74 0x0075, //WMR_75 0x0076, //WMR_76 0x0077, //WMR_77 0x0078, //WMR_78 0x0079, //WMR_79 0x007A, //WMR_7A 0x007B, //WMR_7B 0x007C, //WMR_7C 0x007D, //WMR_7D 0x007E, //WMR_7E 0x007F, //WMR_7F 0x0080, //WMR_80 0x0081, //WMR_81 0x0082, //WMR_82 0x0083, //WMR_83 0x0084, //WMR_84 0x0085, //WMR_85 0x0086, //WMR_86 0x0087, //WMR_87 0x0088, //WMR_88 0x0089, //WMR_89 0x008A, //WMR_8A 0x008B, //WMR_8B 0x008C, //WMR_8C 0x008D, //WMR_8D 0x008E, //WMR_8E 0x008F, //WMR_8F 0x0090, //WMR_90 0x0091, //WMR_91 0x0092, //WMR_92 0x0093, //WMR_93 0x0094, //WMR_94 0x0095, //WMR_95 0x0096, //WMR_96 0x0097, //WMR_97 0x0098, //WMR_98 0x0099, //WMR_99 0x009A, //WMR_9A 0x009B, //WMR_9B 0x009C, //WMR_9C 0x009D, //WMR_9D 0x009E, //WMR_9E 0x009F, //WMR_9F 0x00A0, //WMR_A0 0x00A1, //WMR_A1 0x00A2, //WMR_A2 0x00A3, //WMR_A3 0x00A4, //WMR_A4 0x00A5, //WMR_A5 0x00A6, //WMR_A6 0x00A7, //WMR_A7 0x00A8, //WMR_A8 0x00A9, //WMR_A9 0x00AA, //WMR_AA 0x00AB, //WMR_AB 0x00AC, //WMR_AC 0x00AD, //WMR_AD 0x00AE, //WMR_AE 0x00AF, //WMR_AF 0x00B0, //WMR_B0 0x00B1, //WMR_B1 0x00B2, //WMR_B2 0x00B3, //WMR_B3 0x00B4, //WMR_B4 0x00B5, //WMR_B5 0x00B6, //WMR_B6 0x00B7, //WMR_B7 0x00B8, //WMR_B8 0x00B9, //WMR_B9 0x00BA, //WMR_BA 0x00BB, //WMR_BB 0x00BC, //WMR_BC 0x00BD, //WMR_BD 0x00BE, //WMR_BE 0x00BF, //WMR_BF 0x00C0, //WMR_C0 0x00C1, //WMR_C1 0x00C2, //WMR_C2 0x00C3, //WMR_C3 0x00C4, //WMR_C4 0x00C5, //WMR_C5 0x00C6, //WMR_C6 0x00C7, //WMR_C7 0x00C8, //WMR_C8 0x00C9, //WMR_C9 0x00CA, //WMR_CA 0x00CB, //WMR_CB 0x00CC, //WMR_CC 0x00CD, //WMR_CD 0x00CE, //WMR_CE 0x00CF, //WMR_CF 0x00D0, //WMR_D0 0x00D1, //WMR_D1 0x00D2, //WMR_D2 0x00D3, //WMR_D3 0x00D4, //WMR_D4 0x00D5, //WMR_D5 0x00D6, //WMR_D6 0x00D7, //WMR_D7 0x00D8, //WMR_D8 0x00D9, //WMR_D9 0x00DA, //WMR_DA 0x00DB, //WMR_DB 0x00DC, //WMR_DC 0x00DD, //WMR_DD 0x00DE, //WMR_DE 0x00DF, //WMR_DF 0x00E0, //WMR_E0 0x00E1, //WMR_E1 0x00E2, //WMR_E2 0x00E3, //WMR_E3 0x00E4, //WMR_E4 0x00E5, //WMR_E5 0x00E6, //WMR_E6 0x00E7, //WMR_E7 0x00E8, //WMR_E8 0x00E9, //WMR_E9 0x00EA, //WMR_EA 0x00EB, //WMR_EB 0x00EC, //WMR_EC 0x00ED, //WMR_ED 0x00EE, //WMR_EE 0x00EF, //WMR_EF 0x01F0, //WMR_DELETEOBJECT 0x00F1, //WMR_F1 0x00F2, //WMR_F2 0x00F3, //WMR_F3 0x00F4, //WMR_F4 0x00F5, //WMR_F5 0x00F6, //WMR_F6 0x00F7, //WMR_CREATEPALETTE 0x00F8, //WMR_CREATEBRUSH 0x01F9, //WMR_CREATEPATTERNBRUSH 0x02FA, //WMR_CREATEPENINDIRECT 0x02FB, //WMR_CREATEFONTINDIRECT 0x02FC, //WMR_CREATEBRUSHINDIRECT 0x02FD, //WMR_CREATEBITMAPINDIRECT 0x06FE, //WMR_CREATEBITMAP 0x06FF //WMR_CREATEREGION }; if (idx < 0 || idx > 255) return 0xFFFFFFFF; int ret = WMR_VALUES[idx]; return ret; } //*********************************************************************************************** // Native WMF enumerations // Sources: https://ru.wikipedia.org/wiki/Windows_Metafile // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wmf/4813e7fd-52d0-4f42-965f-228c8b7488d2 // wingdi.h of MSVC (lines 187-188 for ETO_ constants) enum _WMF_BI_COMPRESSIONS { _BI_UNKNOWN = -1, _BI_RGB = 0, _BI_BITFIELDS = 3 }; enum _BCBM_BIT_COUNT { _BCBM_MONOCHROME = 1, _BCBM_COLOR4 = 4, _BCBM_COLOR8 = 8, _BCBM_COLOR16 = 16 }; enum _ETO_OPTIONS { _ETO_OPAQUE = 0x0002, _ETO_CLIPPED = 0x0004 }; // Get the actual number of colors in the color table from the ClrUsed, BitCount, Width, and Height. // Return Number of entries in the color table. // Colors Number of colors in the table. // BitCount BitCount Enumeration // Width bitmap width // Height bitmap height static int getWmfRealColorCount(int Colors, int BitCount, int Width, int Height) { int area = Width * Height; if (area < 0) area = -area; if (Colors == 0) { if (BitCount == _BCBM_MONOCHROME) Colors = 2; else if (BitCount == _BCBM_COLOR4) Colors = 16; else if (BitCount == _BCBM_COLOR8) Colors = 256; if (Colors > area) Colors = area; } return Colors; } // Get the actual number of colors in the color table from the BitMapInfoHeader. // Return Number of entries in the color table. // Bmih char * pointer to the OdWmfBitmapInfoHeader static int getWmfRealColorCount(const char *Bmih) { const OdWmfBitmapInfoHeader* pHeader = (const OdWmfBitmapInfoHeader*) Bmih; return getWmfRealColorCount((int) pHeader->biClrUsed, (int) pHeader->biBitCount, (int) pHeader->biWidth, (int) pHeader->biHeight); } // Return 1 on success, 0 on failure // Test a OdWmfBitmapInfo object. // Bmi pointer to a OdWmfBitmapInfo object. // blimit one byte past the end of the record. static int isBitmapInfoValid(const char* Bmi, const char* blimit) { if ((Bmi + sizeof(OdWmfBitmapInfo) + sizeof(OdWmfBitmapInfoHeader)) > blimit) return 0; int ClrUsed = getWmfRealColorCount(Bmi); if ( ClrUsed && (Bmi + sizeof(OdWmfBitmapInfo) + ClrUsed * sizeof(OdWmfQuad)) > blimit) return 0; return 1; } // Return parameters from a bitmapcoreheader. // All are returned as 32 bit integers, regardless of their internal representation. // BmiCh char * pointer to a OdWmfBitmapCoreHeader. Note, data may not be properly aligned. // Size size of the coreheader in bytes // Width Width of pixel array // Height Height of pixel array // BitCount Pixel Format (BitCount Enumeration) void getBitmapCoreHeader(const char* BmiCh, OdUInt32* Size, OdInt32* Width, OdInt32* Height, OdInt32* BitCount) { const char* contents = BmiCh; *Size = takeType(OdUInt32); *Width = takeType(OdUInt16); *Height = takeType(OdUInt16); skipType(OdUInt16); *BitCount = takeType(OdUInt16); } // Return parameters from a bitinfoheader. // All are returned as 32 bit integers, regardless of their internal representation. // // Bmih char * pointer to a OdWmfBitmapInfoHeader. Note, data may not be properly aligned. // Size Structure size in bytes // Width Bitmap width in pixels // Height Bitmap height in pixels, may be negative. // Planes Planes (must be 1) // BitCount BitCount Enumeration (determines number of RBG colors) // Compression BI_Compression Enumeration // SizeImage Image size in bytes or 0 = "default size (calculated from geometry?)" // XPelsPerMeter X Resolution in pixels/meter // YPelsPerMeter Y Resolution in pixels/meter // ClrUsed Number of bmciColors in OdWmfBitmapInfo/U_BITMAPCOREINFO that are used by the bitmap // ClrImportant Number of bmciColors needed (0 means all). void getWmfBitmapInfoHeader(const char* Bmih, OdUInt32* Size, OdInt32* Width, OdInt32* Height, OdUInt32* Planes, OdUInt32* BitCount, OdUInt32* Compression, OdUInt32* SizeImage, OdInt32* XPelsPerMeter, OdInt32* YPelsPerMeter, OdUInt32* ClrUsed, OdUInt32* ClrImportant) { const char* contents = Bmih; *Size = takeType(OdUInt32); *Width = takeType(OdInt32); *Height = takeType(OdInt32); *Planes = takeType(OdUInt16); *BitCount = takeType(OdUInt16); *Compression = takeType(OdUInt32); *SizeImage = takeType(OdUInt32); *XPelsPerMeter = takeType(OdInt32); *YPelsPerMeter = takeType(OdInt32); *ClrUsed = takeType(OdUInt32); *ClrImportant = takeType(OdUInt32); } // Assume a packed DIB and get the parameters from it, use by DBI_to_RGBA() // // Return BI_Compression Enumeration. For anything other than _BI_RGB values other than px may not be valid. // dib pointer to the start of the DIB in the record // px pointer to DIB pixel array // ct pointer to DIB color table // numCt DIB color table number of entries, for PNG or JPG returns the number of bytes in the image // width Width of pixel array // height Height of pixel array (always returned as a positive number) // colortype DIB BitCount Enumeration // invert If DIB rows are in opposite order from RGBA rows static int getDibParams(const char* dib, const char** px, const OdWmfQuad **ct, OdUInt32 * numCt, OdInt32* width, OdInt32* height, OdInt32* colortype, OdInt32* invert) { OdUInt32 Size, bic = _BI_RGB; // this information is not in the coreheader; getBitmapCoreHeader(dib, &Size, width, height, colortype); if (Size != 0xC) { // if biCompression is not _BI_RGB some or all of the following might not hold real values. // Ignore most of the information returned from the bitmapinfoheader. OdUInt32 uig4; OdInt32 ig4; getWmfBitmapInfoHeader(dib, &uig4, width, height,&uig4, (OdUInt32 *) colortype, &bic, &uig4, &ig4, &ig4, &uig4, &uig4); } if (*height < 0) { *height = -*height; *invert = 1; } else *invert = 0; *px = dib + OdWmfBitmapInfoHeaderSize; if (bic == _BI_RGB) { *numCt = getWmfRealColorCount(dib); if (*numCt) { *ct = (OdWmfQuad *) (dib + OdWmfBitmapInfoHeaderSize); *px += (*numCt) * sizeof(ODCOLORREF); // * OdWmfColorRefSize; } else *ct = nullptr; } else { const OdWmfBitmapInfoHeader* pInfoHeader = (const OdWmfBitmapInfoHeader*)dib; *numCt = pInfoHeader->biSizeImage; *ct = nullptr; } return bic; } // Check that the bitmap in the specified packed DIB is compatible with the record size // Return 1 on success, 0 on failure // record EMF record that contains a DIB pixel array // blimit one byte past the end of the record. // // This method can only test DIBs that hold Microsoft's various bitmap types. PNG or JPG is just a bag // of bytes, and there is no possible way to derive from the known width and height how big it should be. // This should not be called directly by end user code. static int isDibValid(const char* record, const char* blimit) { int dibparams = _BI_UNKNOWN; // type of image not yet determined const char *px = nullptr; // DIB pixels const OdWmfQuad *ct = nullptr; // DIB color table int bs; int usedbytes; if (!isBitmapInfoValid(record, blimit)) return 0; // this DIB has issues with colors fitting into the record OdUInt32 numCt; // these values will be set in get_DIB_params OdInt32 width, height, colortype, invert; // these values will be set in get_DIB_params // next call returns pointers and values, but allocates no memory dibparams = getDibParams(record, &px, (const OdWmfQuad **)&ct, &numCt, &width, &height, &colortype, &invert); // sanity checking if (numCt && colortype >= _BCBM_COLOR16) return 0; if (!numCt && colortype < _BCBM_COLOR16) return 0; if (dibparams == _BI_RGB) { // this is the only DIB type where we can calculate how big it should be when stored in the WMF file bs = colortype / 8; if (bs < 1) usedbytes = (width*colortype + 7) / 8; // width of line in fully and partially occupied bytes else usedbytes = width * bs; if (px + usedbytes > blimit) return 0; } return 1; } // Derive from bounding rect, start and end radials, for arc, chord, or pie, the center, start, and end points, and the bounding rectangle. // // Return 0 on success, other values on errors. // rclBox bounding rectangle // ArcStart start of arc // ArcEnd end of arc // f1 1 if rotation angle >= 180, else 0 // f2 Rotation direction, 1 if counter clockwise, else 0 // center Center coordinates // start Start coordinates(point on the ellipse defined by rect) // end End coordinates(point on the ellipse defined by rect) // size W, H of the x, y axes of the bounding rectangle. int emr_arc_points_common(OdWmfRectL* rclBox, OdWmfPointL* ArcStart, OdWmfPointL* ArcEnd, int* f1, int f2, OdWmfPointF* center, OdWmfPointF* start, OdWmfPointF* end, OdWmfPointF* size) { OdWmfPointF estart; // EMF start position, defines a radial OdWmfPointF eend; // EMF end position, defines a radial OdWmfPointF vec_estart; // define a unit vector from the center to estart OdWmfPointF vec_eend; // define a unit vector from the center to eend OdWmfPointF radii; // x,y radii of ellipse OdWmfPointF ratio; // intermediate value float scale, cross; center->x = float((rclBox->left + rclBox->right) / 2.0); center->y = float((rclBox->top + rclBox->bottom) / 2.0); size->x = float(rclBox->right - rclBox->left); size->y = float(rclBox->bottom - rclBox->top); estart.x = float(ArcStart->x); estart.y = float(ArcStart->y); eend.x = float(ArcEnd->x); eend.y = float(ArcEnd->y); radii.x = float(size->x / 2.0); radii.y = float(size->y / 2.0); vec_estart.x = (estart.x - center->x); // initial vector, not unit length vec_estart.y = (estart.y - center->y); scale = float(sqrt(vec_estart.x*vec_estart.x + vec_estart.y*vec_estart.y)); if (!scale) return 1; // bogus record, has start at center vec_estart.x /= scale; // now a unit vector vec_estart.y /= scale; vec_eend.x = (eend.x - center->x); // initial vector, not unit length vec_eend.y = (eend.y - center->y); scale = sqrt(vec_eend.x*vec_eend.x + vec_eend.y*vec_eend.y); if (!scale) return 2; // bogus record, has end at center vec_eend.x /= scale; // now a unit vector vec_eend.y /= scale; // Find the intersection of the vectors with the ellipse. With no loss of generality // we can translate the ellipse to the origin, then we just need to find tu (t a factor, u the unit vector) // that also satisfies (x/Rx)^2 + (y/Ry)^2 = 1. x is t*(ux), y is t*(uy), where ux,uy are the x,y components // of the unit vector. Substituting gives: // (t*(ux)/Rx)^2 + (t*(uy)/Ry)^2 = 1 // t^2 = 1/( (ux/Rx)^2 + (uy/Ry)^2 ) // t = sqrt(1/( (ux/Rx)^2 + (uy/Ry)^2 )) ratio.x = vec_estart.x / radii.x; ratio.y = vec_estart.y / radii.y; ratio.x *= ratio.x; // we only use the square ratio.y *= ratio.y; scale = float(1.0 / sqrt(ratio.x + ratio.y)); start->x = center->x + scale * vec_estart.x; start->y = center->y + scale * vec_estart.y; ratio.x = vec_eend.x / radii.x; ratio.y = vec_eend.y / radii.y; ratio.x *= ratio.x; // we only use the square ratio.y *= ratio.y; scale = float(1.0 / sqrt(ratio.x + ratio.y)); end->x = center->x + scale * vec_eend.x; end->y = center->y + scale * vec_eend.y; //lastly figure out if the swept angle is >180 degrees or not, based on the direction of rotation //and the two unit vectors. cross = vec_estart.x * vec_eend.y - vec_estart.y * vec_eend.x; if (!f2) { // counter clockwise rotation if (cross >= 0) *f1 = 1; else *f1 = 0; } else { if (cross >= 0) *f1 = 0; else *f1 = 1; } return 0; } // Derive from bounding box and start and end arc, for WMF arc, chord, or pie records, the center, start, and end points, and the bounding rectangle. // // Return 0 on success, other values on errors. // rclBox Bounding box of Arc // ArcStart Coordinates for Start of Arc // ArcEnd Coordinates for End of Arc // f1 1 if rotation angle >= 180, else 0 // f2 Rotation direction, 1 if counter clockwise, else 0 // center Center coordinates // start Start coordinates(point on the ellipse defined by rect) // end End coordinates(point on the ellipse defined by rect) // size W, H of the x, y axes of the bounding rectangle. int getWmfArcPoints(OdWmfRect rclBox, OdWmfPoint ArcStart, OdWmfPoint ArcEnd, int* f1, int f2, OdWmfPointF* center, OdWmfPointF* start, OdWmfPointF* end, OdWmfPointF* size) { OdWmfRectL rclBoxL; OdWmfPointL ArcStartL, ArcEndL; rclBoxL.left = rclBox.left; rclBoxL.top = rclBox.top; rclBoxL.right = rclBox.right; rclBoxL.bottom = rclBox.bottom; ArcStartL.x = ArcStart.x; ArcStartL.y = ArcStart.y; ArcEndL.x = ArcEnd.x; ArcEndL.y = ArcEnd.y; return emr_arc_points_common(&rclBoxL, &ArcStartL, &ArcEndL, f1, f2, center, start, end, size); } // ********************************************************************************************** size_t getWmfRecordSize(const char* contents, const char* blimit) { takeWmfRecordAndSize(pRecord, size); if (contents > blimit) return 0; return size_t(size); } int getWmfHeader(const char* contents, const char* blimit, OdWmfPlaceableHeader* Placeable, OdWmfHeader* Header) { OdUInt32 Key; int size=0; if (!contents || !Placeable || !Header || !blimit) return 0; if (contents + 4 > blimit) return 0; memcpy(&Key, contents + offsetof(OdWmfPlaceableHeader,Key), 4); if (Key == 0x9AC6CDD7) { size += OdWmfPlaceableHeaderSize; if (contents + size > blimit) return 0; memcpy(Placeable, contents, OdWmfPlaceableHeaderSize); contents += OdWmfPlaceableHeaderSize; } else memset(Placeable, 0, OdWmfPlaceableHeaderSize); if (contents + OdWmfHeaderSize > blimit) return 0; size += 2* (*(OdUInt16 *)(contents + offsetof(OdWmfHeader,Size16w))); if (contents + size > blimit) return 0; memcpy(Header, contents, OdWmfHeaderSize); return size; } int getWmfSetBkColor(const char* contents, ODCOLORREF* Color) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfSetBkColorSize) return 0; *Color = takeType(ODCOLORREF); return size; } int getWmfSetBkMode(const char* contents, OdUInt16* Mode) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfSetBkModeSize) return 0; *Mode = takeType(OdUInt16); return size; } int getWmfSetMapMode(const char* contents, OdUInt16* Mode) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfSetMapModeSize) return 0; *Mode = takeType(OdUInt16); return size; } int getWmfSetOp2(const char* contents, OdUInt16* Mode) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfSetOp2Size) return 0; *Mode = takeType(OdUInt16); return size; } int getWmfSetPolyFillMode(const char* contents, OdUInt16* Mode) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfSetPolyFillModeSize) return 0; *Mode = takeType(OdUInt16); return size; } int getWmfSetStretchBltMode(const char* contents, OdUInt16* Mode) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfSetStretchBltModeSize) return 0; *Mode = takeType(OdUInt16); return size; } int getWmfSetTextColor(const char* contents, ODCOLORREF* Color) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfSetTextColorSize) return 0; *Color = takeType(ODCOLORREF); return size; } int getOdWmfSetWindowOrg(const char* contents, OdWmfPoint* coord) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfSetWindowOrgSize) return 0; coord->y = takeType(OdInt16); coord->x = takeType(OdInt16); return size; } int getWmfSetWindowExt(const char* contents, OdWmfPoint* extent) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfSetWindowExtSize) return 0; extent->y = takeType(OdInt16); extent->x = takeType(OdInt16); return size; } int getWmfSetViewportOrg(const char* contents, OdWmfPoint * coord) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfSetViewportOrgSize) return 0; coord->y = takeType(OdInt16); coord->x = takeType(OdInt16); return size; } int getWmfLineTo(const char* contents, OdWmfPoint * coord) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfLineToSize) return 0; coord->y = takeType(OdInt16); coord->x = takeType(OdInt16); return size; } int getWmfIntersectClipRect(const char* contents, OdWmfRect* rect) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfIntersectClipRectSize) return 0; rect->bottom = takeType(OdUInt16); rect->right = takeType(OdUInt16); rect->top = takeType(OdUInt16); rect->left = takeType(OdUInt16); return size; } int getWmfArc(const char* contents, OdWmfPoint* StartArc, OdWmfPoint* EndArc, OdWmfRect* rect) { takeWmfRecordAndSize(pRecord, size); if (size < 22) // OdWmfArcSize return 0; EndArc->y = takeType(OdUInt16); EndArc->x = takeType(OdUInt16); StartArc->y = takeType(OdUInt16); StartArc->x = takeType(OdUInt16); rect->bottom = takeType(OdUInt16); rect->right = takeType(OdUInt16); rect->top = takeType(OdUInt16); rect->left = takeType(OdUInt16); return size; } int getWmfEllipse(const char* contents, OdWmfRect* rect) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfEllipseSize) return 0; rect->bottom = takeType(OdUInt16); rect->right = takeType(OdUInt16); rect->top = takeType(OdUInt16); rect->left = takeType(OdUInt16); return size; } int getWmfPie(const char* contents, OdWmfPoint* Radial1, OdWmfPoint* Radial2, OdWmfRect* rect) { takeWmfRecordAndSize(pRecord, size); if (size < 22) // OdWmfPieSize return 0; Radial2->y = takeType(OdUInt16); Radial2->x = takeType(OdUInt16); Radial1->y = takeType(OdUInt16); Radial1->x = takeType(OdUInt16); rect->bottom = takeType(OdUInt16); rect->right = takeType(OdUInt16); rect->top = takeType(OdUInt16); rect->left = takeType(OdUInt16); return size; } int getWmfRectangle(const char* contents, OdWmfRect* rect) { takeWmfRecordAndSize(pRecord, size); if (size < 14) // OdWmfRectangleSize return 0; rect->bottom = takeType(OdUInt16); rect->right = takeType(OdUInt16); rect->top = takeType(OdUInt16); rect->left = takeType(OdUInt16); return size; } int getWmfRoundRect(const char* contents, OdInt16* Width, OdInt16* Height, OdWmfRect* rect) { takeWmfRecordAndSize(pRecord, size); if (size < 18) // OdWmfRoundRectSize return 0; *Height = takeType(OdInt16); *Width = takeType(OdInt16); rect->bottom = takeType(OdUInt16); rect->right = takeType(OdUInt16); rect->top = takeType(OdUInt16); rect->left = takeType(OdUInt16); return size; } int getWmfPatBlt(const char* contents, OdWmfPoint* Dst, OdWmfPoint* cwh, OdUInt32* dwRop3) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfPatBltSize) return 0; *dwRop3 = takeType(OdUInt32); cwh->y = takeType(OdUInt16); cwh->x = takeType(OdUInt16); Dst->y = takeType(OdUInt16); Dst->x = takeType(OdUInt16); return size; } int getWmfTextOut(const char* contents, OdWmfPoint* Dst, OdUInt16* Length, const char** String) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfTextOutSize) return 0; *Length = takeType(OdUInt16); *String = takeString(*Length); Dst->y = takeType(OdInt16); Dst->x = takeType(OdInt16); return size; } int getWmfBitBlt(const char* contents, OdWmfPoint* Dst, OdWmfPoint* cwh, OdWmfPoint* Src, OdUInt32* dwRop3, OdWmfBitmap* Bm16, const char** px) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfBitBltSizeMin) return 0; *dwRop3 = takeType(OdUInt32); Src->y = takeType(OdUInt16); Src->x = takeType(OdUInt16); cwh->y = takeType(OdUInt16); cwh->x = takeType(OdUInt16); Dst->y = takeType(OdUInt16); Dst->x = takeType(OdUInt16); if (testNoPxb(size, pRecord->xb)) { memset(Bm16, 0, OdWmfBitmapSize); *px = NULL; } else { memcpy(Bm16, contents, OdWmfBitmapSize); *px = contents + OdWmfBitmapSize; } return size; } int getWmfStretchBlt(const char* contents, OdWmfPoint* Dst, OdWmfPoint* cDst, OdWmfPoint* Src, OdWmfPoint* cSrc, OdUInt32* dwRop3, OdWmfBitmap* Bm16, const char** px) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfStretchBltSizeMin) return 0; *dwRop3 = takeType(OdUInt32); cSrc->y = takeType(OdUInt16); cSrc->x = takeType(OdUInt16); Src->y = takeType(OdUInt16); Src->x = takeType(OdUInt16); cDst->y = takeType(OdUInt16); cDst->x = takeType(OdUInt16); Dst->y = takeType(OdUInt16); Dst->x = takeType(OdUInt16); if (testNoPxb(size, pRecord->xb)) { memset(Bm16, 0, OdWmfBitmapSize); *px = NULL; } else { memcpy(Bm16, contents, OdWmfBitmapSize); *px = contents + OdWmfBitmapSize; } return size; } int getWmfChord(const char* contents, OdWmfPoint* Radial1, OdWmfPoint* Radial2, OdWmfRect* rect) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfChordSize) return 0; Radial2->y = takeType(OdUInt16); Radial2->x = takeType(OdUInt16); Radial1->y = takeType(OdUInt16); Radial1->x = takeType(OdUInt16); rect->bottom = takeType(OdUInt16); rect->right = takeType(OdUInt16); rect->top = takeType(OdUInt16); rect->left = takeType(OdUInt16); return size; } int getWmfExtTextOut(const char* contents, OdWmfPoint* Dst, OdUInt16 *Length, OdUInt16 *Opts, const char** string, const OdUInt16** dx, OdWmfRect* rect) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfExtTextOutSize) return 0; Dst->y = takeType(OdInt16); Dst->x = takeType(OdInt16); *Length = takeType(OdUInt16); *Opts = takeType(OdUInt16); if (*Opts & (_ETO_OPAQUE | _ETO_CLIPPED)) memcpy(rect, contents, OdWmfRectSize), contents += OdWmfRectSize; else memset(rect, 0, OdWmfRectSize); *string = takeString(*Length); // storage area must be 2n bytes. if (*Length) *dx = takeType(OdUInt16*); // unused else *dx = nullptr; return size; } int getWmfDibStretchBlt(const char* contents, OdWmfPoint* Dst, OdWmfPoint* cDst, OdWmfPoint* Src, OdWmfPoint* cSrc, OdUInt32* dwRop3, const char** dib) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfDibStretchBltSizeMin) return 0; *dwRop3 = takeType(OdUInt32); cSrc->y = takeType(OdUInt16); cSrc->x = takeType(OdUInt16); Src->y = takeType(OdUInt16); Src->x = takeType(OdUInt16); cDst->y = takeType(OdUInt16); cDst->x = takeType(OdUInt16); Dst->y = takeType(OdUInt16); Dst->x = takeType(OdUInt16); if (testNoPxb(size, pRecord->xb)) *dib = NULL; else { *dib = contents; if (!isDibValid(*dib, *dib + size)) return 0; } return size; } int getWmfStretchDib(const char* contents, OdWmfPoint* Dst, OdWmfPoint* cDst, OdWmfPoint* Src, OdWmfPoint* cSrc, OdUInt16* cUsage, OdUInt32* dwRop3, const char** dib) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfStretchDibSize) return 0; *dwRop3 = takeType(OdUInt32); *cUsage = takeType(OdUInt16); cSrc->y = takeType(OdInt16); cSrc->x = takeType(OdInt16); Src->y = takeType(OdInt16); Src->x = takeType(OdInt16); cDst->y = takeType(OdInt16); cDst->x = takeType(OdInt16); Dst->y = takeType(OdInt16); Dst->x = takeType(OdInt16); *dib = contents; if (!isDibValid(*dib, *dib+size)) return 0; return size; } static OdUInt32* wmr_properties_table = NULL; OdUInt32 getWmfProperties(OdUInt32 type) { OdUInt32 result = OdUInt32(_WMR_INVALID); if (type == _WMR_INVALID) { if (wmr_properties_table) free(wmr_properties_table); wmr_properties_table = NULL; return result; } if (type <= _WMR_MAX) { if (!wmr_properties_table) { wmr_properties_table = (OdUInt32*)malloc(sizeof(OdUInt32) * (1 + _WMR_MAX)); if (!wmr_properties_table) return result; for (int i = 0; i <= _WMR_MAX; i++) wmr_properties_table[i] = 0x00; wmr_properties_table[0x00] = 0x0A0; // U_WMREOF wmr_properties_table[0x01] = 0x020; // U_WMRSETBKCOLOR wmr_properties_table[0x02] = 0x020; // U_WMRSETBKMODE wmr_properties_table[0x03] = 0x0A0; // U_WMRSETMAPMODE wmr_properties_table[0x04] = 0x0A0; // U_WMRSETROP2 wmr_properties_table[0x05] = 0x000; // U_WMRSETRELABS wmr_properties_table[0x06] = 0x0A0; // U_WMRSETPOLYFILLMODE wmr_properties_table[0x07] = 0x0A0; // U_WMRSETSTRETCHBLTMODE wmr_properties_table[0x08] = 0x000; // U_WMRSETTEXTCHAREXTRA wmr_properties_table[0x09] = 0x020; // U_WMRSETTEXTCOLOR wmr_properties_table[0x0A] = 0x020; // U_WMRSETTEXTJUSTIFICATION wmr_properties_table[0x0B] = 0x0A0; // U_WMRSETWINDOWORG wmr_properties_table[0x0C] = 0x0A0; // U_WMRSETWINDOWEXT wmr_properties_table[0x0D] = 0x0A0; // U_WMRSETVIEWPORTORG wmr_properties_table[0x0E] = 0x0A0; // U_WMRSETVIEWPORTEXT wmr_properties_table[0x0F] = 0x000; // U_WMROFFSETWINDOWORG wmr_properties_table[0x10] = 0x000; // U_WMRSCALEWINDOWEXT wmr_properties_table[0x11] = 0x0A0; // U_WMROFFSETVIEWPORTORG wmr_properties_table[0x12] = 0x0A0; // U_WMRSCALEVIEWPORTEXT wmr_properties_table[0x13] = 0x28B; // U_WMRLINETO wmr_properties_table[0x14] = 0x289; // U_WMRMOVETO wmr_properties_table[0x15] = 0x0A0; // U_WMREXCLUDECLIPRECT wmr_properties_table[0x16] = 0x0A0; // U_WMRINTERSECTCLIPRECT wmr_properties_table[0x17] = 0x283; // U_WMRARC wmr_properties_table[0x18] = 0x087; // U_WMRELLIPSE wmr_properties_table[0x19] = 0x082; // U_WMRFLOODFILL wmr_properties_table[0x1A] = 0x087; // U_WMRPIE wmr_properties_table[0x1B] = 0x087; // U_WMRRECTANGLE wmr_properties_table[0x1C] = 0x087; // U_WMRROUNDRECT wmr_properties_table[0x1D] = 0x000; // U_WMRPATBLT wmr_properties_table[0x1E] = 0x0A0; // U_WMRSAVEDC wmr_properties_table[0x1F] = 0x082; // U_WMRSETPIXEL wmr_properties_table[0x20] = 0x0A0; // U_WMROFFSETCLIPRGN wmr_properties_table[0x21] = 0x002; // U_WMRTEXTOUT wmr_properties_table[0x22] = 0x082; // U_WMRBITBLT wmr_properties_table[0x23] = 0x082; // U_WMRSTRETCHBLT wmr_properties_table[0x24] = 0x083; // U_WMRPOLYGON wmr_properties_table[0x25] = 0x283; // U_WMRPOLYLINE wmr_properties_table[0x26] = 0x000; // U_WMRESCAPE wmr_properties_table[0x27] = 0x0A0; // U_WMRRESTOREDC wmr_properties_table[0x28] = 0x0A0; // U_WMRFILLREGION wmr_properties_table[0x29] = 0x083; // U_WMRFRAMEREGION wmr_properties_table[0x2A] = 0x0A0; // U_WMRINVERTREGION wmr_properties_table[0x2B] = 0x0A0; // U_WMRPAINTREGION wmr_properties_table[0x2C] = 0x0A0; // U_WMRSELECTCLIPREGION wmr_properties_table[0x2D] = 0x120; // U_WMRSELECTOBJECT wmr_properties_table[0x2E] = 0x020; // U_WMRSETTEXTALIGN wmr_properties_table[0x2F] = 0x002; // U_WMRDRAWTEXT wmr_properties_table[0x30] = 0x087; // U_WMRCHORD wmr_properties_table[0x31] = 0x0A0; // U_WMRSETMAPPERFLAGS wmr_properties_table[0x32] = 0x002; // U_WMREXTTEXTOUT wmr_properties_table[0x33] = 0x082; // U_WMRSETDIBTODEV wmr_properties_table[0x34] = 0x120; // U_WMRSELECTPALETTE wmr_properties_table[0x35] = 0x0A0; // U_WMRREALIZEPALETTE wmr_properties_table[0x36] = 0x000; // U_WMRANIMATEPALETTE wmr_properties_table[0x37] = 0x000; // U_WMRSETPALENTRIES wmr_properties_table[0x38] = 0x087; // U_WMRPOLYPOLYGON wmr_properties_table[0x39] = 0x000; // U_WMRRESIZEPALETTE wmr_properties_table[0x40] = 0x082; // U_WMRDIBBITBLT wmr_properties_table[0x41] = 0x082; // U_WMRDIBSTRETCHBLT wmr_properties_table[0x42] = 0x121; // U_WMRDIBCREATEPATTERNBRUSH wmr_properties_table[0x43] = 0x082; // U_WMRSTRETCHDIB wmr_properties_table[0x48] = 0x082; // U_WMREXTFLOODFILL wmr_properties_table[0xF0] = 0x121; // U_WMRCREATEPENINDIRECT wmr_properties_table[0xF1] = 0x121; // U_WMRCREATEFONTINDIRECT wmr_properties_table[0xF2] = 0x121; // U_WMRCREATEBRUSHINDIRECT wmr_properties_table[0xF7] = 0x121; // U_WMRCREATEPALETTE wmr_properties_table[0xF8] = 0x121; // U_WMRCREATEPATTERNBRUSH wmr_properties_table[0xF9] = 0x121; // U_WMRCREATEREGION wmr_properties_table[0xFA] = 0x121; // U_WMRCREATEBITMAPINDIRECT wmr_properties_table[0xFB] = 0x121; // U_WMRCREATEBITMAP wmr_properties_table[0xFC] = 0x120; // U_WMRDELETEOBJECT } result = wmr_properties_table[type]; } return result; } // Missing WMF function implementations for ODA compatibility int getWmfPolygon(const char* contents, OdUInt16* cPts, const char** points) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfPolygonSize) return 0; *cPts = takeType(OdUInt16); *points = contents; return size; } int getWmfEscape(const char* contents, OdUInt16* Escape, OdUInt16* elen, const char** text) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfEscapeSize) return 0; *Escape = takeType(OdUInt16); *elen = takeType(OdUInt16); *text = contents; return size; } int getWmfRestoreDc(const char* contents, OdInt16* DC) { takeWmfRecordAndSize(pRecord, size); if (size < 8) return 0; *DC = takeType(OdInt16); return size; } int getWmfSelectClipRegion(const char* contents, OdUInt16* region) { takeWmfRecordAndSize(pRecord, size); if (size < 8) return 0; *region = takeType(OdUInt16); return size; } int getWmfSelectObject(const char* contents, OdUInt16* object) { takeWmfRecordAndSize(pRecord, size); if (size < 8) return 0; *object = takeType(OdUInt16); return size; } int getWmfSetTextAlign(const char* contents, OdUInt16* textAlign) { takeWmfRecordAndSize(pRecord, size); if (size < OdWmfSetTextAlignSize) return 0; *textAlign = takeType(OdUInt16); return size; } int getWmfPolyPolygon(const char* contents, OdUInt16* nPolys, const OdUInt16** aPolyCounts, const char** Points) { takeWmfRecordAndSize(pRecord, size); if (size < 10) return 0; *nPolys = takeType(OdUInt16); *aPolyCounts = takeType(OdUInt16*); *Points = contents; // points start after polygon counts return size; } int getWmfDeleteObject(const char* contents, OdUInt16* object) { takeWmfRecordAndSize(pRecord, size); if (size < 8) return 0; *object = takeType(OdUInt16); return size; } int getWmfCreateBrushIndirect(const char* contents, const char** membrush) { takeWmfRecordAndSize(pRecord, size); if (size < 14) return 0; *membrush = contents; return size; } int getWmfCreateFontIndirect(const char* contents, const char** memfont) { takeWmfRecordAndSize(pRecord, size); if (size < (OdWmfRecordSize + OdWmfFontCoreSize)) return 0; *memfont = contents; // font data starts after record header return size; } int getWmfSetViewportText(const char* contents, OdWmfPoint* coord) { takeWmfRecordAndSize(pRecord, size); if (size < 10) return 0; coord->y = takeType(OdInt16); coord->x = takeType(OdInt16); return size; } int getWmfDibBitBlt(const char* contents, OdWmfPoint* Dst, OdWmfPoint* cwh, OdWmfPoint* Src, OdUInt32* dwRop3, const char** dib) { takeWmfRecordAndSize(pRecord, size); *dwRop3 = takeType(OdUInt32); Src->y = takeType(OdInt16); Src->x = takeType(OdInt16); skipType(OdUInt16); cwh->y = takeType(OdInt16); cwh->x = takeType(OdInt16); Dst->y = takeType(OdInt16); Dst->x = takeType(OdInt16); *dib = nullptr; if (testNoPxb(size, pRecord->xb)) return size; if (!isDibValid(contents, contents + size)) return 0; *dib = contents; return size; } // Print functions for debugging/logging int getWmfHeaderPrint(const char *contents, const char *blimit) { // Basic WMF header parsing if (!contents || (blimit && contents >= blimit)) return 0; return 22; // Standard WMF header size } int getWmfOneRecPrint(const char* contents, const char* blimit, int, // recnum OdUInt32 off) { if (!contents || (blimit && contents >= blimit)) return 0; takeWmfRecordAndSize(pRecord, size); return int(off + size); } /////////////////////////////////////////////////////////////////////////////