/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// // // MetafileSupport.cpp // #include "OdaCommon.h" #include "OdBinaryData.h" #include "Gi/GiRasterImage.h" #include "RxRasterServices.h" #include "MetafileSupport.h" #include "DynamicLinker.h" #include "OdPlatformStreamer.h" #include "MemoryStream.h" #include "FlatMemStream.h" #include "Gi/GiConveyorGeometry.h" #include "Gi/GiTextStyle.h" #include "Gs/GsDefs.h" #include "OdEmf.h" #ifdef USE_UEMF #include "uwmf.h" #include "uwmf_print.h" #include "uemf.h" #include "uemf_safe.h" #include "uemf_print.h" #endif #ifdef _MSC_VER OD_DISABLE_WARNING(4100) OD_DISABLE_WARNING(4101) OD_DISABLE_WARNING(4127) OD_DISABLE_WARNING(4189) OD_DISABLE_WARNING(4456) OD_DISABLE_WARNING(4458) OD_DISABLE_WARNING(4505) OD_DISABLE_WARNING(4701) OD_DISABLE_WARNING(4702) OD_DISABLE_WARNING(4996) #endif /////////////////////////////////////////////////////////////////////////////// //#ifndef OD_CLD_TOOLS_H_ //#include "OdCharMapper.h" //inline OdAnsiString OdString_toUtf8(const OdString& sUnicode) //{ // OdAnsiCharArray dstBuf; // int lenStr = sUnicode.getLength(); // dstBuf.reserve(lenStr * 4 + 1); // OdCharMapper::unicodeToUtf8(sUnicode.c_str(), lenStr, dstBuf); // OdAnsiString asRes((const char*)dstBuf.asArrayPtr(), dstBuf.length(), CP_UTF_8); // return asRes; //} //#endif inline OdString OdString_fromLatin1(const char* pLatin1, int numChars) { OdCharArray dstBuf; OdCharMapper::multiByteToWideChar(CP_8859_1, pLatin1, numChars, dstBuf); dstBuf.push_back(L'\0'); return OdString(dstBuf.asArrayPtr()); } //inline OdString OdString_fromUtf32(const OdUInt32* pUtf32, int numChars) //{ // if (sizeof(OdUInt32) == sizeof(OdChar)) // return OdString(reinterpret_cast(pUtf32)); // // OdString sUnicode; // OdChar* pDest = sUnicode.getBuffer(numChars + 1); // int idx = 0; // while (idx < numChars) // *pDest++ = static_cast(pUtf32[idx++]); // *pDest = L'\0'; // sUnicode.releaseBuffer(); // return sUnicode; //} /////////////////////////////////////////////////////////////////////////////// #ifdef _WINGDI_ ////typedef struct tagBITMAPINFOHEADER { //// DWORD biSize; //// LONG biWidth; //// LONG biHeight; //// WORD biPlanes; //// WORD biBitCount; //// DWORD biCompression; //// DWORD biSizeImage; //// LONG biXPelsPerMeter; //// LONG biYPelsPerMeter; //// DWORD biClrUsed; //// DWORD biClrImportant; ////} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER; //typedef struct tagBITMAPFILEHEADER { // WORD bfType; // DWORD bfSize; // WORD bfReserved1; // WORD bfReserved2; // DWORD bfOffBits; //} BITMAPFILEHEADER, *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER; #define BITMAPFILEHEADER_LENGTH sizeof(BITMAPFILEHEADER) #define BITMAPINFOHEADER_LENGTH sizeof(BITMAPINFOHEADER) #else #define BITMAPFILEHEADER_LENGTH 14 #define BITMAPINFOHEADER_LENGTH 40 #endif // _WINGDI_ static OdStreamBufPtr createBitmapByDib(//int bpp = 1, // bytes per pixel // int format, const unsigned char* data, int dataSize, // dib int cols, int rows, const unsigned char* colormap = NULL, int colormapSize = 0) // const WT_Color_Map* colormap ) { OdStreamBufPtr buf = OdMemoryStream::createNew(); OdStreamBuf* pBuf = buf; //BITMAPFILEHEADER and begin with the memory address of the DIB header(immediately following the bitmap file header), //which is always 14 bytes past the beginning of the bmp memory address. // https://stackoverflow.com/questions/272152/what-do-i-have-to-do-to-convert-a-dib-to-a-bmp { //int bpp = 1; // bytes per pixel //if ( format == WT_Image::RGB ) bpp = 3; // WD_IMAGE_RGB_EXT_OPCODE 0x0006 //else if ( format == WT_Image::RGBA ) bpp = 4; // WD_IMAGE_RGBA_EXT_OPCODE 0x0007 int bpp = 1; int lnsz = dataSize / rows / cols; if (lnsz >= 4) bpp = 4; else if (lnsz >= 3) bpp = 3; int lineSize = cols * bpp; //scanline in image int padding = ((lineSize + 3) / 4) * 4 - lineSize; // bmp lines must be 32bit aligned int paletteSize = colormap ? (4 * colormapSize) : 0; // 24bit raster have no colormap int clrDepth = bpp * 8; bool bBitonal = colormap && colormapSize == 2; // is converted bitonal // 0x4d42(19778) BMP magic OdPlatformStreamer::wrInt16(*pBuf, 0x4d42); OdUInt32 scanLinesPos = OdUInt32(BITMAPFILEHEADER_LENGTH) + OdUInt32(BITMAPINFOHEADER_LENGTH) + paletteSize; if (bBitonal) scanLinesPos += 4 * (256 - 2); OdUInt32 size = scanLinesPos + (lineSize + padding) * rows; OdPlatformStreamer::wrInt32(*pBuf, size); OdPlatformStreamer::wrInt32(*pBuf, 0); // reserved OdPlatformStreamer::wrInt32(*pBuf, scanLinesPos); // offBits pBuf->putBytes(data, dataSize); //OdPlatformStreamer::wrInt32(*pBuf, BITMAPINFOHEADER_LENGTH); //// save BITMAPINFOHEADER //OdPlatformStreamer::wrInt32(*pBuf, cols); //OdPlatformStreamer::wrInt32(*pBuf, rows); //OdPlatformStreamer::wrInt16(*pBuf, 1); //OdPlatformStreamer::wrInt16(*pBuf, (OdInt16) clrDepth); //OdPlatformStreamer::wrInt32(*pBuf, 0); //OdPlatformStreamer::wrInt32(*pBuf, 0); //OdPlatformStreamer::wrInt32(*pBuf, 0); //OdPlatformStreamer::wrInt32(*pBuf, 0); //OdPlatformStreamer::wrInt32(*pBuf, 0); //OdPlatformStreamer::wrInt32(*pBuf, 0); //// palette //if ( colormap != 0 && paletteSize != 0 ) //{ // buf->putBytes( colormap->map(), paletteSize ); // if (bBitonal) // { // for (int idx = 2; idx < 256; idx++) // buf->putBytes(colormap->map(), 4); // } //} // pixels //for ( int i = rows - 1; i >= 0 ; i-- ) //{ // if ( bpp == 1 ) // buf->putBytes( data + i * lineSize, lineSize ); // else for ( int j = 0; j < cols; j++ ) // { // buf->putBytes( data + i * lineSize + j * bpp + 2, 1 ); // buf->putBytes( data + i * lineSize + j * bpp + 1, 1 ); // buf->putBytes( data + i * lineSize + j * bpp, 1 ); // if ( bpp == 4 ) // buf->putBytes( data + i * lineSize + j * bpp + 3, 1 ); // } // if ( padding ) buf->putBytes( data, padding ); //} } buf->rewind(); return buf; } /////////////////////////////////////////////////////////////////////////////// // // initially fromwmf-inout.h.example // ////#ifndef SEEN_EXTENSION_INTERNAL_WMF_H ////#define SEEN_EXTENSION_INTERNAL_WMF_H // //#define PNG_SKIP_SETJMP_CHECK // else any further png.h include blows up in the compiler ////#include ////#include "extension/implementation/implementation.h" ////#include "style.h" ////#include "uwmf.h" ////#include "text_reassemble.h" // //namespace Inkscape { namespace Extension { namespace Internal { #define DIRTY_NONE 0x00 #define DIRTY_TEXT 0x01 #define DIRTY_FILL 0x02 #define DIRTY_STROKE 0x04 // not used currently typedef struct { int type; int level; const char* record; // char* record; } WMF_OBJECT, *PWMF_OBJECT; typedef struct { int size; // number of slots allocated in strings int count; // number of slots used in strings char **strings; // place to store strings } WMF_STRINGS, *PWMF_STRINGS; enum drawmode { DRAW_PAINT, DRAW_PATTERN, DRAW_IMAGE }; // apply to either fill or stroke typedef struct wmf_device_context { struct { // struct SPStyle OdCmEntityColor fill_color; OdSharedPtr text_style; } style; char* font_name; bool stroke_set; int stroke_mode; // enumeration from drawmode, not used if fill_set is not True int stroke_idx; // used with DRAW_PATTERN and DRAW_IMAGE to return the appropriate fill int stroke_recidx;// record used to regenerate hatch when it needs to be redone due to bkmode, textmode, etc. change bool fill_set; enum drawmode fill_mode; // enumeration from drawmode, not used if fill_set is not True int fill_idx; // used with DRAW_PATTERN and DRAW_IMAGE to return the appropriate fill int fill_recidx; // record used to regenerate hatch when it needs to be redone due to bkmode, textmode, etc. change int dirty; // holds the dirty bits for text, stroke, fill int active_pen; // used when the active object is deleted to set the default values, -1 is none active int active_brush; // ditto int active_font; // ditto. also used to hold object number in case font needs to be remade due to textcolor change. OdWmfPoint sizeWnd; OdWmfPoint sizeView; OdWmfPoint winorg; OdWmfPoint vieworg; double ScaleInX, ScaleInY; double ScaleOutX, ScaleOutY; OdUInt16 bkMode; ODCOLORREF bkColor; ODCOLORREF textColor; OdUInt16 textAlign; OdWmfPoint cur; } WMF_DEVICE_CONTEXT, *PWMF_DEVICE_CONTEXT; #define WMF_MAX_DC 128 // both emf-inout.h and wmf-inout.h are included by init.cpp, // so whichever one goes in first defines these ommon types // ////#ifndef SEEN_EXTENSION_INTERNAL_METAFILECOMMON_ ////#define SEEN_EXTENSION_INTERNAL_METAFILECOMMON_ // A coloured pixel. //typedef struct { // OdUInt8 red; // OdUInt8 green; // OdUInt8 blue; // OdUInt8 opacity; //} pixel_t; // A picture. //typedef struct { // pixel_t *pixels; // size_t width; // size_t height; //} bitmap_t; //// structure to store PNG image bytes //typedef struct { // char *buffer; // size_t size; //} MEMPNG, *PMEMPNG; ////#endif // //// like this causes a mysterious crash on the return from Wmf::open ////typedef struct emf_callback_data { //// this fixes it, so some confusion between this struct and the one in emf-inout??? ////typedef struct wmf_callback_data { //// as does this typedef struct { // TODO //Glib::ustring *outsvg; // TODO //Glib::ustring *path; // TODO //Glib::ustring *outdef; // TODO //Glib::ustring *defs; WMF_DEVICE_CONTEXT dc[WMF_MAX_DC+1]; // FIXME: This should be dynamic.. int level; double E2IdirY; // WMF Y direction relative to Inkscape Y direction. Will be negative for MM_LOMETRIC etc. double D2PscaleX,D2PscaleY; // WMF device to Inkscape Page scale. float PixelsInX, PixelsInY; // size of the drawing, in WMF 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 OdUInt32 mask; // Draw properties int arcdir; // U_AD_COUNTERCLOCKWISE 1 or U_AD_CLOCKWISE 2 OdUInt32 dwRop2; // Binary raster operation, 0 if none (use brush/pen unmolested) OdUInt32 dwRop3; // Ternary raster operation, 0 if none (use brush/pen unmolested) unsigned int id; unsigned int drawtype; // one of 0 or _META_FILLPATH, _META_STROKEPATH, _META_STROKEANDFILLPATH // both of these end up in under the names shown here. These structures allow duplicates to be avoided. WMF_STRINGS hatches; // hold pattern names, all like WMFhatch#_$$$$$$ where # is the WMF hatch code and $$$$$$ is the color WMF_STRINGS images; // hold images, all like Image#, where # is the slot the image lives. // TODO //TR_INFO *tri; // Text Reassembly data structure int n_obj; int low_water; // first object slot which _might_ be unoccupied. Everything below is filled. PWMF_OBJECT wmf_obj; } WMF_CALLBACK_DATA, *PWMF_CALLBACK_DATA; /////////////////////////////////////////////////////////////////////////////// // // initially from emf-inout.h.example // //#ifndef SEEN_EXTENSION_INTERNAL_EMF_H //#define SEEN_EXTENSION_INTERNAL_EMF_H //#include //#include //#include // for U_emf_record_sizeok() //#include "extension/internal/metafile-inout.h" // picks up PNG //#include "extension/implementation/implementation.h" //#include "style.h" //#include "text_reassemble.h" //namespace Inkscape { namespace Extension { namespace Internal { //#define DIRTY_NONE 0x00 //#define DIRTY_TEXT 0x01 //#define DIRTY_FILL 0x02 //#define DIRTY_STROKE 0x04 typedef struct emf_object { emf_object() : type(0), level(0), lpEMFR(NULL) {}; int type; int level; char *lpEMFR; } EMF_OBJECT, *PEMF_OBJECT; typedef struct emf_strings { emf_strings() : size(0), count(0), strings(NULL) {}; int size; // number of slots allocated in strings int count; // number of slots used in strings char **strings; // place to store strings } EMF_STRINGS, *PEMF_STRINGS; typedef struct emf_device_context { emf_device_context() : // SPStyle: class with constructor font_name(NULL), clip_id(0), stroke_set(false), stroke_mode(0), stroke_idx(0), stroke_recidx(0), fill_set(false), fill_mode(0), fill_idx(0), fill_recidx(0), dirty(0), // sizeWnd, sizeView, winorg, vieworg, ScaleInX(0), ScaleInY(0), ScaleOutX(0), ScaleOutY(0), bkMode(_TRANSPARENT), // bkColor, textColor textAlign(0) // worldTransform, cur { font_name = NULL; sizeWnd.cx = sizeWnd.cy = 0; sizeView.cx = sizeView.cy = 0; winorg.x = winorg.y = 0; vieworg.x = vieworg.y = 0; bkColor = ODRGB(255, 255, 255); // default foreground color (white) textColor = ODRGB(0, 0, 0); // default foreground color (black) worldTransform.eM11 = 1.0; worldTransform.eM12 = 0.0; worldTransform.eM21 = 0.0; worldTransform.eM22 = 1.0; worldTransform.eDx = 0.0; worldTransform.eDy = 0.0; cur.x = cur.y = 0; }; //SPStyle style; char *font_name; int clip_id; // 0 if none, else 1 + index into clips bool stroke_set; int stroke_mode; // enumeration from drawmode, not used if fill_set is not True int stroke_idx; // used with DRAW_PATTERN and DRAW_IMAGE to return the appropriate fill int stroke_recidx;// record used to regenerate hatch when it needs to be redone due to bkmode, textmode, etc. change bool fill_set; int fill_mode; // enumeration from drawmode, not used if fill_set is not True int fill_idx; // used with DRAW_PATTERN and DRAW_IMAGE to return the appropriate fill int fill_recidx; // record used to regenerate hatch when it needs to be redone due to bkmode, textmode, etc. change int dirty; // holds the dirty bits for text, stroke, fill OdEmfSizeXY sizeWnd; OdEmfSizeXY sizeView; OdWmfPointL winorg; OdWmfPointL vieworg; double ScaleInX, ScaleInY; double ScaleOutX, ScaleOutY; OdUInt16 bkMode; ODCOLORREF bkColor; ODCOLORREF textColor; OdUInt32 textAlign; OdEmfXForm worldTransform; OdWmfPointL cur; } EMF_DEVICE_CONTEXT, *PEMF_DEVICE_CONTEXT; #define EMF_MAX_DC 128 typedef struct emf_callback_data { emf_callback_data() : // dc: array, structure w/ constructor level(0), E2IdirY(1.0), D2PscaleX(1.0), D2PscaleY(1.0), MM100InX(0), MM100InY(0), PixelsInX(0), PixelsInY(0), PixelsOutX(0), PixelsOutY(0), ulCornerInX(0), ulCornerInY(0), ulCornerOutX(0), ulCornerOutY(0), mask(0), arcdir(_AD_COUNTERCLOCKWISE), dwRop2(_R2_COPYPEN), dwRop3(0), MMX(0),MMY(0), drawtype(0), pDesc(NULL), // hatches, images, gradients, struct w/ constructor //tri(NULL), n_obj(0) // emf_obj; {}; //Glib::ustring outsvg; //Glib::ustring path; //Glib::ustring outdef; //Glib::ustring defs; EMF_DEVICE_CONTEXT dc[EMF_MAX_DC+1]; // FIXME: This should be dynamic.. int level; double E2IdirY; // EMF Y direction relative to Inkscape Y direction. Will be negative for MM_LOMETRIC etc. double D2PscaleX,D2PscaleY; // EMF device to Inkscape Page scale. 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 OdUInt32 mask; // Draw properties int arcdir; //U_AD_COUNTERCLOCKWISE 1 or U_AD_CLOCKWISE 2 OdUInt32 dwRop2; // Binary raster operation, 0 if none (use brush/pen unmolested) OdUInt32 dwRop3; // Ternary raster operation, 0 if none (use brush/pen unmolested) float MMX; float MMY; unsigned int drawtype; // one of 0 or _EMR_FILLPATH, _EMR_STROKEPATH, _EMR_STROKEANDFILLPATH char *pDesc; // both of these end up in under the names shown here. These structures allow duplicates to be avoided. EMF_STRINGS hatches; // hold pattern names, all like EMFhatch#_$$$$$$ where # is the EMF hatch code and $$$$$$ is the color EMF_STRINGS images; // hold images, all like Image#, where # is the slot the image lives. EMF_STRINGS gradients; // hold gradient names, all like EMF[HV]_$$$$$$_$$$$$$ where $$$$$$ are the colors EMF_STRINGS clips; // hold clipping paths, referred to be the slot where the clipping path lives // TODO //TR_INFO *tri; // Text Reassembly data structure int n_obj; PEMF_OBJECT emf_obj; } EMF_CALLBACK_DATA, *PEMF_CALLBACK_DATA; /////////////////////////////////////////////////////////////////////////////// // // base class for calsses Wmf & Emf struct OdMetafileParser { OdGiRasterImagePtr m_pRasterImage; OdGiConveyorGeometry* m_pDestGeom; OdGiConveyorContext* m_pContext; OdGiRegenType m_regenType; OdGePoint3d m_origin; OdGeVector3d m_u, m_v; OdGsDCRect m_rect; bool m_isExport; const char* contents; OdUInt32 off; // for Emf size_t nSize; // size of the current record, in bytes, or an error value if <=0 //virtual pixel_t* pixel_at (bitmap_t * bitmap, int x, int y); //virtual void my_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length); //virtual void toPNG(PMEMPNG accum, int width, int height, const char *px); //virtual OdUInt32 sethexcolor(ODCOLORREF color); //virtual void print_document_to_file(SPDocument *doc, const gchar *filename); ////virtual double current_scale(PWMF_CALLBACK_DATA d); //virtual std::string current_matrix(PWMF_CALLBACK_DATA d, double x, double y, int useoffset); //virtual double current_rotation(PWMF_CALLBACK_DATA d); //virtual void enlarge_hatches(PWMF_CALLBACK_DATA d); //virtual int in_hatches(PWMF_CALLBACK_DATA d, char *test); //virtual OdUInt32 add_hatch(PWMF_CALLBACK_DATA d, OdUInt32 hatchType, ODCOLORREF hatchColor); //virtual void enlarge_images(PWMF_CALLBACK_DATA d); //virtual int in_images(PWMF_CALLBACK_DATA d, char *test); //virtual OdUInt32 add_dib_image(PWMF_CALLBACK_DATA d, const char *dib, OdUInt32 iUsage); //virtual OdUInt32 add_bm16_image(PWMF_CALLBACK_DATA d, OdWmfBitmap Bm16, const char *px); //virtual void output_style(PWMF_CALLBACK_DATA d); ////virtual double _pix_x_to_point(PWMF_CALLBACK_DATA d, double px); ////virtual double _pix_y_to_point(PWMF_CALLBACK_DATA d, double py); ////virtual double pix_to_x_point(PWMF_CALLBACK_DATA d, double px, double py); ////virtual double pix_to_y_point(PWMF_CALLBACK_DATA d, double px, double py); virtual double pix_to_abs_size(PWMF_CALLBACK_DATA d, double px) { ODA_FAIL_ONCE_X(WMF); return 0.0; } //virtual std::string pix_to_xy(PWMF_CALLBACK_DATA d, double x, double y); virtual void select_brush(PWMF_CALLBACK_DATA d, int index); virtual void select_font(PWMF_CALLBACK_DATA d, int index); virtual void select_pen(PWMF_CALLBACK_DATA d, int index); //int insertable_object(PWMF_CALLBACK_DATA d); //void delete_object(PWMF_CALLBACK_DATA d, int index); //int insert_object(PWMF_CALLBACK_DATA d, int type, const char *record); //virtual OdUInt32* unknown_chars(size_t count); virtual void common_dib_to_image(PWMF_CALLBACK_DATA d, const char *dib, double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh, OdUInt32 iUsage); virtual void common_bm16_to_image(PWMF_CALLBACK_DATA d, OdWmfBitmap Bm16, const char *px, double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh); virtual bool hasDrawCtx(); virtual void rectangle_clip(PWMF_CALLBACK_DATA d, double dx, double dy, double dw, double dh); virtual void rectangle_brush(PWMF_CALLBACK_DATA d, double dx, double dy, double dw, double dh); virtual void text_out(PWMF_CALLBACK_DATA d, const OdString& sText, double dx, double dy); // --- virtual void common_image_extraction(PEMF_CALLBACK_DATA d, void *pEmr, double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh, OdUInt32 iUsage, OdUInt32 offBits, OdUInt32 cbBits, OdUInt32 offBmi, OdUInt32 cbBmi); }; /////////////////////////////////////////////////////////////////////////////// // // initially from wmf-inout.h.example // class Wmf : public OdMetafileParser // : Inkscape::Extension::Implementation::Implementation //This is a derived class { public: Wmf() {} virtual ~Wmf() {} //bool check(Inkscape::Extension::Extension *module); //Can this module load (always yes for now) //void save(Inkscape::Extension::Output *mod, // Save the given document to the given filename // SPDocument *doc, // gchar const *filename); //virtual SPDocument *open( Inkscape::Extension::Input *mod, // const gchar *uri ); //static void init(void);//Initialize the class public: // removed static to use some of next with OdMetafileParser //pixel_t *pixel_at (bitmap_t * bitmap, int x, int y); //void my_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length); //void toPNG(PMEMPNG accum, int width, int height, const char *px); //OdUInt32 sethexcolor(ODCOLORREF color); //void print_document_to_file(SPDocument *doc, const gchar *filename); double current_scale(PWMF_CALLBACK_DATA d); //std::string current_matrix(PWMF_CALLBACK_DATA d, double x, double y, int useoffset); //double current_rotation(PWMF_CALLBACK_DATA d); //void enlarge_hatches(PWMF_CALLBACK_DATA d); //int in_hatches(PWMF_CALLBACK_DATA d, char *test); //OdUInt32 add_hatch(PWMF_CALLBACK_DATA d, OdUInt32 hatchType, ODCOLORREF hatchColor); //void enlarge_images(PWMF_CALLBACK_DATA d); //int in_images(PWMF_CALLBACK_DATA d, char *test); //OdUInt32 add_dib_image(PWMF_CALLBACK_DATA d, const char *dib, OdUInt32 iUsage); //OdUInt32 add_bm16_image(PWMF_CALLBACK_DATA d, OdWmfBitmap Bm16, const char *px); //void output_style(PWMF_CALLBACK_DATA d); double _pix_x_to_point(PWMF_CALLBACK_DATA d, double px); double _pix_y_to_point(PWMF_CALLBACK_DATA d, double py); double pix_to_x_point(PWMF_CALLBACK_DATA d, double px, double py); double pix_to_y_point(PWMF_CALLBACK_DATA d, double px, double py); double pix_to_abs_size(PWMF_CALLBACK_DATA d, double px); //std::string pix_to_xy(PWMF_CALLBACK_DATA d, double x, double y); //void select_brush(PWMF_CALLBACK_DATA d, int index); //void select_font(PWMF_CALLBACK_DATA d, int index); //void select_pen(PWMF_CALLBACK_DATA d, int index); static int insertable_object(PWMF_CALLBACK_DATA d); static void delete_object(PWMF_CALLBACK_DATA d, int index); static int insert_object(PWMF_CALLBACK_DATA d, int type, const char *record); //OdUInt32 *unknown_chars(size_t count); //void common_dib_to_image(PWMF_CALLBACK_DATA d, const char *dib, // double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh, OdUInt32 iUsage); //void common_bm16_to_image(PWMF_CALLBACK_DATA d, OdWmfBitmap Bm16, const char *px, // double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh); //void free_wmf_strings(WMF_STRINGS name); bool wmfMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK_DATA d); }; //} } } // namespace Inkscape, Extension, Implementation ////#endif // EXTENSION_INTERNAL_WMF_H /////////////////////////////////////////////////////////////////////////////// // // initially from wmf-inout.cpp.example // //#ifdef HAVE_CONFIG_H //# include "config.h" //#endif // //#include //This must precede text_reassemble.h or it blows up in pngconf.h when compiling //#include //#include //#include //#define EMF_DRIVER //work around SPStyle issue, MUST be EMF, not WMF //#include "sp-root.h" //#include "sp-path.h" //#include "style.h" //#include "print.h" //#include "extension/system.h" //#include "extension/print.h" //#include "extension/db.h" //#include "extension/input.h" //#include "extension/output.h" //#include "display/drawing.h" //#include "display/drawing-item.h" //#include "unit-constants.h" //#include "clear-n_.h" //#include "document.h" //#include "libunicode-convert/unicode-convert.h" // // //#include "wmf-inout.h" //#include "wmf-print.h" // //#define PRINT_WMF "org.inkscape.print.wmf" // //#ifndef U_PS_JOIN_MASK //#define U_PS_JOIN_MASK (U_PS_JOIN_BEVEL|U_PS_JOIN_MITER|U_PS_JOIN_ROUND) //#endif // //namespace Inkscape { namespace Extension { namespace Internal { // static OdWmfRect rc_old; //static bool clipset = false; //static OdUInt32 BLTmode=0; // //// Given "bitmap", this returns the pixel of bitmap at the point //// ("x", "y"). // //pixel_t * Wmf::pixel_at (bitmap_t * bitmap, int x, int y) //{ // return bitmap->pixels + bitmap->width * y + x; //} // // Write "bitmap" to a PNG file specified by "path"; returns 0 on // success, non-zero on error. // //void Wmf::my_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) //{ // PMEMPNG p=(PMEMPNG)png_get_io_ptr(png_ptr); // // size_t nsize = p->size + length; // // // allocate or grow buffer // if(p->buffer){ p->buffer = (char *) realloc(p->buffer, nsize); } // else{ p->buffer = (char *) malloc(nsize); } // // if(!p->buffer){ png_error(png_ptr, "Write Error"); } // // // copy new bytes to end of buffer // memcpy(p->buffer + p->size, data, length); // p->size += length; //} // //void Wmf::toPNG(PMEMPNG accum, int width, int height, const char *px){ // bitmap_t bmStore; // bitmap_t *bitmap = &bmStore; // accum->buffer=NULL; // PNG constructed in memory will end up here, caller must free(). // accum->size=0; // bitmap->pixels=(pixel_t *)px; // bitmap->width = width; // bitmap->height = height; // // png_structp png_ptr = NULL; // png_infop info_ptr = NULL; // size_t x, y; // png_byte ** row_pointers = NULL; // // The following number is set by trial and error only. I cannot // // see where it it is documented in the libpng manual. // int pixel_size = 3; // int depth = 8; // // png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); // if (png_ptr == NULL){ // accum->buffer=NULL; // return; // } // // info_ptr = png_create_info_struct (png_ptr); // if (info_ptr == NULL){ // png_destroy_write_struct (&png_ptr, &info_ptr); // accum->buffer=NULL; // return; // } // // // Set up error handling. // // if (setjmp (png_jmpbuf (png_ptr))) // { // png_destroy_write_struct (&png_ptr, &info_ptr); // accum->buffer=NULL; // return; // } // // // Set image attributes. // // png_set_IHDR ( // png_ptr, // info_ptr, // bitmap->width, // bitmap->height, // depth, // PNG_COLOR_TYPE_RGB, // PNG_INTERLACE_NONE, // PNG_COMPRESSION_TYPE_DEFAULT, // PNG_FILTER_TYPE_DEFAULT // ); // // // Initialize rows of PNG. // // row_pointers = (png_byte **) png_malloc (png_ptr, bitmap->height * sizeof (png_byte *)); // for (y = 0; y < bitmap->height; ++y) { // png_byte *row = // (png_byte *) png_malloc (png_ptr, sizeof (OdUInt8) * bitmap->width * pixel_size); // row_pointers[bitmap->height - y - 1] = row; // Row order in WMF is reversed. // for (x = 0; x < bitmap->width; ++x) { // pixel_t * pixel = pixel_at (bitmap, x, y); // *row++ = pixel->red; // R & B channels were set correctly by DIB_to_RGB // *row++ = pixel->green; // *row++ = pixel->blue; // } // } // // // Write the image data to memory // // png_set_rows (png_ptr, info_ptr, row_pointers); // // png_set_write_fn(png_ptr, accum, my_png_write_data, NULL); // // png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); // // for (y = 0; y < bitmap->height; y++) { // png_free (png_ptr, row_pointers[y]); // } // png_free (png_ptr, row_pointers); // png_destroy_write_struct(&png_ptr, &info_ptr); // //} // // convert an WMF RGB(A) color to 0RGB // inverse of gethexcolor() in emf-print.cpp //OdUInt32 Wmf::sethexcolor(ODCOLORREF color) //{ // OdUInt32 out; // out = (U_RGBAGetR(color) << 16) + // (U_RGBAGetG(color) << 8 ) + // (U_RGBAGetB(color) ); // return(out); //} // //Wmf::Wmf (void) // The null constructor //{ // return; //} // // //Wmf::~Wmf (void) //The destructor //{ // return; //} // //bool //Wmf::check (Inkscape::Extension::Extension *) //module //{ // if (NULL == Inkscape::Extension::db.get(PRINT_WMF)) // return FALSE; // return TRUE; //} // // //void //Wmf::print_document_to_file(SPDocument *doc, const gchar *filename) //{ // Inkscape::Extension::Print *mod; // SPPrintContext context; // const gchar *oldconst; // gchar *oldoutput; // unsigned int ret; // // doc->ensureUpToDate(); // // mod = Inkscape::Extension::get_print(PRINT_WMF); // oldconst = mod->get_param_string("destination"); // oldoutput = g_strdup(oldconst); // mod->set_param_string("destination", filename); // //// Start // context.module = mod; // // fixme: This has to go into module constructor somehow // // Create new arena // mod->base = doc->getRoot(); // Inkscape::Drawing drawing; // mod->dkey = SPItem::display_key_new(1); // mod->root = mod->base->invoke_show(drawing, mod->dkey, SP_ITEM_SHOW_DISPLAY); // drawing.setRoot(mod->root); // // Print document // ret = mod->begin(doc); // if (ret) { // g_free(oldoutput); // throw Inkscape::Extension::Output::save_failed(); // } // mod->base->invoke_print(&context); // ret = mod->finish(); // // Release arena // mod->base->invoke_hide(mod->dkey); // mod->base = NULL; // mod->root = NULL; // deleted by invoke_hide ////end // // mod->set_param_string("destination", oldoutput); // g_free(oldoutput); // // return; //} // // //void //Wmf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filename) //{ // Inkscape::Extension::Extension * ext; // // ext = Inkscape::Extension::db.get(PRINT_WMF); // if (ext == NULL) // return; // // bool new_val = mod->get_param_bool("textToPath"); // bool new_FixPPTCharPos = mod->get_param_bool("FixPPTCharPos"); // character position bug // // reserve FixPPT2 for opacity bug. Currently WMF does not export opacity values // bool new_FixPPTDashLine = mod->get_param_bool("FixPPTDashLine"); // dashed line bug // bool new_FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys"); // gradient bug // bool new_FixPPTPatternAsHatch = mod->get_param_bool("FixPPTPatternAsHatch"); // force all patterns as standard WMF hatch // // TableGen( //possibly regenerate the unicode-convert tables // mod->get_param_bool("TnrToSymbol"), // mod->get_param_bool("TnrToWingdings"), // mod->get_param_bool("TnrToZapfDingbats"), // mod->get_param_bool("UsePUA") // ); // // ext->set_param_bool("FixPPTCharPos",new_FixPPTCharPos); // Remember to add any new ones to PrintWmf::init or a mysterious failure will result! // ext->set_param_bool("FixPPTDashLine",new_FixPPTDashLine); // ext->set_param_bool("FixPPTGrad2Polys",new_FixPPTGrad2Polys); // ext->set_param_bool("FixPPTPatternAsHatch",new_FixPPTPatternAsHatch); // ext->set_param_bool("textToPath", new_val); // // print_document_to_file(doc, filename); // // return; //} // // WMF has no worldTranform, so this always returns 1.0. Retain it to keep WMF and WMF in sync as much as possible. double Wmf::current_scale(PWMF_CALLBACK_DATA d){ return 1.0; } // WMF has no worldTranform, so this always returns an Identity rotation matrix, but the offsets may have values. //std::string Wmf::current_matrix(PWMF_CALLBACK_DATA d, double x, double y, int useoffset){ // std::stringstream cxform; // double scale = current_scale(d); // cxform << "\"matrix("; // cxform << 1.0/scale; cxform << ","; // cxform << 0.0; cxform << ","; // cxform << 0.0; cxform << ","; // cxform << 1.0/scale; cxform << ","; // if(useoffset){ cxform << x; cxform << ","; cxform << y; } // else { cxform << "0,0"; } // cxform << ")\""; // return(cxform.str()); //} // // WMF has no worldTranform, so this always returns 0. // Retain it to keep WMF and WMF in sync as much as possible. //double Wmf::current_rotation(PWMF_CALLBACK_DATA d) //{ // return 0.0; //} // // Add another 100 blank slots to the hatches array. //void Wmf::enlarge_hatches(PWMF_CALLBACK_DATA d) //{ // d->hatches.size += 100; // d->hatches.strings = (char **) realloc(d->hatches.strings,d->hatches.size * sizeof(char *)); //} // // See if the pattern name is already in the list. If it is return its position (1->n, not 1-n-1) //int Wmf::in_hatches(PWMF_CALLBACK_DATA d, char *test) //{ // int i; // for(i=0; ihatches.count; i++){ // if(strcmp(test,d->hatches.strings[i])==0)return(i+1); // } // return(0); //} // // (Conditionally) add a hatch. If a matching hatch already exists nothing happens. If one // does not exist it is added to the hatches list and also entered into . // This is also used to add the path part of the hatches, which they reference with a xlink:href //OdUInt32 Wmf::add_hatch(PWMF_CALLBACK_DATA d, OdUInt32 hatchType, ODCOLORREF hatchColor){ // char hatchname[64]; // big enough // char hpathname[64]; // big enough // char hbkname[64]; // big enough // char tmpcolor[8]; // char bkcolor[8]; // OdUInt32 idx; // WMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; // // switch(hatchType){ // case U_HS_SOLIDTEXTCLR: // case U_HS_DITHEREDTEXTCLR: // sprintf(tmpcolor,"%6.6X",sethexcolor(cur_ctx.textColor)); // break; // case U_HS_SOLIDBKCLR: // case U_HS_DITHEREDBKCLR: // sprintf(tmpcolor,"%6.6X",sethexcolor(cur_ctx.bkColor)); // break; // default: // sprintf(tmpcolor,"%6.6X",sethexcolor(hatchColor)); // break; // } // // // For both bkMode types set the PATH + FOREGROUND COLOR for the indicated standard hatch. // // This will be used late to compose, or recompose the transparent or opaque final hatch. // // std::string refpath; // used to reference later the path pieces which are about to be created // sprintf(hpathname,"WMFhpath%d_%s",hatchType,tmpcolor); // idx = in_hatches(d,hpathname); // if(!idx){ // add path/color if not already present // if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); } // d->hatches.strings[d->hatches.count++]=strdup(hpathname); // // *(d->defs) += "\n"; // switch(hatchType){ // case U_HS_HORIZONTAL: // *(d->defs) += " defs) += hpathname; // *(d->defs) += "\" d=\"M 0 0 6 0\" style=\"fill:none;stroke:#"; // *(d->defs) += tmpcolor; // *(d->defs) += "\" />\n"; // break; // case U_HS_VERTICAL: // *(d->defs) += " defs) += hpathname; // *(d->defs) += "\" d=\"M 0 0 0 6\" style=\"fill:none;stroke:#"; // *(d->defs) += tmpcolor; // *(d->defs) += "\" />\n"; // break; // case U_HS_FDIAGONAL: // *(d->defs) += " defs) += hpathname; // *(d->defs) += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#"; // *(d->defs) += tmpcolor; // *(d->defs) += "\"/>\n"; // break; // case U_HS_BDIAGONAL: // *(d->defs) += " defs) += hpathname; // *(d->defs) += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#"; // *(d->defs) += tmpcolor; // *(d->defs) += "\"/>\n"; // break; // case U_HS_CROSS: // *(d->defs) += " defs) += hpathname; // *(d->defs) += "\" d=\"M 0 0 6 0 M 0 0 0 6\" style=\"fill:none;stroke:#"; // *(d->defs) += tmpcolor; // *(d->defs) += "\" />\n"; // break; // case U_HS_DIAGCROSS: // *(d->defs) += " defs) += hpathname; // *(d->defs) += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#"; // *(d->defs) += tmpcolor; // *(d->defs) += "\"/>\n"; // *(d->defs) += " defs) += hpathname; // *(d->defs) += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#"; // *(d->defs) += tmpcolor; // *(d->defs) += "\"/>\n"; // break; // case U_HS_SOLIDCLR: // case U_HS_DITHEREDCLR: // case U_HS_SOLIDTEXTCLR: // case U_HS_DITHEREDTEXTCLR: // case U_HS_SOLIDBKCLR: // case U_HS_DITHEREDBKCLR: // default: // *(d->defs) += " defs) += hpathname; // *(d->defs) += "\" d=\"M 0 0 6 0 6 6 0 6 z\" style=\"fill:#"; // *(d->defs) += tmpcolor; // *(d->defs) += ";stroke:none"; // *(d->defs) += "\" />\n"; // break; // } // } // // // References to paths possibly just created above. These will be used in the actual patterns. // switch(hatchType){ // case U_HS_HORIZONTAL: // case U_HS_VERTICAL: // case U_HS_CROSS: // case U_HS_SOLIDCLR: // case U_HS_DITHEREDCLR: // case U_HS_SOLIDTEXTCLR: // case U_HS_DITHEREDTEXTCLR: // case U_HS_SOLIDBKCLR: // case U_HS_DITHEREDBKCLR: // default: // refpath += " \n"; // break; // case U_HS_FDIAGONAL: // case U_HS_BDIAGONAL: // refpath += " \n"; // refpath += " \n"; // refpath += " \n"; // break; // case U_HS_DIAGCROSS: // refpath += " \n"; // refpath += " \n"; // refpath += " \n"; // refpath += " \n"; // refpath += " \n"; // refpath += " \n"; // break; // } // // if(cur_ctx.bkMode == U_TRANSPARENT || hatchType >= U_HS_SOLIDCLR){ // sprintf(hatchname,"WMFhatch%d_%s",hatchType,tmpcolor); // sprintf(hpathname,"WMFhpath%d_%s",hatchType,tmpcolor); // idx = in_hatches(d,hatchname); // if(!idx){ // add it if not already present // if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); } // d->hatches.strings[d->hatches.count++]=strdup(hatchname); // *(d->defs) += "\n"; // *(d->defs) += " defs) += hatchname; // *(d->defs) += "\" xlink:href=\"#WMFhbasepattern\">\n"; // *(d->defs) += refpath; // *(d->defs) += " \n"; // idx = d->hatches.count; // } // } // else { // bkMode==U_OPAQUE // // Set up an object in the defs for this background, if there is not one already there // sprintf(bkcolor,"%6.6X",sethexcolor(cur_ctx.bkColor)); // sprintf(hbkname,"WMFhbkclr_%s",bkcolor); // idx = in_hatches(d,hbkname); // if(!idx){ // add path/color if not already present. Hatchtype is not needed in the name. // if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); } // d->hatches.strings[d->hatches.count++]=strdup(hbkname); // // *(d->defs) += "\n"; // *(d->defs) += " defs) += hbkname; // *(d->defs) += "\" x=\"0\" y=\"0\" width=\"6\" height=\"6\" fill=\"#"; // *(d->defs) += bkcolor; // *(d->defs) += "\" />\n"; // } // // // this is the pattern, its name will show up in Inkscape's pattern selector // sprintf(hatchname,"WMFhatch%d_%s_%s",hatchType,tmpcolor,bkcolor); // idx = in_hatches(d,hatchname); // if(!idx){ // add it if not already present // if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); } // d->hatches.strings[d->hatches.count++]=strdup(hatchname); // *(d->defs) += "\n"; // *(d->defs) += " defs) += hatchname; // *(d->defs) += "\" xlink:href=\"#WMFhbasepattern\">\n"; // *(d->defs) += " defs) += hbkname; // *(d->defs) += "\" />\n"; // *(d->defs) += refpath; // *(d->defs) += " \n"; // idx = d->hatches.count; // } // } // return(idx-1); //} // // Add another 100 blank slots to the images array. //void Wmf::enlarge_images(PWMF_CALLBACK_DATA d) //{ // d->images.size += 100; // d->images.strings = (char **) realloc(d->images.strings,d->images.size * sizeof(char *)); //} // // See if the image string is already in the list. If it is return its position (1->n, not 1-n-1) //int Wmf::in_images(PWMF_CALLBACK_DATA d, char *test) //{ // int i; // for(i=0; iimages.count; i++){ // if(strcmp(test,d->images.strings[i])==0)return(i+1); // } // return(0); //} // // (Conditionally) add an image from a DIB. If a matching image already exists nothing happens. If one // does not exist it is added to the images list and also entered into . //OdUInt32 Wmf::add_dib_image(PWMF_CALLBACK_DATA d, const char *dib, OdUInt32 iUsage) //{ // OdUInt32 idx; // char imagename[64]; // big enough // char xywh[64]; // big enough // int dibparams; // // MEMPNG mempng; // PNG in memory comes back in this // mempng.buffer = NULL; // // char *rgba_px = NULL; // RGBA pixels // const char *px = NULL; // DIB pixels // const OdWmfQuad *ct = NULL; // DIB color table // int32_t width, height, colortype, numCt, invert; // if((iUsage != U_DIB_RGB_COLORS) || // !(dibparams = wget_DIB_params( // this returns pointers and values, but allocates no memory // dib, // &px, // &ct, // &numCt, // &width, // &height, // &colortype, // &invert // )) // ){ // // if(!DIB_to_RGBA( // px, // DIB pixel array // 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 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 // ) && // rgba_px // ){ // toPNG( // Get the image from the RGBA px into mempng // &mempng, // width, height, // of the SRC bitmap // rgba_px // ); // free(rgba_px); // } // } // gchar *base64String; // if(dibparams == U_BI_JPEG || dibparams==U_BI_PNG){ // base64String = g_base64_encode((guchar*) px, numCt ); // idx = in_images(d, (char *) base64String); // } // else if(mempng.buffer){ // base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size ); // free(mempng.buffer); // idx = in_images(d, (char *) base64String); // } // else { // // insert a random 3x4 blotch otherwise // width = 3; // height = 4; // base64String = g_strdup("iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII="); // idx = in_images(d, (char *) base64String); // } // if(!idx){ // add it if not already present - we looked at the actual data for comparison // if(d->images.count == d->images.size){ enlarge_images(d); } // idx = d->images.count; // d->images.strings[d->images.count++]=strdup(base64String); // // sprintf(imagename,"WMFimage%d",idx++); // sprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer // // *(d->defs) += "\n"; // *(d->defs) += " defs) += imagename; // *(d->defs) += "\"\n "; // *(d->defs) += xywh; // *(d->defs) += "\n"; // if(dibparams == U_BI_JPEG){ *(d->defs) += " xlink:href=\"data:image/jpeg;base64,"; } // else { *(d->defs) += " xlink:href=\"data:image/png;base64,"; } // *(d->defs) += base64String; // *(d->defs) += "\"\n"; // *(d->defs) += " />\n"; // // // *(d->defs) += "\n"; // *(d->defs) += " defs) += imagename; // *(d->defs) += "_ref\"\n "; // *(d->defs) += xywh; // *(d->defs) += "\n patternUnits=\"userSpaceOnUse\""; // *(d->defs) += " >\n"; // *(d->defs) += " defs) += imagename; // *(d->defs) += "_ign\" "; // *(d->defs) += " xlink:href=\"#"; // *(d->defs) += imagename; // *(d->defs) += "\" />\n"; // *(d->defs) += " "; // *(d->defs) += " \n"; // } // g_free(base64String); // return(idx-1); //} // // (Conditionally) add an image from a Bitmap16. If a matching image already exists nothing happens. If one // does not exist it is added to the images list and also entered into . //OdUInt32 Wmf::add_bm16_image(PWMF_CALLBACK_DATA d, OdWmfBitmap Bm16, const char *px) //{ // // OdUInt32 idx; // char imagename[64]; // big enough // char xywh[64]; // big enough // // MEMPNG mempng; // PNG in memory comes back in this // mempng.buffer = NULL; // // char *rgba_px = NULL; // RGBA pixels // const OdWmfQuad *ct = NULL; // color table, always NULL here // int32_t width, height, colortype, numCt, invert; // numCt = 0; // width = Bm16.Width; // bitmap width in pixels. // height = Bm16.Height; // bitmap height in scan lines. // colortype = Bm16.BitsPixel; // seems to be BitCount Enumeration // invert = 0; // if(colortype < 16)return(0xFFFFFFFF); // these would need a colortable if they were a dib, no idea what bm16 is supposed to do instead. // // if(!DIB_to_RGBA(// This is not really a dib, but close enough... // px, // DIB pixel array // ct, // DIB color table (always NULL here) // numCt, // DIB color table number of entries (always 0) // &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 // colortype, // DIB BitCount Enumeration // numCt, // Color table used if not 0 // invert // If DIB rows are in opposite order from RGBA rows // ) && rgba_px) // { // toPNG( // Get the image from the RGBA px into mempng // &mempng, // width, height, // of the SRC bitmap // rgba_px // ); // free(rgba_px); // } // gchar *base64String; // if(mempng.buffer){ // base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size ); // free(mempng.buffer); // } // else { // // insert a random 3x4 blotch otherwise // width = 3; // height = 4; // base64String = g_strdup("iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII="); // } // idx = in_images(d, (char *) base64String); // if(!idx){ // add it if not already present - we looked at the actual data for comparison // if(d->images.count == d->images.size){ enlarge_images(d); } // idx = d->images.count; // d->images.strings[d->images.count++]=g_strdup(base64String); // // sprintf(imagename,"WMFimage%d",idx++); // sprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer // // *(d->defs) += "\n"; // *(d->defs) += " defs) += imagename; // *(d->defs) += "\"\n "; // *(d->defs) += xywh; // *(d->defs) += "\n"; // *(d->defs) += " xlink:href=\"data:image/png;base64,"; // *(d->defs) += base64String; // *(d->defs) += "\"\n"; // *(d->defs) += " />\n"; // // // *(d->defs) += "\n"; // *(d->defs) += " defs) += imagename; // *(d->defs) += "_ref\"\n "; // *(d->defs) += xywh; // *(d->defs) += "\n patternUnits=\"userSpaceOnUse\""; // *(d->defs) += " >\n"; // *(d->defs) += " defs) += imagename; // *(d->defs) += "_ign\" "; // *(d->defs) += " xlink:href=\"#"; // *(d->defs) += imagename; // *(d->defs) += "\" />\n"; // *(d->defs) += " \n"; // } // g_free(base64String); // return(idx-1); //} // //void //Wmf::output_style(PWMF_CALLBACK_DATA d) //{ //// SVGOStringStream tmp_id; // SVGOStringStream tmp_style; // char tmp[1024] = {0}; // // float fill_rgb[3]; // sp_color_get_rgb_floatv( &(cur_ctx.style.fill_color), fill_rgb ); // float stroke_rgb[3]; // sp_color_get_rgb_floatv(&(cur_ctx.style.stroke.value.color), stroke_rgb); // // // for _META_BITBLT with no image, try to approximate some of these operations/ // // Assume src color is "white" // if(d->dwRop3){ // switch(d->dwRop3){ // case U_PATINVERT: // treat all of these as black // case U_SRCINVERT: // case U_DSTINVERT: // case U_BLACKNESS: // case U_SRCERASE: // case U_NOTSRCCOPY: // fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=0.0; // break; // case U_SRCCOPY: // treat all of these as white // case U_NOTSRCERASE: // case U_PATCOPY: // case U_WHITENESS: // fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=1.0; // break; // case U_SRCPAINT: // use the existing color // case U_SRCAND: // case U_MERGECOPY: // case U_MERGEPAINT: // case U_PATPAINT: // default: // break; // } // d->dwRop3 = 0; // might as well reset it here, it must be set for each BITBLT // } // // // Implement some of these, the ones where the original screen color does not matter. // // The options that merge screen and pen colors cannot be done correctly because we // // have no way of knowing what color is already on the screen. For those just pass the // // pen color through. // switch(d->dwRop2){ // case U_R2_BLACK: // fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 0.0; // stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 0.0; // break; // case U_R2_NOTMERGEPEN: // case U_R2_MASKNOTPEN: // break; // case U_R2_NOTCOPYPEN: // fill_rgb[0] = 1.0 - fill_rgb[0]; // fill_rgb[1] = 1.0 - fill_rgb[1]; // fill_rgb[2] = 1.0 - fill_rgb[2]; // stroke_rgb[0] = 1.0 - stroke_rgb[0]; // stroke_rgb[1] = 1.0 - stroke_rgb[1]; // stroke_rgb[2] = 1.0 - stroke_rgb[2]; // break; // case U_R2_MASKPENNOT: // case U_R2_NOT: // case U_R2_XORPEN: // case U_R2_NOTMASKPEN: // case U_R2_NOTXORPEN: // case U_R2_NOP: // case U_R2_MERGENOTPEN: // case U_R2_COPYPEN: // case U_R2_MASKPEN: // case U_R2_MERGEPENNOT: // case U_R2_MERGEPEN: // break; // case U_R2_WHITE: // fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 1.0; // stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 1.0; // break; // default: // break; // } // // //// tmp_id << "\n\tid=\"" << (d->id++) << "\""; //// *(d->outsvg) += tmp_id.str().c_str(); // *(d->outsvg) += "\n\tstyle=\""; // if (!cur_ctx.fill_set || ( d->mask & U_DRAW_NOFILL)) { // nofill are lines and arcs // tmp_style << "fill:none;"; // } else { // switch(cur_ctx.fill_mode){ // // both of these use the url(#) method // case DRAW_PATTERN: // snprintf(tmp, 1023, "fill:url(#%s); ",d->hatches.strings[cur_ctx.fill_idx]); // tmp_style << tmp; // break; // case DRAW_IMAGE: // snprintf(tmp, 1023, "fill:url(#WMFimage%d_ref); ",cur_ctx.fill_idx); // tmp_style << tmp; // break; // case DRAW_PAINT: // default: // <-- this should never happen, but just in case... // snprintf( // tmp, 1023, // "fill:#%02x%02x%02x;", // SP_COLOR_F_TO_U(fill_rgb[0]), // SP_COLOR_F_TO_U(fill_rgb[1]), // SP_COLOR_F_TO_U(fill_rgb[2]) // ); // tmp_style << tmp; // break; // } // snprintf( // tmp, 1023, // "fill-rule:%s;", // (cur_ctx.style.fill_rule.value == 0 ? "evenodd" : "nonzero") // ); // tmp_style << tmp; // tmp_style << "fill-opacity:1;"; // // // if the stroke is the same as the fill, and the right size not to change the end size of the object, do not do it separately // if( // (cur_ctx.fill_set ) && // (cur_ctx.stroke_set ) && // (cur_ctx.style.stroke_width.value == 1 ) && // (cur_ctx.fill_mode == cur_ctx.stroke_mode) && // ( // (cur_ctx.fill_mode != DRAW_PAINT) || // ( // (fill_rgb[0]==stroke_rgb[0]) && // (fill_rgb[1]==stroke_rgb[1]) && // (fill_rgb[2]==stroke_rgb[2]) // ) // ) // ){ // cur_ctx.stroke_set = false; // } // } // // if (!cur_ctx.stroke_set) { // tmp_style << "stroke:none;"; // } else { // switch(cur_ctx.stroke_mode){ // // both of these use the url(#) method // case DRAW_PATTERN: // snprintf(tmp, 1023, "stroke:url(#%s); ",d->hatches.strings[cur_ctx.stroke_idx]); // tmp_style << tmp; // break; // case DRAW_IMAGE: // snprintf(tmp, 1023, "stroke:url(#WMFimage%d_ref); ",cur_ctx.stroke_idx); // tmp_style << tmp; // break; // case DRAW_PAINT: // default: // <-- this should never happen, but just in case... // snprintf( // tmp, 1023, // "stroke:#%02x%02x%02x;", // SP_COLOR_F_TO_U(stroke_rgb[0]), // SP_COLOR_F_TO_U(stroke_rgb[1]), // SP_COLOR_F_TO_U(stroke_rgb[2]) // ); // tmp_style << tmp; // break; // } // if(cur_ctx.style.stroke_width.value){ // tmp_style << "stroke-width:" << // MAX( 0.001, cur_ctx.style.stroke_width.value ) << "px;"; // } // else { // In a WMF a 0 width pixel means "1 pixel" // tmp_style << "stroke-width:" << pix_to_abs_size( d, 1 ) << "px;"; // } // // tmp_style << "stroke-linecap:" << // ( // cur_ctx.style.stroke_linecap.computed == 0 ? "butt" : // cur_ctx.style.stroke_linecap.computed == 1 ? "round" : // cur_ctx.style.stroke_linecap.computed == 2 ? "square" : // "unknown" // ) << ";"; // // tmp_style << "stroke-linejoin:" << // ( // cur_ctx.style.stroke_linejoin.computed == 0 ? "miter" : // cur_ctx.style.stroke_linejoin.computed == 1 ? "round" : // cur_ctx.style.stroke_linejoin.computed == 2 ? "bevel" : // "unknown" // ) << ";"; // // // Set miter limit if known, even if it is not needed immediately (not miter) // tmp_style << "stroke-miterlimit:" << // MAX( 2.0, cur_ctx.style.stroke_miterlimit.value ) << ";"; // // if (cur_ctx.style.stroke_dasharray_set && // cur_ctx.style.stroke_dash.n_dash && cur_ctx.style.stroke_dash.dash) // { // tmp_style << "stroke-dasharray:"; // for (int i=0; iid << ")\" "; // clipset = false; // // *(d->outsvg) += tmp_style.str().c_str(); //} double Wmf::_pix_x_to_point(PWMF_CALLBACK_DATA d, double px) { WMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; double scale = (cur_ctx.ScaleInX ? cur_ctx.ScaleInX : 1.0); double tmp; tmp = ((((double) (px - cur_ctx.winorg.x))*scale) + cur_ctx.vieworg.x) * d->D2PscaleX; tmp -= d->ulCornerOutX; //The WMF boundary rectangle can be anywhere, place its upper left corner in the Inkscape upper left corner return(tmp); } double Wmf::_pix_y_to_point(PWMF_CALLBACK_DATA d, double py) { WMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; double scale = (cur_ctx.ScaleInY ? cur_ctx.ScaleInY : 1.0); double tmp; tmp = ((((double) (py - cur_ctx.winorg.y))*scale) * d->E2IdirY + cur_ctx.vieworg.y) * d->D2PscaleY; tmp -= d->ulCornerOutY; //The WMF boundary rectangle can be anywhere, place its upper left corner in the Inkscape upper left corner return(tmp); } double Wmf::pix_to_x_point(PWMF_CALLBACK_DATA d, double px, double py) { double x = _pix_x_to_point(d, px); return x; } double Wmf::pix_to_y_point(PWMF_CALLBACK_DATA d, double px, double py) { double y = _pix_y_to_point(d, py); return y; } double Wmf::pix_to_abs_size(PWMF_CALLBACK_DATA d, double px) { WMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; double ppx = fabs(px * (cur_ctx.ScaleInX ? cur_ctx.ScaleInX : 1.0) * d->D2PscaleX * current_scale(d)); return ppx; } // returns "x,y" (without the quotes) in inkscape coordinates for a pair of WMF x,y coordinates // //std::string Wmf::pix_to_xy(PWMF_CALLBACK_DATA d, double x, double y){ // std::stringstream cxform; // cxform << pix_to_x_point(d,x,y); // cxform << ","; // cxform << pix_to_y_point(d,x,y); // return(cxform.str()); //} // //void //Wmf::select_pen(PWMF_CALLBACK_DATA d, int index) //{ // const char* record = NULL; // U_PEN up; // WMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; // // if (index < 0 && index >= d->n_obj){ return; } // record = d->wmf_obj[index].record; // if(!record){ return; } // cur_ctx.active_pen = index; // // (void) getWmfCreatePenIndirect(record, &up); // int width = up.Widthw[0]; // width is stored in the first 16 bits of the 32. // // switch (up.Style & U_PS_STYLE_MASK) { // case U_PS_DASH: // case U_PS_DOT: // case U_PS_DASHDOT: // case U_PS_DASHDOTDOT: // { // int i = 0; // int penstyle = (up.Style & U_PS_STYLE_MASK); // cur_ctx.style.stroke_dash.n_dash = // penstyle == U_PS_DASHDOTDOT ? 6 : penstyle == U_PS_DASHDOT ? 4 : 2; // if (cur_ctx.style.stroke_dash.dash && (d->level==0 || (d->level>0 && cur_ctx.style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash))) // delete[] cur_ctx.style.stroke_dash.dash; // cur_ctx.style.stroke_dash.dash = new double[cur_ctx.style.stroke_dash.n_dash]; // if (penstyle==U_PS_DASH || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { // cur_ctx.style.stroke_dash.dash[i++] = 3; // cur_ctx.style.stroke_dash.dash[i++] = 1; // } // if (penstyle==U_PS_DOT || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { // cur_ctx.style.stroke_dash.dash[i++] = 1; // cur_ctx.style.stroke_dash.dash[i++] = 1; // } // if (penstyle==U_PS_DASHDOTDOT) { // cur_ctx.style.stroke_dash.dash[i++] = 1; // cur_ctx.style.stroke_dash.dash[i++] = 1; // } // // cur_ctx.style.stroke_dasharray_set = 1; // break; // } // // case U_PS_SOLID: // default: // { // cur_ctx.style.stroke_dasharray_set = 0; // break; // } // } // // switch (up.Style & U_PS_ENDCAP_MASK) { // case U_PS_ENDCAP_ROUND: { cur_ctx.style.stroke_linecap.computed = 1; break; } // case U_PS_ENDCAP_SQUARE: { cur_ctx.style.stroke_linecap.computed = 2; break; } // case U_PS_ENDCAP_FLAT: // default: { cur_ctx.style.stroke_linecap.computed = 0; break; } // } // // switch (up.Style & U_PS_JOIN_MASK) { // case U_PS_JOIN_BEVEL: { cur_ctx.style.stroke_linejoin.computed = 2; break; } // case U_PS_JOIN_MITER: { cur_ctx.style.stroke_linejoin.computed = 0; break; } // case U_PS_JOIN_ROUND: // default: { cur_ctx.style.stroke_linejoin.computed = 1; break; } // } // // // double pen_width; // if (up.Style == U_PS_NULL) { // cur_ctx.stroke_set = false; // pen_width =0.0; // } else if (width) { // cur_ctx.stroke_set = true; // int cur_level = d->level; // d->level = d->wmf_obj[index].level; // this object may have been defined in some other DC. // pen_width = pix_to_abs_size( d, width ); // d->level = cur_level; // } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?) // cur_ctx.stroke_set = true; // int cur_level = d->level; // d->level = d->wmf_obj[index].level; // this object may have been defined in some other DC. // pen_width = pix_to_abs_size( d, 1 ); // d->level = cur_level; // } // cur_ctx.style.stroke_width.value = pen_width; // // double r, g, b; // r = SP_COLOR_U_TO_F( U_RGBAGetR(up.Color) ); // g = SP_COLOR_U_TO_F( U_RGBAGetG(up.Color) ); // b = SP_COLOR_U_TO_F( U_RGBAGetB(up.Color) ); // cur_ctx.style.stroke.value.color.set( r, g, b ); //} // //void //Wmf::select_brush(PWMF_CALLBACK_DATA d, int index) //{ // OdUInt8 iType; // const char *membrush; // // if (index < 0 || index >= d->n_obj)return; // const char* record = d->wmf_obj[index].record; // if(!record) // return; // WMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; // // cur_ctx.active_brush = index; // // iType = *(OdUInt8 *)(record + offsetof(OdWmfRecord, iType ) ); // if(iType == _META_CREATEBRUSHINDIRECT){ // OdWmfLogBrush lb; // getWmfCreateBrushIndirect(record, &membrush); // memcpy(&lb, membrush, OdWmfLogBrushSize); // if(lb.Style == U_BS_SOLID){ // double r, g, b; // r = SP_COLOR_U_TO_F( U_RGBAGetR(lb.Color) ); // g = SP_COLOR_U_TO_F( U_RGBAGetG(lb.Color) ); // b = SP_COLOR_U_TO_F( U_RGBAGetB(lb.Color) ); // cur_ctx.style.fill_color.set( r, g, b ); // cur_ctx.fill_mode = DRAW_PAINT; // cur_ctx.fill_set = true; // } // else if(lb.Style == U_BS_HATCHED){ // cur_ctx.fill_idx = add_hatch(d, lb.Hatch, lb.Color); // cur_ctx.fill_recidx = index; // used if the hatch needs to be redone due to bkMode, textmode, etc. changes // cur_ctx.fill_mode = DRAW_PATTERN; // cur_ctx.fill_set = true; // } // else if(lb.Style == U_BS_NULL){ // cur_ctx.fill_mode = DRAW_PAINT; // set it to something // cur_ctx.fill_set = false; // } // } // else if(iType == _META_DIBCREATEPATTERNBRUSH){ // OdUInt32 tidx; // OdUInt16 Style; // OdUInt16 cUsage; // const char *Bm16h; // Pointer to Bitmap16 header (px follows) // const char *dib; // Pointer to DIB // (void) getWmfDibCreatePatternBrush(record, &Style, &cUsage, &Bm16h, &dib); // // Bm16 not handled yet // if(dib || Bm16h){ // if(dib){ tidx = add_dib_image(d, dib, cUsage); } // else if(Bm16h){ // OdWmfBitmap Bm16; // const char *px; // memcpy(&Bm16, Bm16h, U_SIZE_BITMAP16); // px = Bm16h + U_SIZE_BITMAP16; // tidx = add_bm16_image(d, Bm16, px); // } // if(tidx == 0xFFFFFFFF){ // Problem with the image, for instance, an unsupported bitmap16 type // double r, g, b; // r = SP_COLOR_U_TO_F( U_RGBAGetR(cur_ctx.textColor)); // g = SP_COLOR_U_TO_F( U_RGBAGetG(cur_ctx.textColor)); // b = SP_COLOR_U_TO_F( U_RGBAGetB(cur_ctx.textColor)); // cur_ctx.style.fill_color.set( r, g, b ); // cur_ctx.fill_mode = DRAW_PAINT; // } // else { // cur_ctx.fill_idx = tidx; // cur_ctx.fill_mode = DRAW_IMAGE; // } // cur_ctx.fill_set = true; // } // else { // g_message("Please send WMF file to developers - select_brush _META_DIBCREATEPATTERNBRUSH not bm16 or dib, not handled"); // } // } //} // //void //Wmf::select_font(PWMF_CALLBACK_DATA d, int index) //{ // const char *memfont; // const char *facename; // OdWmfFont font; // // if (index < 0 || index >= d->n_obj) // return; // const char* record = d->wmf_obj[index].record; // if (!record) // return; // WMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; // cur_ctx.active_font = index; // // // (void) getWmfCreateFontIndirect(record, &memfont); // memcpy(&font,memfont,OdWmfFontCoreSize); //make sure it is in a properly aligned structure before touching it // facename = memfont + OdWmfFontCoreSize; // // // The logfont information always starts with a U_LOGFONT structure but the U_WMRCREATEFONTINDIRECT // // is defined as U_LOGFONT_PANOSE so it can handle one of those if that is actually present. Currently only logfont // // is supported, and the remainder, it it really is a U_LOGFONT_PANOSE record, is ignored // int cur_level = d->level; // d->level = d->wmf_obj[index].level; // double font_size = pix_to_abs_size( d, font.Height ); // // 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->D2Pscale[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 .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; // cur_ctx.style.font_size.computed = font_size; // cur_ctx.style.font_weight.value = // font.Weight == U_FW_THIN ? SP_CSS_FONT_WEIGHT_100 : // font.Weight == U_FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_200 : // font.Weight == U_FW_LIGHT ? SP_CSS_FONT_WEIGHT_300 : // font.Weight == U_FW_NORMAL ? SP_CSS_FONT_WEIGHT_400 : // font.Weight == U_FW_MEDIUM ? SP_CSS_FONT_WEIGHT_500 : // font.Weight == U_FW_SEMIBOLD ? SP_CSS_FONT_WEIGHT_600 : // font.Weight == U_FW_BOLD ? SP_CSS_FONT_WEIGHT_700 : // font.Weight == U_FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_800 : // font.Weight == U_FW_HEAVY ? SP_CSS_FONT_WEIGHT_900 : // font.Weight == U_FW_NORMAL ? SP_CSS_FONT_WEIGHT_NORMAL : // font.Weight == U_FW_BOLD ? SP_CSS_FONT_WEIGHT_BOLD : // font.Weight == U_FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_LIGHTER : // font.Weight == U_FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_BOLDER : // U_FW_NORMAL; // cur_ctx.style.font_style.value = (font.Italic ? SP_CSS_FONT_STYLE_ITALIC : SP_CSS_FONT_STYLE_NORMAL); // cur_ctx.style.text_decoration.underline = font.Underline; // cur_ctx.style.text_decoration.line_through = font.StrikeOut; // // // malformed WMF with empty filename may exist, ignore font change if encountered // if(cur_ctx.font_name)free(cur_ctx.font_name); // if(*facename){ // cur_ctx.font_name = strdup(facename); // } // else { // Malformed WMF might specify an empty font name // cur_ctx.font_name = strdup("Arial"); // Default font, WMF spec says device can pick whatever it wants // } // cur_ctx.style.baseline_shift.value = round((double)((font.Escapement + 3600) % 3600) / 10.0); // use baseline_shift instead of text_transform to avoid overflow //} // Find the first free hole where an object may be stored. // If there are not any return -1. This is a big error, possibly from a corrupt WMF file. int Wmf::insertable_object(PWMF_CALLBACK_DATA d) { int index = d->low_water; // Start looking from here, it may already have been filled while (index < d->n_obj && d->wmf_obj[index].record != NULL) index++; ODA_ASSERT_ONCE_X(WMF, index < d->n_obj); if (index >= d->n_obj) return(-1); // this is a big problem, percolate it back up so the program can get out of this gracefully d->low_water = index; // Could probably be index+1 return index; } void Wmf::delete_object(PWMF_CALLBACK_DATA d, int index) { if (index >= 0 && index < d->n_obj) { WMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; // If the active object is deleted set default draw values if (index == cur_ctx.active_pen) { // Use default pen: solid, black, 1 pixel wide cur_ctx.active_pen = -1; //cur_ctx.style.stroke_dasharray_set = 0; //cur_ctx.style.stroke_linecap.computed = 2; // U_PS_ENDCAP_SQUARE //cur_ctx.style.stroke_linejoin.computed = 0; // U_PS_JOIN_MITER; cur_ctx.stroke_set = true; //cur_ctx.style.stroke_width.value = 1.0; //cur_ctx.style.stroke.value.color.set( 0, 0, 0 ); } else if (index == cur_ctx.active_brush) { cur_ctx.active_brush = -1; cur_ctx.fill_set = false; } else if(index == cur_ctx.active_font) { cur_ctx.active_font = -1; if (cur_ctx.font_name) { free(cur_ctx.font_name); } cur_ctx.font_name = strdup("Arial"); // Default font, WMF spec says device can pick whatever it wants //cur_ctx.style.font_size.computed = 16.0; //cur_ctx.style.font_weight.value = SP_CSS_FONT_WEIGHT_400; //cur_ctx.style.font_style.value = SP_CSS_FONT_STYLE_NORMAL; //cur_ctx.style.text_decoration.underline = 0; //cur_ctx.style.text_decoration.line_through = 0; //cur_ctx.style.baseline_shift.value = 0; } d->wmf_obj[index].type = 0; // We are keeping a copy of the WMR rather than just a structure. Currently that is not necessary as the entire // WMF is read in at once and is stored in a big malloc. However, in past versions it was handled // reord by record, and we might need to do that again at some point in the future if we start running into WMF // files too big to fit into memory. if (d->wmf_obj[index].record) d->wmf_obj[index].record = NULL; // record was changed for const char* //free(d->wmf_obj[index].record); d->wmf_obj[index].record = NULL; if(index < d->low_water) d->low_water = index; } } // returns the new index, or -1 on error. int Wmf::insert_object(PWMF_CALLBACK_DATA d, int type, const char *record) { int index = insertable_object(d); if (index >= 0) { d->wmf_obj[index].type = type; d->wmf_obj[index].level = d->level; d->wmf_obj[index].record = record; // record was changed for const char* // = wmr_dup(record); } return index; } // \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 // //OdUInt32 *Wmf::unknown_chars(size_t count){ // OdUInt32 *res = (OdUInt32 *) malloc(sizeof(OdUInt32) * (count + 1)); // if(!res)throw "Inkscape fatal memory allocation error - cannot continue"; // for(OdUInt32 i=0; ioutsvg) += tmp_image.str().c_str(); // // *(d->outsvg) += "/> \n"; // *(d->path) = ""; //} // // // \brief store SVG for an image given the pixmap and various coordinate information // \param d // \param Bm16 core Bitmap16 header // \param px pointer to Bitmap16 image data // \param dx (double) destination x in inkscape pixels // \param dy (double) destination y in inkscape pixels // \param dw (double) destination width in inkscape pixels // \param dh (double) destination height in inkscape pixels // \param sx (int) source x in src image pixels // \param sy (int) source y in src image pixels // \param iUsage // //void Wmf::common_bm16_to_image(PWMF_CALLBACK_DATA d, OdWmfBitmap Bm16, const char *px, // double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh){ // // SVGOStringStream tmp_image; // // tmp_image << " y=\"" << dy << "\"\n x=\"" << dx <<"\"\n "; // // // The image ID is filled in much later when tmp_image is converted // // MEMPNG mempng; // PNG in memory comes back in this // mempng.buffer = NULL; // // char *rgba_px = NULL; // RGBA pixels // char *sub_px = NULL; // RGBA pixels, subarray // const OdWmfQuad *ct = NULL; // color table // int32_t width, height, colortype, numCt, invert; // // numCt = 0; // width = Bm16.Width; // bitmap width in pixels. // height = Bm16.Height; // bitmap height in scan lines. // colortype = Bm16.BitsPixel; // seems to be BitCount Enumeration // invert = 0; // // if(sw == 0 || sh == 0){ // sw = width; // sh = height; // } // // if(colortype < 16)return; // these would need a colortable if they were a dib, no idea what bm16 is supposed to do instead. // if(!DIB_to_RGBA( // This is not really a dib, but close enough... // px, // DIB pixel array // ct, // DIB color table (always NULL here) // numCt, // DIB color table number of entries (always 0) // &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 // colortype, // DIB BitCount Enumeration // numCt, // Color table used if not 0 // 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 // sx,sy, // 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 // sub_px // ); // free(sub_px); // } // if(mempng.buffer){ // tmp_image << " xlink:href=\"data:image/png;base64,"; // gchar *base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size ); // free(mempng.buffer); // tmp_image << base64String; // g_free(base64String); // } // else { // tmp_image << " xlink:href=\"data:image/png;base64,"; // // insert a random 3x4 blotch otherwise // tmp_image << "iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII="; // } // // tmp_image << "\"\n height=\"" << dh << "\"\n width=\"" << dw << "\"\n"; // // tmp_image << " transform=" << current_matrix(d, 0.0, 0.0, 0); // returns an identity matrix, no offsets. // *(d->outsvg) += "\n\t outsvg) += tmp_image.str().c_str(); // // *(d->outsvg) += "/> \n"; // *(d->path) = ""; //} // \fn wmfMetaFileProc(char *contents, unsigned int length, PWMF_CALLBACK_DATA lpData) // \returns true on success, false on error // \param contents binary contents of an WMF file // \param length length in bytes of contents // \param d Inkscape data structures returned by this call // //THis was a callback, just build it into a normal function bool Wmf::wmfMetaFileProc(const char* pcContents, unsigned int length, PWMF_CALLBACK_DATA d) { size_t off = 0; OdUInt32 wmr_mask = 0; int OK = 1; //TCHUNK_SPECS tsp; //OdUInt8 iType = 0; enum META_TYPES type = META_TYPES(0); OdUInt8& iType = *reinterpret_cast(&type); contents = pcContents; //size_t nSize = 0; // size of the current record, in bytes, or an error value if <=0 const char *blimit = contents + length; // 1 byte past the end of the last record // variables used to retrieve data from WMF records OdUInt16 utmp16; OdWmfPoint pt16; // any point OdWmfRect rc; // any rectangle, usually a bounding rectangle OdWmfPoint Dst; // Destination coordinates OdWmfPoint cDst = { 0, 0 }; // Destination w,h, if different from Src OdWmfPoint Src; // Source coordinates OdWmfPoint cSrc; // Source w,h, if different from Dst OdWmfPoint cwh; // w,h, if Src and Dst use the same values OdUInt16 cUsage; // colorusage enumeration OdUInt32 dwRop3; // raster operations, these are only barely supported here const char *dib; // DIB style image structure OdWmfBitmap Bm16; // Bitmap16 style image structure const char *px; // Image for Bm16 OdUInt16 cPts; // number of points in the next variable const char *points; // any list of OdWmfPoint, may not be aligned OdUInt16 tlen; // length of returned text, in bytes const char *text; // returned text, Latin1 encoded OdUInt16 Opts; const OdUInt16 *dx; // character spacing for one text mode, inkscape ignores this double left, right, top, bottom; // values used, because a bounding rect can have values reversed L<->R, T<->B OdUInt16 tbkMode = _TRANSPARENT; // holds proposed change to bkMode, if text is involved saving these to the DC must wait until the text is written ODCOLORREF tbkColor = ODRGB(255, 255, 255); // holds proposed change to bkColor //// initialize the tsp for text reassembly //tsp.string = NULL; //tsp.ori = 0.0; // degrees //tsp.fs = 12.0; // font size //tsp.x = 0.0; //tsp.y = 0.0; //tsp.boff = 0.0; // offset to baseline from LL corner of bounding rectangle, changes with fs and taln //tsp.vadvance = 0.0; // meaningful only when a complex contains two or more lines //tsp.taln = ALILEFT + ALIBASE; //tsp.ldir = LDIR_LR; //tsp.color.Red = 0; // RGB Black //tsp.color.Green = 0; // RGB Black //tsp.color.Blue = 0; // RGB Black //tsp.color.Reserved = 0; // not used //tsp.italics = 0; //tsp.weight = 80; //tsp.decoration = TXTDECOR_NONE; //tsp.condensed = 100; //tsp.co = 0; //tsp.fi_idx = -1; // set to an invalid //SVGOStringStream dbg_str; // There is very little information in WMF headers, get what is there. In many cases pretty much everything will have to // default. If there is no placeable header we know pretty much nothing about the size of the page, in which case // assume that it is 1440 WMF pixels/inch and make the page A4 landscape. That is almost certainly the wrong page size // but it has to be set to something, and nothing horrible happens if the drawing goes off the page. { OdWmfPlaceableHeader Placeable; OdWmfHeader Header; off = 0; nSize = getWmfHeader(contents, blimit, &Placeable, &Header); if (!nSize) return false; if(!Header.nObjects) Header.nObjects = 256; // there _may_ be WMF files with no objects, more likely it is corrupt. Try to use it anyway. d->n_obj = Header.nObjects; d->wmf_obj = new WMF_OBJECT[d->n_obj]; d->low_water = 0; // completely empty at this point, so start searches at 0 // Init the new wmf_obj list elements to null, provided the // dynamic allocation succeeded. if (d->wmf_obj) { for( int i=0; i < d->n_obj; ++i ) d->wmf_obj[i].record = NULL; } //if if (!Placeable.Inch) { Placeable.Inch= 1440; } if (!Placeable.Dst.right && !Placeable.Dst.left) // no page size has been supplied { // This is gross, scan forward looking for a SETWINDOWEXT record, use the first one found to // define the page size size_t hold_nSize = off = nSize; Placeable.Dst.left = 0; Placeable.Dst.top = 0; while (OK) { nSize = getWmfRecordSize(contents + off, blimit); if (nSize) { iType = *(OdUInt8 *)(contents + off + offsetof(OdWmfRecord, iType ) ); type = (META_TYPES)indexToWmr(iType); switch (type) // == iType { case _META_SETWINDOWEXT: OK=0; nSize = getWmfSetWindowExt(contents + off, &Dst); Placeable.Dst.right = Dst.x; Placeable.Dst.bottom = Dst.y; break; case _META_EOF: OK=0; // Really messed up WMF, have to set the page to something, make it A4 horizontal Placeable.Dst.right = (OdInt16) round(((double) Placeable.Inch) * 297.0/25.4); Placeable.Dst.bottom = (OdInt16) round(((double) Placeable.Inch) * 210.0/25.4); break; default: off += nSize; break; } // switch } } off = 0; nSize = hold_nSize; OK = 1; } // drawing size in WMF pixels d->PixelsInX = float(Placeable.Dst.right - Placeable.Dst.left + 1); d->PixelsInY = float(Placeable.Dst.bottom - Placeable.Dst.top + 1); WMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; // // Set values for Window and ViewPort extents to 0 - not defined yet. // cur_ctx.sizeView.x = cur_ctx.sizeWnd.x = 0; cur_ctx.sizeView.y = cur_ctx.sizeWnd.y = 0; // Upper left corner in device units, usually both 0, but not always d->ulCornerInX = Placeable.Dst.left; d->ulCornerInY = Placeable.Dst.top; d->E2IdirY = 1.0; // assume MM_ANISOTROPIC, if not, this will be changed later //d->D2PscaleX = d->D2PscaleY = PX_PER_IN/(double) Placeable.Inch; if (false) { d->D2PscaleX = d->D2PscaleY = kMmPerInch * 100.0 /(double) Placeable.Inch; ////d->MM100InX *= 25.4/(10.0*3.0); ////d->MM100InY *= 25.4/(10.0*3.0); ////d->D2PscaleX *= 25.4/(10.0*3.0); ////d->D2PscaleY *= 25.4/(10.0*3.0); } //trinfo_load_qe(d->tri, d->D2PscaleX); // quantization error that will affect text positions // drawing size in Inkscape pixels d->PixelsOutX = float(d->PixelsInX * d->D2PscaleX); d->PixelsOutY = float(d->PixelsInY * d->D2PscaleY); // Upper left corner in Inkscape units d->ulCornerOutX = d->ulCornerInX * d->D2PscaleX; d->ulCornerOutY = d->ulCornerInY * d->E2IdirY * d->D2PscaleY; //d->dc[0].style.stroke_width.value = pix_to_abs_size( d, 1 ); // This could not be set until the size of the WMF was known //dbg_str << "\n"; // *(d->outdef) += "\n"; //SVGOStringStream tmp_outdef; //tmp_outdef << "PixelsOutX/ PX_PER_MM << "mm\"\n" << // " height=\"" << d->PixelsOutY/ PX_PER_MM << "mm\">\n"; // *(d->outdef) += tmp_outdef.str().c_str(); // *(d->outdef) += ""; // temporary end of header // //// d->defs holds any defines which are read in. } // --------------------- ODA_ASSERT_VAR(OdArray types;) while (OK) { if (off >= length) //normally should exit from while after WMREOF sets OK to false. return false; contents += nSize; // pointer to the start of the next record off += nSize; // offset from beginning of buffer to the start of the next record //SVGOStringStream tmp_path; //SVGOStringStream tmp_str; // Check that the current record size is OK, abort if not. // Pointer math might wrap, so check both sides of the range. // Some of the records will reset this with the same value,others will not // return a value at this time. nSize = getWmfRecordSize(contents, blimit); if (!nSize) break; iType = *(OdUInt8 *)(contents + offsetof(OdWmfRecord, iType)); type = (META_TYPES)indexToWmr(iType); WMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; ODA_ASSERT_VAR(types.push_back(type);) // Uncomment the following to track down toxic records // std::cout << "record type: " << (int) iType << " name " << U_wmr_names(iType) << " length: " << nSize << " offset: " << off <dirty:"<< d->tri->dirty << " wmr_mask: " << std::hex << wmr_mask << std::dec << std::endl; // incompatible change to text drawing detected (color or background change) forces out existing text // OR // next record is valid type and forces pending text to be drawn immediately //if ((cur_ctx.dirty & DIRTY_TEXT) || ((wmr_mask != 0xFFFFFFFF) && (wmr_mask & U_DRAW_TEXT) && d->tri->dirty)){ // TR_layout_analyze(d->tri); // TR_layout_2_svg(d->tri); // SVGOStringStream ts; // ts << d->tri->out; // *(d->outsvg) += ts.str().c_str(); // d->tri = trinfo_clear(d->tri); //} //if(cur_ctx.dirty){ //Apply the delayed background changes, clear the flag // cur_ctx.bkMode = tbkMode; // memcpy(&(cur_ctx.bkColor),&tbkColor, sizeof(ODCOLORREF)); // // if(cur_ctx.dirty & DIRTY_TEXT){ // // ODCOLORREF and TRCOLORREF are exactly the same in memory, but the compiler needs some convincing... // if(tbkMode == U_TRANSPARENT){ (void) trinfo_load_bk(d->tri, BKCLR_NONE, *(TRCOLORREF *) &tbkColor); } // else // { // (void) trinfo_load_bk(d->tri, BKCLR_LINE, *(TRCOLORREF *) &tbkColor); } // Opaque // } // // // It is possible to have a series of EMF records that would result in // // the following creating hash patterns which are never used. For instance, if // // there were a series of records that changed the background color but did nothing // // else. // if((cur_ctx.fill_mode == DRAW_PATTERN) && (cur_ctx.dirty & DIRTY_FILL)) // { // select_brush(d, cur_ctx.fill_recidx); // } // // cur_ctx.dirty = 0; //} //std::cout << "BEFORE DRAW logic d->mask: " << std::hex << d->mask << " wmr_mask: " << wmr_mask << std::dec << std::endl; //std::cout << "BEFORE DRAW" // << " test0 " << ( d->mask & U_DRAW_VISIBLE) // << " test1 " << ( d->mask & U_DRAW_FORCE) // << " test2 " << (wmr_mask & U_DRAW_ALTERS) // << " test3 " << (wmr_mask & U_DRAW_VISIBLE) // << " test4 " << !(d->mask & U_DRAW_ONLYTO) // << " test5 " << ((d->mask & U_DRAW_ONLYTO) && !(wmr_mask & U_DRAW_ONLYTO) ) // << std::endl; //if( // (wmr_mask != 0xFFFFFFFF) && // next record is valid type // (d->mask & U_DRAW_VISIBLE) && // This record is drawable // ( // (d->mask & U_DRAW_FORCE) || // This draw is forced by STROKE/FILL/STROKEANDFILL PATH // (wmr_mask & U_DRAW_ALTERS) || // Next record would alter the drawing environment in some way // ( (wmr_mask & U_DRAW_VISIBLE) && // Next record is visible... // ( // ( !(d->mask & U_DRAW_ONLYTO) ) || // Non *TO records cannot be followed by any Visible // ((d->mask & U_DRAW_ONLYTO) && !(wmr_mask & U_DRAW_ONLYTO) )// *TO records can only be followed by other *TO records // ) // ) // ) //) //{ ////std::cout << "PATH DRAW at TOP <<+++++++++++++++++++++++++++++++++++++" << std::endl; // *(d->outsvg) += " outsvg) += "\n\t"; // *(d->outsvg) += "\n\td=\""; // this is the ONLY place d=" should be used!!!! // *(d->outsvg) += *(d->path); // *(d->outsvg) += " \" /> \n"; // *(d->path) = ""; //reset the path // // reset the flags // d->mask = 0; // d->drawtype = 0; //} // std::cout << "AFTER DRAW logic d->mask: " << std::hex << d->mask << " wmr_mask: " << wmr_mask << std::dec << std::endl; ODA_ASSERT_VAR(static int s_idxCatch = -1;) ODA_ASSERT_VAR(int idxType = (int)types.size() - 1;) ODA_ASSERT_VAR(if (s_idxCatch >= 0 && idxType == s_idxCatch)) ODA_ASSERT_VAR(return true;) // brk if (false) return true; switch (type) // switch (iType) { case _META_EOF: { //dbg_str << "\n"; // *(d->outsvg) = *(d->outdef) + *(d->defs) + "\n\n\n" + *(d->outsvg) + "\n"; OK=0; break; } case _META_SETBKCOLOR: { //dbg_str << "\n"; nSize = getWmfSetBkColor(contents, &tbkColor); //if(memcmp(&tbkColor, &(cur_ctx.bkColor), sizeof(ODCOLORREF))){ // cur_ctx.dirty |= DIRTY_TEXT; // if(cur_ctx.fill_mode == DRAW_PATTERN){ cur_ctx.dirty |= DIRTY_FILL; } // tbkMode = cur_ctx.bkMode; //} break; } case _META_SETBKMODE: { //dbg_str << "\n"; nSize = getWmfSetBkMode(contents, &tbkMode); //if(tbkMode != cur_ctx.bkMode){ // cur_ctx.dirty |= DIRTY_TEXT; // if(tbkMode != cur_ctx.bkMode){ // if(cur_ctx.fill_mode == DRAW_PATTERN){ cur_ctx.dirty |= DIRTY_FILL; } // } // memcpy(&tbkColor,&(cur_ctx.bkColor),sizeof(ODCOLORREF)); //} break; } case _META_SETMAPMODE: { //dbg_str << "\n"; nSize = getWmfSetMapMode(contents, &utmp16); //switch (utmp16){ //case U_MM_TEXT: //default: // // Use all values from the header. // break; //For all of the following the indicated scale this will be encoded in WindowExtEx/ViewportExtex // and show up in ScaleIn[XY] // //case U_MM_LOMETRIC: // 1 LU = 0.1 mm, //case U_MM_HIMETRIC: // 1 LU = 0.01 mm //case U_MM_LOENGLISH: // 1 LU = 0.1 in //case U_MM_HIENGLISH: // 1 LU = 0.01 in //case U_MM_TWIPS: // 1 LU = 1/1440 in // d->E2IdirY = -1.0; // // Use d->D2Pscale[XY] values from the header. // break; //case U_MM_ISOTROPIC: // ScaleIn[XY] should be set elsewhere by SETVIEWPORTEXTEX and SETWINDOWEXTEX //case U_MM_ANISOTROPIC: // break; //} break; } case _META_SETROP2: { //dbg_str << "\n"; nSize = getWmfSetOp2(contents, &utmp16); d->dwRop2 = utmp16; break; } case _META_SETRELABS: //dbg_str << "\n"; break; case _META_SETPOLYFILLMODE: { //dbg_str << "\n"; nSize = getWmfSetPolyFillMode(contents, &utmp16); //cur_ctx.style.fill_rule.value = (utmp16 == U_ALTERNATE ? 0 : utmp16 == U_WINDING ? 1 : 0); break; } case _META_SETSTRETCHBLTMODE: { //dbg_str << "\n"; nSize = getWmfSetStretchBltMode(contents, &utmp16); //BLTmode = utmp16; break; } case _META_SETTEXTCHAREXTRA: //dbg_str << "\n"; break; case _META_SETTEXTCOLOR: { //dbg_str << "\n"; nSize = getWmfSetTextColor(contents, &(cur_ctx.textColor)); //if(tbkMode != cur_ctx.bkMode){ // if(cur_ctx.fill_mode == DRAW_PATTERN){ cur_ctx.dirty |= DIRTY_FILL; } //} //// not text_dirty, because multicolored complex text is supported in libTERE break; } case _META_SETTEXTJUSTIFICATION: //dbg_str << "\n"; break; case _META_SETWINDOWORG: { //dbg_str << "\n"; nSize = getOdWmfSetWindowOrg(contents, &cur_ctx.winorg); break; } case _META_SETWINDOWEXT: { //dbg_str << "\n"; nSize = getWmfSetWindowExt(contents, &cur_ctx.sizeWnd); if (!cur_ctx.sizeWnd.x || !cur_ctx.sizeWnd.y) { cur_ctx.sizeWnd = cur_ctx.sizeView; if (!cur_ctx.sizeWnd.x || !cur_ctx.sizeWnd.y) { cur_ctx.sizeWnd.x = (OdInt16) d->PixelsOutX; cur_ctx.sizeWnd.y = (OdInt16) d->PixelsOutY; } } if (!cur_ctx.sizeView.x || !cur_ctx.sizeView.y) { cur_ctx.sizeView = cur_ctx.sizeWnd; } // scales logical to WMF pixels, transfer a negative sign on Y, if any if (cur_ctx.sizeWnd.x && cur_ctx.sizeWnd.y) { cur_ctx.ScaleInX = (double) cur_ctx.sizeView.x / (double) cur_ctx.sizeWnd.x; cur_ctx.ScaleInY = (double) cur_ctx.sizeView.y / (double) cur_ctx.sizeWnd.y; if(cur_ctx.ScaleInY < 0) { cur_ctx.ScaleInY *= -1.0; d->E2IdirY = -1.0; } } else { cur_ctx.ScaleInX = 1; cur_ctx.ScaleInY = 1; } if (hasDrawCtx() && indexToWmr(iType) == _META_SETWINDOWEXT) //*** { // draw initial white rect ODCOLORREF svBkColor = cur_ctx.bkColor; cur_ctx.bkColor = ODRGB(255, 255, 255); // default color (white) double dx = 0, dy = 0, dw = cur_ctx.sizeWnd.x, dh = cur_ctx.sizeWnd.y; rectangle_brush(d, dx, dy, dw, dh); cur_ctx.bkColor = svBkColor; } break; } case _META_SETVIEWPORTORG: { //dbg_str << "\n"; nSize = getWmfSetViewportOrg(contents, &cur_ctx.vieworg); break; } case _META_SETVIEWPORTEXT: { //dbg_str << "\n"; nSize = getWmfSetViewportText(contents, &cur_ctx.sizeView); if (!cur_ctx.sizeView.x || !cur_ctx.sizeView.y) { cur_ctx.sizeView = cur_ctx.sizeWnd; if (!cur_ctx.sizeView.x || !cur_ctx.sizeView.y) { cur_ctx.sizeView.x = (OdInt16) d->PixelsOutX; cur_ctx.sizeView.y = (OdInt16) d->PixelsOutY; } } if (!cur_ctx.sizeWnd.x || !cur_ctx.sizeWnd.y) { cur_ctx.sizeWnd = cur_ctx.sizeView; } // scales logical to WMF pixels, transfer a negative sign on Y, if any if (cur_ctx.sizeWnd.x && cur_ctx.sizeWnd.y) { cur_ctx.ScaleInX = (double) cur_ctx.sizeView.x / (double) cur_ctx.sizeWnd.x; cur_ctx.ScaleInY = (double) cur_ctx.sizeView.y / (double) cur_ctx.sizeWnd.y; if(cur_ctx.ScaleInY < 0) { cur_ctx.ScaleInY *= -1.0; d->E2IdirY = -1.0; } } else { cur_ctx.ScaleInX = 1; cur_ctx.ScaleInY = 1; } break; } case _META_OFFSETWINDOWORG: //dbg_str << "\n"; break; case _META_SCALEWINDOWEXT: //dbg_str << "\n"; break; case _META_OFFSETVIEWPORTORG: //dbg_str << "\n"; break; case _META_SCALEVIEWPORTEXT: //dbg_str << "\n"; break; case _META_LINETO: { //dbg_str << "\n"; nSize = getWmfLineTo(contents, &pt16); d->mask |= wmr_mask; //tmp_path << "\n\tL " << pix_to_xy( d, pt16.x, pt16.y) << " "; break; } case _META_MOVETO: { //dbg_str << "\n"; nSize = getWmfLineTo(contents, &pt16); d->mask |= wmr_mask; cur_ctx.cur = pt16; ODA_ASSERT_VAR(if (pt16.x || pt16.y)) ODA_ASSERT(true); // brk // ? TODO // ???? x = pix_to_x_point(d, pt16.x, pt16.y); y = pix_to_y_point(d, pt16.x, pt16.y); //tmp_path << "\n\tM " << pix_to_xy( d, pt16.x, pt16.y ) << " "; break; } case _META_EXCLUDECLIPRECT: //dbg_str << "\n"; break; case _META_INTERSECTCLIPRECT: { //dbg_str << "\n"; nSize = getWmfIntersectClipRect(contents, &rc); if (!hasDrawCtx()) break; //clipset = true; if ((rc.left == rc_old.left) && (rc.top == rc_old.top) && (rc.right == rc_old.right) && (rc.bottom == rc_old.bottom)) break; rc_old = rc; double dx = pix_to_x_point( d, rc.left, rc.top ); double dy = pix_to_y_point( d, rc.left, rc.top ); double dw = pix_to_abs_size( d, rc.right - rc.left + 1); double dh = pix_to_abs_size( d, rc.bottom - rc.top + 1); rectangle_clip(d, dx, dy, dw, dh); //SVGOStringStream tmp_rectangle; //tmp_rectangle << "\nid) << "\" >"; //tmp_rectangle << "\n"; //tmp_rectangle << "\n"; // *(d->outdef) += tmp_rectangle.str().c_str(); // *(d->path) = ""; break; } case _META_ARC: { //dbg_str << "\n"; OdWmfPoint ArcStart, ArcEnd; nSize = getWmfArc(contents, &ArcStart, &ArcEnd, &rc); //OdWmfPointF center,start,end,size; //int f1; //int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1); //int stat = getWmfArcPoints(rc, ArcStart, ArcEnd,&f1, f2, ¢er, &start, &end, &size); //if(!stat){ // tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y); // tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ; // tmp_path << " "; // tmp_path << 180.0 * current_rotation(d)/M_PI; // tmp_path << " "; // tmp_path << " " << f1 << "," << f2 << " "; // tmp_path << pix_to_xy(d, end.x, end.y) << " \n"; // d->mask |= wmr_mask; //} //else { // dbg_str << "\n"; //} break; } case _META_ELLIPSE: { //dbg_str << "\n"; nSize = getWmfEllipse(contents, &rc); //double cx = pix_to_x_point( d, (rc.left + rc.right)/2.0, (rc.bottom + rc.top)/2.0 ); //double cy = pix_to_y_point( d, (rc.left + rc.right)/2.0, (rc.bottom + rc.top)/2.0 ); //double rx = pix_to_abs_size( d, fabs(rc.right - rc.left )/2.0 ); //double ry = pix_to_abs_size( d, fabs(rc.top - rc.bottom)/2.0 ); //SVGOStringStream tmp_ellipse; //tmp_ellipse << "cx=\"" << cx << "\" "; //tmp_ellipse << "cy=\"" << cy << "\" "; //tmp_ellipse << "rx=\"" << rx << "\" "; //tmp_ellipse << "ry=\"" << ry << "\" "; //d->mask |= wmr_mask; // *(d->outsvg) += " outsvg) += "\n\t"; // *(d->outsvg) += tmp_ellipse.str().c_str(); // *(d->outsvg) += "/> \n"; // *(d->path) = ""; break; } case _META_FLOODFILL: //dbg_str << "\n"; break; case _META_PIE: { //dbg_str << "\n"; OdWmfPoint ArcStart, ArcEnd; nSize = getWmfPie(contents, &ArcStart, &ArcEnd, &rc); //OdWmfPointF center,start,end,size; //int f1; //int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1); //if(!getWmfArcPoints(rc, ArcStart, ArcEnd, &f1, f2, ¢er, &start, &end, &size)){ // tmp_path << "\n\tM " << pix_to_xy(d, center.x, center.y); // tmp_path << "\n\tL " << pix_to_xy(d, start.x, start.y); // tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ; // tmp_path << " "; // tmp_path << 180.0 * current_rotation(d)/M_PI; // tmp_path << " "; // tmp_path << " " << f1 << "," << f2 << " "; // tmp_path << pix_to_xy(d, end.x, end.y) << " \n"; // tmp_path << " z "; // d->mask |= wmr_mask; //} //else { // dbg_str << "\n"; //} break; } case _META_RECTANGLE: { //dbg_str << "\n"; nSize = getWmfRectangle(contents, &rc); //U_sanerect16(rc, &left, &top, &right, &bottom); //SVGOStringStream tmp_rectangle; //tmp_rectangle << "\n\tM " << pix_to_xy( d, left , top ) << " "; //tmp_rectangle << "\n\tL " << pix_to_xy( d, right, top ) << " "; //tmp_rectangle << "\n\tL " << pix_to_xy( d, right, bottom ) << " "; //tmp_rectangle << "\n\tL " << pix_to_xy( d, left, bottom ) << " "; //tmp_rectangle << "\n\tz"; d->mask |= wmr_mask; //tmp_path << tmp_rectangle.str().c_str(); break; } case _META_ROUNDRECT: { //dbg_str << "\n"; OdInt16 Height, Width; nSize = getWmfRoundRect(contents, &Width, &Height, &rc); //U_sanerect16(rc, &left, &top, &right, &bottom); //double f = 4.*(sqrt(2) - 1)/3; //double f1 = 1.0 - f; //double cnx = Width/2; //double cny = Height/2; //SVGOStringStream tmp_rectangle; //tmp_rectangle << "\n" // << " M " // << pix_to_xy(d, left , top + cny ) // << "\n"; //tmp_rectangle << " C " // << pix_to_xy(d, left , top + cny*f1 ) // << " " // << pix_to_xy(d, left + cnx*f1 , top ) // << " " // << pix_to_xy(d, left + cnx , top ) // << "\n"; //tmp_rectangle << " L " // << pix_to_xy(d, right - cnx , top ) // << "\n"; //tmp_rectangle << " C " // << pix_to_xy(d, right - cnx*f1 , top ) // << " " // << pix_to_xy(d, right , top + cny*f1 ) // << " " // << pix_to_xy(d, right , top + cny ) // << "\n"; //tmp_rectangle << " L " // << pix_to_xy(d, right , bottom - cny ) // << "\n"; //tmp_rectangle << " C " // << pix_to_xy(d, right , bottom - cny*f1 ) // << " " // << pix_to_xy(d, right - cnx*f1 , bottom ) // << " " // << pix_to_xy(d, right - cnx , bottom ) // << "\n"; //tmp_rectangle << " L " // << pix_to_xy(d, left + cnx , bottom ) // << "\n"; //tmp_rectangle << " C " // << pix_to_xy(d, left + cnx*f1 , bottom ) // << " " // << pix_to_xy(d, left , bottom - cny*f1 ) // << " " // << pix_to_xy(d, left , bottom - cny ) // << "\n"; //tmp_rectangle << " z\n"; d->mask |= wmr_mask; //tmp_path << tmp_rectangle.str().c_str(); break; } case _META_PATBLT: { //dbg_str << "\n"; // Treat this like any other rectangle, ie, ignore the dwRop3 nSize = getWmfPatBlt(contents, &Dst, &cwh, &dwRop3); //SVGOStringStream tmp_rectangle; //tmp_rectangle << "\n\tM " << pix_to_xy( d, Dst.x , Dst.y ) << " "; //tmp_rectangle << "\n\tL " << pix_to_xy( d, Dst.x + cwh.x, Dst.y ) << " "; //tmp_rectangle << "\n\tL " << pix_to_xy( d, Dst.x + cwh.x, Dst.y + cwh.y ) << " "; //tmp_rectangle << "\n\tL " << pix_to_xy( d, Dst.x, Dst.y + cwh.y ) << " "; //tmp_rectangle << "\n\tz"; d->mask |= wmr_mask; //tmp_path << tmp_rectangle.str().c_str(); break; } case _META_SAVEDC: { //dbg_str << "\n"; if (d->level < WMF_MAX_DC) { d->dc[d->level + 1] = cur_ctx; // = d->dc[d->level]; if (cur_ctx.font_name) d->dc[d->level + 1].font_name = strdup(cur_ctx.font_name); // or memory access problems because font name pointer duplicated d->level = d->level + 1; } break; } case _META_SETPIXEL: //dbg_str << "\n"; break; case _META_OFFSETCLIPRGN: //dbg_str << "\n"; break; // _META_TEXTOUT should be here, but has been moved down to merge with _META_EXTTEXTOUT case _META_BITBLT: { //dbg_str << "\n"; nSize = getWmfBitBlt(contents, &Dst, &cwh, &Src, &dwRop3, &Bm16, &px); if(!px) { //int32_t dx = Dst.x; //int32_t dy = Dst.y; //int32_t dw = cwh.x; //int32_t dh = cwh.y; //SVGOStringStream tmp_rectangle; //tmp_rectangle << "\n\tM " << pix_to_xy( d, dx, dy ) << " "; //tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy ) << " "; //tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy + dh ) << " "; //tmp_rectangle << "\n\tL " << pix_to_xy( d, dx, dy + dh ) << " "; //tmp_rectangle << "\n\tz"; d->mask |= wmr_mask; d->dwRop3 = dwRop3; // we will try to approximate SOME of these d->mask |= _DRAW_CLOSED; // Bitblit is not really open or closed, but we need it to fill, and this is the flag for that //tmp_path << tmp_rectangle.str().c_str(); } else { // Not done yet, Bm16 image present } double dx = pix_to_x_point( d, Dst.x, Dst.y); double dy = pix_to_y_point( d, Dst.x, Dst.y); double dw = pix_to_abs_size( d, cwh.x); double dh = pix_to_abs_size( d, cwh.y); //source position within the bitmap, in pixels int sx = Src.x; int sy = Src.y; int sw = 0; // extract all of the image int sh = 0; if(sx<0)sx=0; if(sy<0)sy=0; common_bm16_to_image(d,Bm16,px,dx,dy,dw,dh,sx,sy,sw,sh); break; } case _META_STRETCHBLT: { //dbg_str << "\n"; nSize = getWmfStretchBlt(contents,&Dst,&cDst,&Src,&cSrc,&dwRop3,&Bm16,&px); if(!px) { //int32_t dx = Dst.x; //int32_t dy = Dst.y; //int32_t dw = cDst.x; //int32_t dh = cDst.y; //SVGOStringStream tmp_rectangle; //tmp_rectangle << "\n\tM " << pix_to_xy( d, dx, dy ) << " "; //tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy ) << " "; //tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy + dh ) << " "; //tmp_rectangle << "\n\tL " << pix_to_xy( d, dx, dy + dh ) << " "; //tmp_rectangle << "\n\tz"; d->mask |= wmr_mask; d->dwRop3 = dwRop3; // we will try to approximate SOME of these d->mask |= _DRAW_CLOSED; // Bitblit is not really open or closed, but we need it to fill, and this is the flag for that //tmp_path << tmp_rectangle.str().c_str(); } //else //{ // // Not done yet, Bm16 image present //} double dx = pix_to_x_point( d, Dst.x, Dst.y); double dy = pix_to_y_point( d, Dst.x, Dst.y); double dw = pix_to_abs_size( d, cDst.x); double dh = pix_to_abs_size( d, cDst.y); //source position within the bitmap, in pixels int sx = Src.x; int sy = Src.y; int sw = cSrc.x; // extract the specified amount of the image int sh = cSrc.y; if(sx<0)sx=0; if(sy<0)sy=0; common_bm16_to_image(d,Bm16,px,dx,dy,dw,dh,sx,sy,sw,sh); break; } case _META_POLYGON: case _META_POLYLINE: { //dbg_str << "\n"; nSize = getWmfPolygon(contents, &cPts, &points); OdUInt32 i; if (cPts < 2) break; d->mask |= wmr_mask; memcpy(&pt16,points,OdWmfPointSize); points += OdWmfPointSize; //tmp_str << "\n\tM " << pix_to_xy( d, pt16.x, pt16.y) << " "; //for (i=1; i\n"; OdUInt16 Escape, elen; nSize = getWmfEscape(contents, &Escape, &elen, &text); if (elen>=4) { OdUInt32 utmp4; memcpy(&utmp4, text ,4); if (Escape == _MFE_SETLINECAP) { //switch (utmp4 & U_PS_ENDCAP_MASK) { // case U_PS_ENDCAP_ROUND: { cur_ctx.style.stroke_linecap.computed = 1; break; } // case U_PS_ENDCAP_SQUARE: { cur_ctx.style.stroke_linecap.computed = 2; break; } // case U_PS_ENDCAP_FLAT: // default: { cur_ctx.style.stroke_linecap.computed = 0; break; } //} } else if (Escape == _MFE_SETLINEJOIN) { //switch (utmp4 & U_PS_JOIN_MASK) { // case U_PS_JOIN_BEVEL: { cur_ctx.style.stroke_linejoin.computed = 2; break; } // case U_PS_JOIN_MITER: { cur_ctx.style.stroke_linejoin.computed = 0; break; } // case U_PS_JOIN_ROUND: // default: { cur_ctx.style.stroke_linejoin.computed = 1; break; } //} } else if (Escape == _MFE_SETMITERLIMIT) { //The function takes a float but uses a 32 bit int in the record. //float miterlimit = utmp4; //cur_ctx.style.stroke_miterlimit.value = miterlimit; //ratio, not a pt size //if (cur_ctx.style.stroke_miterlimit.value < 2) // cur_ctx.style.stroke_miterlimit.value = 2.0; } } break; } case _META_RESTOREDC: { //dbg_str << "\n"; OdInt16 DC; nSize = getWmfRestoreDc(contents, &DC); int old_level = d->level; if (DC >= 0) { if (DC < d->level) d->level = DC; } else { if (d->level + DC >= 0) d->level = d->level + DC; } while (old_level > d->level) { //if (d->dc[old_level].style.stroke_dash.dash && (old_level==0 || (old_level>0 && d->dc[old_level].style.stroke_dash.dash!=d->dc[old_level-1].style.stroke_dash.dash))){ // delete[] d->dc[old_level].style.stroke_dash.dash; //} if(d->dc[old_level].font_name){ free(d->dc[old_level].font_name); // else memory leak d->dc[old_level].font_name = NULL; } old_level--; } break; } case _META_FILLREGION: //dbg_str << "\n"; break; case _META_FRAMEREGION: //dbg_str << "\n"; break; case _META_INVERTREGION: //dbg_str << "\n"; break; case _META_PAINTREGION: //dbg_str << "\n"; break; case _META_SELECTCLIPREGION: { //dbg_str << "\n"; nSize = getWmfSelectClipRegion(contents, &utmp16); //if (utmp16 == U_RGN_COPY) // clipset = false; break; } case _META_SELECTOBJECT: { //dbg_str << "\n"; nSize = getWmfSelectObject(contents, &utmp16); if (!hasDrawCtx()) break; unsigned int index = utmp16; // WMF has no stock objects if ( //index >= 0 && index < (unsigned int) d->n_obj) { switch (d->wmf_obj[index].type) { case _META_CREATEPENINDIRECT: select_pen(d, index); break; case _META_CREATEBRUSHINDIRECT: case _META_DIBCREATEPATTERNBRUSH: select_brush(d, index); break; case _META_CREATEFONTINDIRECT: select_font(d, index); break; case _META_CREATEPATTERNBRUSH: // <- this one did not display properly on XP, DIBCREATEPATTERNBRUSH works case _META_CREATEPALETTE: case _META_CREATEBITMAPINDIRECT: case _META_CREATEBITMAP: case _META_CREATEREGION: // these do not do anything, but their objects must be kept in the count break; } } break; } case _META_SETTEXTALIGN: { //dbg_str << "\n"; nSize = getWmfSetTextAlign(contents, &(cur_ctx.textAlign)); break; } case _META_DRAWTEXT: //dbg_str << "\n"; break; case _META_CHORD: { //dbg_str << "\n"; OdWmfPoint ArcStart, ArcEnd; nSize = getWmfChord(contents, &ArcStart, &ArcEnd, &rc); OdWmfPointF center,start,end,size; int f1; int f2 = (d->arcdir == _AD_COUNTERCLOCKWISE ? 0 : 1); if (!getWmfArcPoints(rc, ArcStart, ArcEnd, &f1, f2, ¢er, &start, &end, &size)) { //tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y); //tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ; //tmp_path << " "; //tmp_path << 180.0 * current_rotation(d)/M_PI; //tmp_path << " "; //tmp_path << " " << f1 << "," << f2 << " "; //tmp_path << pix_to_xy(d, end.x, end.y) << " \n"; //tmp_path << " z "; d->mask |= wmr_mask; } //else //{ // dbg_str << "\n"; //} break; } case _META_SETMAPPERFLAGS: //dbg_str << "\n"; break; case _META_TEXTOUT: case _META_EXTTEXTOUT: { if (type == _META_TEXTOUT) // iType == _META_TEXTOUT) { //dbg_str << "\n"; nSize = getWmfTextOut(contents, &Dst, &tlen, &text); } else { //dbg_str << "\n"; nSize = getWmfExtTextOut(contents, &Dst, &tlen, &Opts, &text, &dx, &rc); } if (!hasDrawCtx()) break; double x1,y1; int cChars; x1 = Dst.x; y1 = Dst.y; cChars = tlen; if (cur_ctx.textAlign & _TA_UPDATECP) { x1 = cur_ctx.cur.x; y1 = cur_ctx.cur.y; } double x = pix_to_x_point(d, x1, y1); double y = pix_to_y_point(d, x1, y1); // Rotation issues are handled entirely in libTERE now //#if 1 OdString sText = OdString_fromLatin1(text, cChars); //#else // OdUInt32 *dup_wt = U_Latin1ToUtf32le(text, cChars, NULL); // if (!dup_wt) // break; // dup_wt = unknown_chars(cChars); // // //msdepua(dup_wt); //convert everything in Microsoft's private use area. For Symbol, Wingdings, Dingbats // // //if(NonToUnicode(dup_wt, cur_ctx.font_name)) // //{ // // free(cur_ctx.font_name); // // cur_ctx.font_name = strdup("Times New Roman"); // //} // // OdString sText = OdString_fromUtf32(dup_wt, cChars); // // //char *ansi_text = (char *) U_Utf32leToUtf8((OdUInt32 *)dup_wt, 0, NULL); // free(dup_wt); // //// Empty text 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(*((OdUInt8 *)ansi_text) <= 0x1F){ // // free(ansi_text); // // ansi_text=NULL; // //} //#endif if (!sText.isEmpty() && cur_ctx.style.text_style.get())//if (ansi_text) text_out(d, sText, x, y); //{ // SVGOStringStream ts; // gchar *escaped_text = g_markup_escape_text(ansi_text, -1); // // tsp.x = x*0.8; // TERE expects sizes in points // tsp.y = y*0.8; // tsp.color.Red = cur_ctx.textColor.Red; // tsp.color.Green = cur_ctx.textColor.Green; // tsp.color.Blue = cur_ctx.textColor.Blue; // tsp.color.Reserved = 0; // switch(cur_ctx.style.font_style.value){ // case SP_CSS_FONT_STYLE_OBLIQUE: // tsp.italics = FC_SLANT_OBLIQUE; break; // case SP_CSS_FONT_STYLE_ITALIC: // tsp.italics = FC_SLANT_ITALIC; break; // default: // case SP_CSS_FONT_STYLE_NORMAL: // tsp.italics = FC_SLANT_ROMAN; break; // } // switch(cur_ctx.style.font_weight.value){ // case SP_CSS_FONT_WEIGHT_100: tsp.weight = FC_WEIGHT_THIN ; break; // case SP_CSS_FONT_WEIGHT_200: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break; // case SP_CSS_FONT_WEIGHT_300: tsp.weight = FC_WEIGHT_LIGHT ; break; // case SP_CSS_FONT_WEIGHT_400: tsp.weight = FC_WEIGHT_NORMAL ; break; // case SP_CSS_FONT_WEIGHT_500: tsp.weight = FC_WEIGHT_MEDIUM ; break; // case SP_CSS_FONT_WEIGHT_600: tsp.weight = FC_WEIGHT_SEMIBOLD ; break; // case SP_CSS_FONT_WEIGHT_700: tsp.weight = FC_WEIGHT_BOLD ; break; // case SP_CSS_FONT_WEIGHT_800: tsp.weight = FC_WEIGHT_EXTRABOLD ; break; // case SP_CSS_FONT_WEIGHT_900: tsp.weight = FC_WEIGHT_HEAVY ; break; // case SP_CSS_FONT_WEIGHT_NORMAL: tsp.weight = FC_WEIGHT_NORMAL ; break; // case SP_CSS_FONT_WEIGHT_BOLD: tsp.weight = FC_WEIGHT_BOLD ; break; // case SP_CSS_FONT_WEIGHT_LIGHTER: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break; // case SP_CSS_FONT_WEIGHT_BOLDER: tsp.weight = FC_WEIGHT_EXTRABOLD ; break; // default: tsp.weight = FC_WEIGHT_NORMAL ; break; // } // // Inkscape cannot display underline or strike-through at present, but enter it into the SVG in any case. // if( cur_ctx.style.text_decoration.underline){ tsp.decoration = TXTDECOR_UNDER; } // else if (cur_ctx.style.text_decoration.line_through){ tsp.decoration = TXTDECOR_STRIKE1; } // else { tsp.decoration = TXTDECOR_NONE; } // // WMF textalignment is a bit strange: 0x6 is center, 0x2 is right, 0x0 is left, the value 0x4 is also drawn left // tsp.taln = ((cur_ctx.textAlign & U_TA_CENTER) == U_TA_CENTER) ? ALICENTER : // (((cur_ctx.textAlign & U_TA_CENTER) == U_TA_LEFT) ? ALILEFT : // ALIRIGHT); // tsp.taln |= ((cur_ctx.textAlign & U_TA_BASEBIT) ? ALIBASE : // ((cur_ctx.textAlign & U_TA_BOTTOM) ? ALIBOT : // ALITOP)); // tsp.ldir = (cur_ctx.textAlign & U_TA_RTLREADING ? LDIR_RL : LDIR_LR); // language direction // tsp.condensed = FC_WIDTH_NORMAL; // Not implemented well in libTERE (yet) // tsp.ori = cur_ctx.style.baseline_shift.value; // For now orientation is always the same as escapement // // There is no world transform, so ori need not be further rotated // tsp.string = (OdUInt8 *) U_strdup(escaped_text); // this will be free'd much later at a trinfo_clear(). // tsp.fs = cur_ctx.style.font_size.computed * 0.8; // Font size in points // (void) trinfo_load_fontname(d->tri, (OdUInt8 *)cur_ctx.font_name, &tsp); // // when font name includes narrow it may not be set to "condensed". Narrow fonts do not work well anyway though // // as the metrics from fontconfig may not match, or the font may not be present. // if(0<= TR_findcasesub(cur_ctx.font_name, (char *) "Narrow")){ tsp.co=1; } // else { tsp.co=0; } // int status; // status = trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ori is actually escapement // if(status==-1){ // change of escapement, emit what we have and reset // TR_layout_analyze(d->tri); // TR_layout_2_svg(d->tri); // ts << d->tri->out; // *(d->outsvg) += ts.str().c_str(); // d->tri = trinfo_clear(d->tri); // (void) trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ignore return status, it must work // } // g_free(escaped_text); // free(ansi_text); //} break; } case _META_SETDIBTODEV: //dbg_str << "\n"; break; case _META_SELECTPALETTE: //dbg_str << "\n"; break; case _META_REALIZEPALETTE: //dbg_str << "\n"; break; case _META_ANIMATEPALETTE: //dbg_str << "\n"; break; case _META_SETPALENTRIES: //dbg_str << "\n"; break; case _META_POLYPOLYGON: { //dbg_str << "\n"; OdUInt16 nPolys; const OdUInt16 *aPolyCounts; const char *Points; int cpts; // total number of points in Points nSize = getWmfPolyPolygon(contents, &nPolys, &aPolyCounts, &Points); int n, i, j; d->mask |= wmr_mask; //OdWmfPoint apt; //for (n=cpts=0; n < nPolys; n++) { cpts += aPolyCounts[n]; } //i = 0; // offset in BYTES //cpts *= U_SIZE_POINT16; // limit for offset i, in BYTES //for (n=0; n < nPolys && i\n"; break; case _META_DIBBITBLT: { //dbg_str << "\n"; nSize = getWmfDibBitBlt(contents, &Dst, &cwh, &Src, &dwRop3, &dib); // Treat all nonImage bitblts as a rectangular write. Definitely not correct, but at // least it leaves objects where the operations should have been. if (!dib) { if (!hasDrawCtx()) break; // should be an application of a DIBPATTERNBRUSHPT, use a solid color instead //int32_t dx = Dst.x; //int32_t dy = Dst.y; //int32_t dw = cwh.x; //int32_t dh = cwh.y; //SVGOStringStream tmp_rectangle; //tmp_rectangle << "\n\tM " << pix_to_xy( d, dx, dy ) << " "; //tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy ) << " "; //tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy + dh ) << " "; //tmp_rectangle << "\n\tL " << pix_to_xy( d, dx, dy + dh ) << " "; //tmp_rectangle << "\n\tz"; //d->mask |= wmr_mask; //d->dwRop3 = dwRop3; // we will try to approximate SOME of these //d->mask |= U_DRAW_CLOSED; // Bitblit is not really open or closed, but we need it to fill, and this is the flag for that //tmp_path << tmp_rectangle.str().c_str(); double dx = pix_to_x_point(d, Dst.x, Dst.y); double dy = pix_to_y_point(d, Dst.x, Dst.y); double dw = pix_to_abs_size(d, cwh.x); double dh = pix_to_abs_size(d, cwh.y); rectangle_brush(d, dx, dy, dw, dh); } else { double dx = pix_to_x_point( d, Dst.x, Dst.y); double dy = pix_to_y_point( d, Dst.x, Dst.y); double dw = pix_to_abs_size( d, cDst.x); double dh = pix_to_abs_size( d, cDst.y); //source position within the bitmap, in pixels int sx = Src.x; int sy = Src.y; int sw = 0; // extract all of the image int sh = 0; if(sx<0)sx=0; if(sy<0)sy=0; // usageSrc not defined, implicitly it must be U_DIB_RGB_COLORS common_dib_to_image(d,dib,dx,dy,dw,dh,sx,sy,sw,sh,_DIB_RGB_COLORS); } break; } case _META_DIBSTRETCHBLT: { //dbg_str << "\n"; nSize = getWmfDibStretchBlt(contents, &Dst, &cDst, &Src, &cSrc, &dwRop3, &dib); // Always grab image, ignore modes. if (dib) { double dx = pix_to_x_point( d, Dst.x, Dst.y); double dy = pix_to_y_point( d, Dst.x, Dst.y); double dw = pix_to_abs_size( d, cDst.x); double dh = pix_to_abs_size( d, cDst.y); //source position within the bitmap, in pixels int sx = Src.x; int sy = Src.y; int sw = cSrc.x; // extract the specified amount of the image int sh = cSrc.y; // usageSrc not defined, implicitly it must be U_DIB_RGB_COLORS common_dib_to_image(d,dib,dx,dy,dw,dh,sx,sy,sw,sh, _DIB_RGB_COLORS); } break; } case _META_DIBCREATEPATTERNBRUSH: { //dbg_str << "\n"; insert_object(d, _META_DIBCREATEPATTERNBRUSH, contents); break; } case _META_STRETCHDIB: { //dbg_str << "\n"; nSize = getWmfStretchDib(contents, &Dst, &cDst, &Src, &cSrc, &cUsage, &dwRop3, &dib); double dx = pix_to_x_point( d, Dst.x, Dst.y ); double dy = pix_to_y_point( d, Dst.x, Dst.y ); double dw = pix_to_abs_size( d, cDst.x); double dh = pix_to_abs_size( d, cDst.y); int sx = Src.x; //source position within the bitmap, in pixels int sy = Src.y; int sw = cSrc.x; // extract the specified amount of the image int sh = cSrc.y; OdUInt32 iUsageSrc; iUsageSrc = cUsage; common_dib_to_image(d,dib,dx,dy,dw,dh,sx,sy,sw,sh,iUsageSrc); break; } case _META_EXTFLOODFILL: //dbg_str << "\n"; break; case _META_DELETEOBJECT: { //dbg_str << "\n"; nSize = getWmfDeleteObject(contents, &utmp16); delete_object(d, utmp16); break; } case _META_CREATEPALETTE: { //dbg_str << "\n"; insert_object(d, _META_CREATEPALETTE, contents); break; } case _META_CREATEPATTERNBRUSH: { //dbg_str << "\n"; insert_object(d, _META_CREATEPATTERNBRUSH, contents); break; } case _META_CREATEPENINDIRECT: { //dbg_str << "\n"; insert_object(d, _META_CREATEPENINDIRECT, contents); break; } case _META_CREATEFONTINDIRECT: { //dbg_str << "\n"; insert_object(d, _META_CREATEFONTINDIRECT, contents); break; } case _META_CREATEBRUSHINDIRECT: { //dbg_str << "\n"; insert_object(d, _META_CREATEBRUSHINDIRECT, contents); break; } case _META_CREATEBITMAPINDIRECT: { //dbg_str << "\n"; insert_object(d, _META_CREATEBITMAPINDIRECT, contents); break; } case _META_CREATEBITMAP: { //dbg_str << "\n"; insert_object(d, _META_CREATEBITMAP, contents); break; } case _META_CREATEREGION: { //dbg_str << "\n"; insert_object(d, _META_CREATEREGION, contents); break; } //case _META_3A: //case _META_3B: //case _META_3C: //case _META_3D: //case _META_3E: //case _META_3F: //{ // //dbg_str << "\n"; // break; //} //case _META_44: //case _META_45: //case _META_46: //case _META_47: //{ // //dbg_str << "\n"; // break; //} //case _META_49: //case _META_4A: //case _META_4B: //case _META_4C: //case _META_4D: //case _META_4E: //case _META_4F: //case _META_50: //case _META_51: //case _META_52: //case _META_53: //case _META_54: //case _META_55: //case _META_56: //case _META_57: //case _META_58: //case _META_59: //case _META_5A: //case _META_5B: //case _META_5C: //case _META_5D: //case _META_5E: //case _META_5F: //case _META_60: //case _META_61: //case _META_62: //case _META_63: //case _META_64: //case _META_65: //case _META_66: //case _META_67: //case _META_68: //case _META_69: //case _META_6A: //case _META_6B: //case _META_6C: //case _META_6D: //case _META_6E: //case _META_6F: //case _META_70: //case _META_71: //case _META_72: //case _META_73: //case _META_74: //case _META_75: //case _META_76: //case _META_77: //case _META_78: //case _META_79: //case _META_7A: //case _META_7B: //case _META_7C: //case _META_7D: //case _META_7E: //case _META_7F: //case _META_80: //case _META_81: //case _META_82: //case _META_83: //case _META_84: //case _META_85: //case _META_86: //case _META_87: //case _META_88: //case _META_89: //case _META_8A: //case _META_8B: //case _META_8C: //case _META_8D: //case _META_8E: //case _META_8F: //case _META_90: //case _META_91: //case _META_92: //case _META_93: //case _META_94: //case _META_95: //case _META_96: //case _META_97: //case _META_98: //case _META_99: //case _META_9A: //case _META_9B: //case _META_9C: //case _META_9D: //case _META_9E: //case _META_9F: //case _META_A0: //case _META_A1: //case _META_A2: //case _META_A3: //case _META_A4: //case _META_A5: //case _META_A6: //case _META_A7: //case _META_A8: //case _META_A9: //case _META_AA: //case _META_AB: //case _META_AC: //case _META_AD: //case _META_AE: //case _META_AF: //case _META_B0: //case _META_B1: //case _META_B2: //case _META_B3: //case _META_B4: //case _META_B5: //case _META_B6: //case _META_B7: //case _META_B8: //case _META_B9: //case _META_BA: //case _META_BB: //case _META_BC: //case _META_BD: //case _META_BE: //case _META_BF: //case _META_C0: //case _META_C1: //case _META_C2: //case _META_C3: //case _META_C4: //case _META_C5: //case _META_C6: //case _META_C7: //case _META_C8: //case _META_C9: //case _META_CA: //case _META_CB: //case _META_CC: //case _META_CD: //case _META_CE: //case _META_CF: //case _META_D0: //case _META_D1: //case _META_D2: //case _META_D3: //case _META_D4: //case _META_D5: //case _META_D6: //case _META_D7: //case _META_D8: //case _META_D9: //case _META_DA: //case _META_DB: //case _META_DC: //case _META_DD: //case _META_DE: //case _META_DF: //case _META_E0: //case _META_E1: //case _META_E2: //case _META_E3: //case _META_E4: //case _META_E5: //case _META_E6: //case _META_E7: //case _META_E8: //case _META_E9: //case _META_EA: //case _META_EB: //case _META_EC: //case _META_ED: //case _META_EE: //case _META_EF: //{ // //dbg_str << "\n"; // break; //} //case _META_F1: //case _META_F2: //case _META_F3: //case _META_F4: //case _META_F5: //case _META_F6: //{ // //dbg_str << "\n"; // break; //} //case _META_F8: // //dbg_str << "\n"; // break; default: //dbg_str << "\n"; break; } //end of switch //// When testing, uncomment the following to place a comment for each processed WMR record in the SVG //// *(d->outsvg) += dbg_str.str().c_str(); // *(d->path) += tmp_path.str().c_str(); // if(!nSize){ OK=0; std::cout << "nSize == 0, oops!!!" << std::endl; } // There was some problem with this record, it is not safe to continue // } //end of while //// When testing, uncomment the following to show the final SVG derived from the WMF //// std::cout << *(d->outsvg) << std::endl; getWmfProperties((OdUInt32)_WMR_INVALID); // force the release of the lookup table memory, returned value is irrelevant // see here collected types of ODA_ASSERT_VAR(OdArray types;) return true; } //void Wmf::free_wmf_strings(WMF_STRINGS name){ // if(name.count){ // for(int i=0; i< name.count; i++){ free(name.strings[i]); } // free(name.strings); // } //} // //SPDocument * //Wmf::open(Inkscape::Extension::Input*, //mod, // const gchar *uri ) //{ // // WMF_CALLBACK_DATA d; // // memset(&d, 0, sizeof(WMF_CALLBACK_DATA)); // // for(int i = 0; i < WMF_MAX_DC+1; i++){ // be sure all values and pointers are empty to start with // memset(&(d.dc[i]),0,sizeof(WMF_DEVICE_CONTEXT)); // } // // set default drawing objects, these are active if no object has been selected // d.dc[0].active_pen = -1; // -1 when the default is used instead of a selected object // d.dc[0].active_brush = -1; // d.dc[0].active_font = -1; // // Default font, WMF spec says device can pick whatever it wants. WMF files that do not specify a font are unlikely to look very good! // d.dc[0].font_name = strdup("Arial"); // d.dc[0].style.font_size.computed = 16.0; // d.dc[0].style.font_weight.value = SP_CSS_FONT_WEIGHT_400; // d.dc[0].style.font_style.value = SP_CSS_FONT_STYLE_NORMAL; // d.dc[0].style.text_decoration.underline = 0; // d.dc[0].style.text_decoration.line_through = 0; // d.dc[0].style.baseline_shift.value = 0; // d.dc[0].textColor = ODRGB(0, 0, 0); // default foreground color (black) // d.dc[0].bkColor = ODRGB(255, 255, 255); // default background color (white) // d.dc[0].bkMode = U_TRANSPARENT; // d.dc[0].dirty = 0; // // Default pen, WMF files that do not specify a pen are unlikely to look very good! // d.dc[0].style.stroke_dasharray_set = 0; // d.dc[0].style.stroke_linecap.computed = 2; // U_PS_ENDCAP_SQUARE; // d.dc[0].style.stroke_linejoin.computed = 0; // U_PS_JOIN_MITER; // d.dc[0].stroke_set = true; // d.dc[0].style.stroke_width.value = 1.0; // will be reset to something reasonable once WMF draying size is known // d.dc[0].style.stroke.value.color.set( 0, 0, 0 ); // // Default brush = none, WMF files that do not specify a brush are unlikely to look very good! // d.dc[0].fill_set = false; // // if (uri == NULL) { // return NULL; // } // // d.outsvg = new Glib::ustring(""); // d.path = new Glib::ustring(""); // d.outdef = new Glib::ustring(""); // d.defs = new Glib::ustring(""); // d.mask = 0; // d.drawtype = 0; // d.arcdir = U_AD_COUNTERCLOCKWISE; // d.dwRop2 = U_R2_COPYPEN; // d.dwRop3 = 0; // d.E2IdirY = 1.0; // d.D2PscaleX = 1.0; // d.D2PscaleY = 1.0; // d.hatches.size = 0; // d.hatches.count = 0; // d.hatches.strings = NULL; // d.images.size = 0; // d.images.count = 0; // d.images.strings = NULL; // // // set up the size default for patterns in defs. This might not be referenced if there are no patterns defined in the drawing. // // *(d.defs) += "\n"; // *(d.defs) += " \n"; // *(d.defs) += " \n"; // // // size_t length; // char *contents; // if(wmf_readdata(uri, &contents, &length))return(NULL); // // // set up the text reassembly system // if(!(d.tri = trinfo_init(NULL)))return(NULL); // (void) trinfo_load_ft_opts(d.tri, 1, // FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP, // FT_KERNING_UNSCALED); // // (void) wmfMetaFileProc(contents,length, &d); // free(contents); // //// std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl; // // SPDocument *doc = SPDocument::createNewDocFromMem(d.outsvg->c_str(), strlen(d.outsvg->c_str()), TRUE); // // delete d.outsvg; // delete d.path; // delete d.outdef; // delete d.defs; // free_wmf_strings(d.hatches); // free_wmf_strings(d.images); // // if (d.wmf_obj) { // int i; // for (i=0; i\n" // "" N_("WMF Input") "\n" // "org.inkscape.input.wmf\n" // "\n" // ".wmf\n" // "image/x-wmf\n" // "" N_("Windows Metafiles (*.wmf)") "\n" // "" N_("Windows Metafiles") "\n" // "org.inkscape.output.wmf\n" // "\n" // "", new Wmf()); // // // WMF out // Inkscape::Extension::build_from_mem( // "\n" // "" N_("WMF Output") "\n" // "org.inkscape.output.wmf\n" // "true\n" // "true\n" // "true\n" // "true\n" // "false\n" // "false\n" // "false\n" // "false\n" // "false\n" // "\n" // ".wmf\n" // "image/x-wmf\n" // "" N_("Windows Metafile (*.wmf)") "\n" // "" N_("Windows Metafile") "\n" // "\n" // "", new Wmf()); // // return; //} //} } } // namespace Inkscape, Extension, Implementation /////////////////////////////////////////////////////////////////////////////// // // initially from emf-inout.h.example // class Emf : public OdMetafileParser // : public Metafile { public: Emf() {} virtual ~Emf() {} //bool check(Inkscape::Extension::Extension *module); //Can this module load (always yes for now) //void save(Inkscape::Extension::Output *mod, // Save the given document to the given filename // SPDocument *doc, // gchar const *filename); //virtual SPDocument *open( Inkscape::Extension::Input *mod, // const gchar *uri ); //static void init(void);//Initialize the class public: // removed static to use some of next with OdMetafileParser //void print_document_to_file(SPDocument *doc, const gchar *filename); double current_scale(PEMF_CALLBACK_DATA d); //std::string current_matrix(PEMF_CALLBACK_DATA d, double x, double y, int useoffset); //double current_rotation(PEMF_CALLBACK_DATA d); //void enlarge_hatches(PEMF_CALLBACK_DATA d); //int in_hatches(PEMF_CALLBACK_DATA d, char *test); //OdUInt32 add_hatch(PEMF_CALLBACK_DATA d, OdUInt32 hatchType, ODCOLORREF hatchColor); //void enlarge_images(PEMF_CALLBACK_DATA d); //int in_images(PEMF_CALLBACK_DATA d, const char *test); //OdUInt32 add_image(PEMF_CALLBACK_DATA d, void *pEmr, OdUInt32 cbBits, OdUInt32 cbBmi, // OdUInt32 iUsage, OdUInt32 offBits, OdUInt32 offBmi); //void enlarge_gradients(PEMF_CALLBACK_DATA d); //int in_gradients(PEMF_CALLBACK_DATA d, const char *test); //OdUInt32 add_gradient(PEMF_CALLBACK_DATA d, OdUInt32 gradientType, U_TRIVERTEX tv1, U_TRIVERTEX tv2); //void enlarge_clips(PEMF_CALLBACK_DATA d); //int in_clips(PEMF_CALLBACK_DATA d, const char *test); //void add_clips(PEMF_CALLBACK_DATA d, const char *clippath, unsigned int logic); //void output_style(PEMF_CALLBACK_DATA d, int iType); double _pix_x_to_point(PEMF_CALLBACK_DATA d, double px); double _pix_y_to_point(PEMF_CALLBACK_DATA d, double py); double pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py); double pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py); double pix_to_abs_size(PEMF_CALLBACK_DATA d, double px); //void snap_to_faraway_pair(double *x, double *y); //std::string pix_to_xy(PEMF_CALLBACK_DATA d, double x, double y); //void select_pen(PEMF_CALLBACK_DATA d, int index); //void select_extpen(PEMF_CALLBACK_DATA d, int index); //void select_brush(PEMF_CALLBACK_DATA d, int index); //void select_font(PEMF_CALLBACK_DATA d, int index); static void delete_object(PEMF_CALLBACK_DATA d, int index); static void insert_object(PEMF_CALLBACK_DATA d, int index, int type, OdEmfMetaRecord* pObj); //int AI_hack(OdEmfHeader* pEmr); //OdUInt32 *unknown_chars(size_t count); //void common_image_extraction(PEMF_CALLBACK_DATA d, void *pEmr, // double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh, // OdUInt32 iUsage, OdUInt32 offBits, OdUInt32 cbBits, OdUInt32 offBmi, OdUInt32 cbBmi); //void free_emf_strings(EMF_STRINGS name); int emfMetaFileProc(const char *contents, unsigned int length, PEMF_CALLBACK_DATA d); }; //} } } // namespace Inkscape, Extension, Implementation //#endif // EXTENSION_INTERNAL_EMF_H /////////////////////////////////////////////////////////////////////////////// // // initially from emf-inout.cpp.example // //#include "emf-inout.h" // //#define PRINT_EMF "org.inkscape.print.emf" // //#ifndef U_PS_JOIN_MASK //#define U_PS_JOIN_MASK (U_PS_JOIN_BEVEL|U_PS_JOIN_MITER|U_PS_JOIN_ROUND) //#endif // //namespace Inkscape { namespace Extension { namespace Internal { // //static OdUInt32 ICMmode = 0; // not used yet, but code to read it from EMF implemented //static OdUInt32 BLTmode = 0; //float faraway = 10000000; // used in "exclude" clips, hopefully well outside any real drawing! // //bool Emf::check(Inkscape::Extension::Extension*) //module //{ // if (NULL == Inkscape::Extension::db.get(PRINT_EMF)) // return FALSE; // return TRUE; //} // //void Emf::print_document_to_file(SPDocument *doc, const gchar *filename) //{ // Inkscape::Extension::Print *mod; // SPPrintContext context; // const gchar *oldconst; // gchar *oldoutput; // unsigned int ret; // // doc->ensureUpToDate(); // // mod = Inkscape::Extension::get_print(PRINT_EMF); // oldconst = mod->get_param_string("destination"); // oldoutput = g_strdup(oldconst); // mod->set_param_string("destination", filename); // // // Start // context.module = mod; // // fixme: This has to go into module constructor somehow // // Create new arena // mod->base = doc->getRoot(); // Inkscape::Drawing drawing; // mod->dkey = SPItem::display_key_new(1); // mod->root = mod->base->invoke_show(drawing, mod->dkey, SP_ITEM_SHOW_DISPLAY); // drawing.setRoot(mod->root); // // Print document // ret = mod->begin(doc); // if (ret) // { // g_free(oldoutput); // throw Inkscape::Extension::Output::save_failed(); // } // mod->base->invoke_print(&context); // mod->finish(); // // Release arena // mod->base->invoke_hide(mod->dkey); // mod->base = NULL; // mod->root = NULL; // deleted by invoke_hide // // end // // mod->set_param_string("destination", oldoutput); // g_free(oldoutput); //} // //void Emf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filename) //{ // Inkscape::Extension::Extension * ext; // // ext = Inkscape::Extension::db.get(PRINT_EMF); // if (ext == NULL) // return; // // bool new_val = mod->get_param_bool("textToPath"); // bool new_FixPPTCharPos = mod->get_param_bool("FixPPTCharPos"); // character position bug // // reserve FixPPT2 for opacity bug. Currently EMF does not export opacity values // bool new_FixPPTDashLine = mod->get_param_bool("FixPPTDashLine"); // dashed line bug // bool new_FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys"); // gradient bug // bool new_FixPPTLinGrad = mod->get_param_bool("FixPPTLinGrad"); // allow native rectangular linear gradient // bool new_FixPPTPatternAsHatch = mod->get_param_bool("FixPPTPatternAsHatch"); // force all patterns as standard EMF hatch // bool new_FixImageRot = mod->get_param_bool("FixImageRot"); // remove rotations on images // // TableGen( //possibly regenerate the unicode-convert tables // mod->get_param_bool("TnrToSymbol"), // mod->get_param_bool("TnrToWingdings"), // mod->get_param_bool("TnrToZapfDingbats"), // mod->get_param_bool("UsePUA") // ); // // ext->set_param_bool("FixPPTCharPos",new_FixPPTCharPos); // Remember to add any new ones to PrintEmf::init or a mysterious failure will result! // ext->set_param_bool("FixPPTDashLine",new_FixPPTDashLine); // ext->set_param_bool("FixPPTGrad2Polys",new_FixPPTGrad2Polys); // ext->set_param_bool("FixPPTLinGrad",new_FixPPTLinGrad); // ext->set_param_bool("FixPPTPatternAsHatch",new_FixPPTPatternAsHatch); // ext->set_param_bool("FixImageRot",new_FixImageRot); // ext->set_param_bool("textToPath", new_val); // // print_document_to_file(doc, filename); //} // given the transformation matrix from worldTransform return the scale in the matrix part. Assumes that the // matrix is not used to skew, invert, or make another distorting transformation. double Emf::current_scale(PEMF_CALLBACK_DATA d) { EMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; double scale = cur_ctx.worldTransform.eM11 * cur_ctx.worldTransform.eM22 - cur_ctx.worldTransform.eM12 * cur_ctx.worldTransform.eM21; if(scale <= 0.0)scale=1.0; // something is dreadfully wrong with the matrix, but do not crash over it scale=sqrt(scale); return scale; } // given the transformation matrix from worldTransform and the current x,y position in inkscape coordinates, // generate an SVG transform that gives the same amount of rotation, no scaling, and maps x,y back onto x,y. This is used for // rotating objects when the location of at least one point in that object is known. Returns: // "matrix(a,b,c,d,e,f)" (WITH the double quotes) // //std::string Emf::current_matrix(PEMF_CALLBACK_DATA d, double x, double y, int useoffset) //{ // EMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; // SVGOStringStream cxform; // double scale = current_scale(d); // cxform << "\"matrix("; // cxform << cur_ctx.worldTransform.eM11/scale; cxform << ","; // cxform << cur_ctx.worldTransform.eM12/scale; cxform << ","; // cxform << cur_ctx.worldTransform.eM21/scale; cxform << ","; // cxform << cur_ctx.worldTransform.eM22/scale; cxform << ","; // if(useoffset) // { // // for the "new" coordinates drop the worldtransform translations, not used here // double newx = x * cur_ctx.worldTransform.eM11/scale + y * cur_ctx.worldTransform.eM21/scale; // double newy = x * cur_ctx.worldTransform.eM12/scale + y * cur_ctx.worldTransform.eM22/scale; // cxform << x - newx; cxform << ","; // cxform << y - newy; // } // else { // cxform << "0,0"; // } // cxform << ")\""; // return(cxform.str()); //} // // given the transformation matrix from worldTransform return the rotation angle in radians. // counter clocwise from the x axis. //double Emf::current_rotation(PEMF_CALLBACK_DATA d) //{ // EMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; // return -std::atan2(cur_ctx.worldTransform.eM12, cur_ctx.worldTransform.eM11); //} // // Add another 100 blank slots to the hatches array. //void Emf::enlarge_hatches(PEMF_CALLBACK_DATA d) //{ // d->hatches.size += 100; // d->hatches.strings = (char **) realloc(d->hatches.strings,d->hatches.size * sizeof(char *)); //} // // See if the pattern name is already in the list. If it is return its position (1->n, not 1-n-1) //int Emf::in_hatches(PEMF_CALLBACK_DATA d, char *test) //{ // int i; // for(i=0; ihatches.count; i++){ // if(strcmp(test,d->hatches.strings[i])==0)return(i+1); // } // return(0); //} // // (Conditionally) add a hatch. If a matching hatch already exists nothing happens. If one // does not exist it is added to the hatches list and also entered into . // This is also used to add the path part of the hatches, which they reference with a xlink:href //OdUInt32 Emf::add_hatch(PEMF_CALLBACK_DATA d, OdUInt32 hatchType, ODCOLORREF hatchColor) //{ // EMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; // char hatchname[64]; // big enough // char hpathname[64]; // big enough // char hbkname[64]; // big enough // char tmpcolor[8]; // char bkcolor[8]; // OdUInt32 idx; // // switch(hatchType){ // case U_HS_SOLIDTEXTCLR: // case U_HS_DITHEREDTEXTCLR: // sprintf(tmpcolor,"%6.6X",sethexcolor(cur_ctx.textColor)); // break; // case U_HS_SOLIDBKCLR: // case U_HS_DITHEREDBKCLR: // sprintf(tmpcolor,"%6.6X",sethexcolor(cur_ctx.bkColor)); // break; // default: // sprintf(tmpcolor,"%6.6X",sethexcolor(hatchColor)); // break; // } // // // For both bkMode types set the PATH + FOREGROUND COLOR for the indicated standard hatch. // // This will be used late to compose, or recompose the transparent or opaque final hatch. // // std::string refpath; // used to reference later the path pieces which are about to be created // sprintf(hpathname,"EMFhpath%d_%s",hatchType,tmpcolor); // idx = in_hatches(d,hpathname); // if(!idx) // { // // add path/color if not already present // if(d->hatches.count == d->hatches.size) // { enlarge_hatches(d); } // d->hatches.strings[d->hatches.count++]=strdup(hpathname); // // d->defs += "\n"; // switch(hatchType) // { // case U_HS_HORIZONTAL: // d->defs += " defs += hpathname; // d->defs += "\" d=\"M 0 0 6 0\" style=\"fill:none;stroke:#"; // d->defs += tmpcolor; // d->defs += "\" />\n"; // break; // case U_HS_VERTICAL: // d->defs += " defs += hpathname; // d->defs += "\" d=\"M 0 0 0 6\" style=\"fill:none;stroke:#"; // d->defs += tmpcolor; // d->defs += "\" />\n"; // break; // case U_HS_FDIAGONAL: // d->defs += " defs += hpathname; // d->defs += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#"; // d->defs += tmpcolor; // d->defs += "\"/>\n"; // break; // case U_HS_BDIAGONAL: // d->defs += " defs += hpathname; // d->defs += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#"; // d->defs += tmpcolor; // d->defs += "\"/>\n"; // break; // case U_HS_CROSS: // d->defs += " defs += hpathname; // d->defs += "\" d=\"M 0 0 6 0 M 0 0 0 6\" style=\"fill:none;stroke:#"; // d->defs += tmpcolor; // d->defs += "\" />\n"; // break; // case U_HS_DIAGCROSS: // d->defs += " defs += hpathname; // d->defs += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#"; // d->defs += tmpcolor; // d->defs += "\"/>\n"; // d->defs += " defs += hpathname; // d->defs += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#"; // d->defs += tmpcolor; // d->defs += "\"/>\n"; // break; // case U_HS_SOLIDCLR: // case U_HS_DITHEREDCLR: // case U_HS_SOLIDTEXTCLR: // case U_HS_DITHEREDTEXTCLR: // case U_HS_SOLIDBKCLR: // case U_HS_DITHEREDBKCLR: // default: // d->defs += " defs += hpathname; // d->defs += "\" d=\"M 0 0 6 0 6 6 0 6 z\" style=\"fill:#"; // d->defs += tmpcolor; // d->defs += ";stroke:none"; // d->defs += "\" />\n"; // break; // } // } // // // References to paths possibly just created above. These will be used in the actual patterns. // switch(hatchType) // { // case U_HS_HORIZONTAL: // case U_HS_VERTICAL: // case U_HS_CROSS: // case U_HS_SOLIDCLR: // case U_HS_DITHEREDCLR: // case U_HS_SOLIDTEXTCLR: // case U_HS_DITHEREDTEXTCLR: // case U_HS_SOLIDBKCLR: // case U_HS_DITHEREDBKCLR: // default: // refpath += " \n"; // break; // case U_HS_FDIAGONAL: // case U_HS_BDIAGONAL: // refpath += " \n"; // refpath += " \n"; // refpath += " \n"; // break; // case U_HS_DIAGCROSS: // refpath += " \n"; // refpath += " \n"; // refpath += " \n"; // refpath += " \n"; // refpath += " \n"; // refpath += " \n"; // break; // } // // if(cur_ctx.bkMode == U_TRANSPARENT || hatchType >= U_HS_SOLIDCLR) // { // sprintf(hatchname,"EMFhatch%d_%s",hatchType,tmpcolor); // sprintf(hpathname,"EMFhpath%d_%s",hatchType,tmpcolor); // idx = in_hatches(d,hatchname); // if(!idx) // { // // add it if not already present // if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); } // d->hatches.strings[d->hatches.count++]=strdup(hatchname); // d->defs += "\n"; // d->defs += " defs += hatchname; // d->defs += "\" xlink:href=\"#EMFhbasepattern\">\n"; // d->defs += refpath; // d->defs += " \n"; // idx = d->hatches.count; // } // } // else // { // bkMode==U_OPAQUE // // Set up an object in the defs for this background, if there is not one already there // sprintf(bkcolor,"%6.6X",sethexcolor(cur_ctx.bkColor)); // sprintf(hbkname,"EMFhbkclr_%s",bkcolor); // idx = in_hatches(d,hbkname); // if(!idx){ // add path/color if not already present. Hatchtype is not needed in the name. // if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); } // d->hatches.strings[d->hatches.count++]=strdup(hbkname); // // d->defs += "\n"; // d->defs += " defs += hbkname; // d->defs += "\" x=\"0\" y=\"0\" width=\"6\" height=\"6\" fill=\"#"; // d->defs += bkcolor; // d->defs += "\" />\n"; // } // // // this is the pattern, its name will show up in Inkscape's pattern selector // sprintf(hatchname,"EMFhatch%d_%s_%s",hatchType,tmpcolor,bkcolor); // idx = in_hatches(d,hatchname); // if(!idx) // { // add it if not already present // if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); } // d->hatches.strings[d->hatches.count++]=strdup(hatchname); // d->defs += "\n"; // d->defs += " defs += hatchname; // d->defs += "\" xlink:href=\"#EMFhbasepattern\">\n"; // d->defs += " defs += hbkname; // d->defs += "\" />\n"; // d->defs += refpath; // d->defs += " \n"; // idx = d->hatches.count; // } // } // return(idx-1); //} // // Add another 100 blank slots to the images array. //void Emf::enlarge_images(PEMF_CALLBACK_DATA d) //{ // d->images.size += 100; // d->images.strings = (char **) realloc(d->images.strings,d->images.size * sizeof(char *)); //} // // See if the image string is already in the list. If it is return its position (1->n, not 1-n-1) //int Emf::in_images(PEMF_CALLBACK_DATA d, const char *test) //{ // int i; // for(i=0; iimages.count; i++){ // if(strcmp(test,d->images.strings[i])==0)return(i+1); // } // return(0); //} // // (Conditionally) add an image. If a matching image already exists nothing happens. If one // does not exist it is added to the images list and also entered into . // // U_EMRCREATEMONOBRUSH records only work when the bitmap is monochrome. If we hit one that isn't // set idx to 2^32-1 and let the caller handle it. //OdUInt32 Emf::add_image(PEMF_CALLBACK_DATA d, void *pEmr, OdUInt32 cbBits, OdUInt32 cbBmi, // OdUInt32 iUsage, OdUInt32 offBits, OdUInt32 offBmi) //{ // OdUInt32 idx; // char imagename[64]; // big enough // char imrotname[64]; // big enough // char xywh[64]; // big enough // int dibparams = _BI_UNKNOWN; // type of image not yet determined // // MEMPNG mempng; // PNG in memory comes back in this // mempng.buffer = NULL; // // char *rgba_px = NULL; // RGBA pixels // const char *px = NULL; // DIB pixels // const OdWmfQuad *ct = NULL; // DIB color table // OdWmfQuad ct2[2]; // OdUInt32 width, height, colortype, numCt, invert; // if needed these values will be set in get_DIB_params // if(cbBits && cbBmi && (iUsage == U_DIB_RGB_COLORS)) // { // // next call returns pointers and values, but allocates no memory // dibparams = get_DIB_params((const char *)pEmr, offBits, offBmi, &px, (const OdWmfQuad **) &ct, // &numCt, &width, &height, &colortype, &invert); // if(dibparams == _BI_RGB) // { // // U_EMRCREATEMONOBRUSH uses text/bk colors instead of what is in the color map. // if(((PU_EMR)pEmr)->iType == _EMR_CREATEMONOBRUSH){ // if(numCt==2) // { // ct2[0] = U_RGB2BGR(cur_ctx.textColor); // ct2[1] = U_RGB2BGR(cur_ctx.bkColor); // ct = &ct2[0]; // } // else // { // // This record is invalid, nothing more to do here, let caller handle it // return(_EMR_INVALID); // } // } // // if(!DIB_to_RGBA( // px, // DIB pixel array // 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 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 // )) // { // toPNG( // Get the image from the RGBA px into mempng // &mempng, // width, height, // of the SRC bitmap // rgba_px // ); // free(rgba_px); // } // } // } // // gchar *base64String=NULL; // if(dibparams == U_BI_JPEG || dibparams==U_BI_PNG) // { // // image was binary png or jpg in source file // base64String = g_base64_encode((guchar*) px, numCt ); // } // else if(mempng.buffer) // { // // image was DIB in source file, converted to png in this routine // base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size ); // free(mempng.buffer); // } // else // { // // unknown or unsupported image type or failed conversion, insert the common bad image picture // width = 3; // height = 4; // base64String = bad_image_png(); // } // // idx = in_images(d, (char *) base64String); // if(!idx) // { // // add it if not already present - we looked at the actual data for comparison // if(d->images.count == d->images.size){ enlarge_images(d); } // idx = d->images.count; // d->images.strings[d->images.count++]=strdup(base64String); // // sprintf(imagename,"EMFimage%d",idx++); // sprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer // // d->defs += "\n"; // d->defs += " defs += imagename; // d->defs += "\"\n "; // d->defs += xywh; // d->defs += "\n"; // if(dibparams == U_BI_JPEG) // { // d->defs += " xlink:href=\"data:image/jpeg;base64,"; // } // else // { // d->defs += " xlink:href=\"data:image/png;base64,"; // } // d->defs += base64String; // d->defs += "\"\n"; // d->defs += " preserveAspectRatio=\"none\"\n"; // d->defs += " />\n"; // // d->defs += "\n"; // d->defs += " defs += imagename; // d->defs += "_ref\"\n "; // d->defs += xywh; // d->defs += "\n patternUnits=\"userSpaceOnUse\""; // d->defs += " >\n"; // d->defs += " defs += imagename; // d->defs += "_ign\" "; // d->defs += " xlink:href=\"#"; // d->defs += imagename; // d->defs += "\" />\n"; // d->defs += " "; // d->defs += " \n"; // } // g_free(base64String);//wait until this point to free because it might be a duplicate image // // // image allows the inner image to be rotated nicely, load this one second only if needed // // imagename retained from above // // Here comes a dreadful hack. How do we determine if this rotation of the base image has already // // been loaded? The image names contain no identifying information, they are just numbered sequentially. // // So the rotated name is EMFrotimage###_XXXXXX, where ### is the number of the referred to image, and // // XXXX is the rotation in radians x 1000000 and truncated. That is then stored in BASE64 as the "image". // // The corresponding SVG generated though is not for an image, but a reference to an image. // // The name of the pattern MUST stil be EMFimage###_ref or output_style() will not be able to use it. // if (current_rotation(d) >= 0.00001 || current_rotation(d) <= -0.00001) // some rotation, allow a little rounding error around 0 degrees // { // int tangle = round(current_rotation(d)*1000000.0); // sprintf(imrotname,"EMFrotimage%d_%d",idx-1,tangle); // base64String = g_base64_encode((guchar*) imrotname, strlen(imrotname) ); // idx = in_images(d, (char *) base64String); // scan for this "image" // if(!idx) // { // if(d->images.count == d->images.size) // { enlarge_images(d); } // idx = d->images.count; // d->images.strings[d->images.count++]=strdup(base64String); // sprintf(imrotname,"EMFimage%d",idx++); // // d->defs += "\n"; // d->defs += " defs += " id=\""; // d->defs += imrotname; // d->defs += "_ref\"\n"; // d->defs += " xlink:href=\"#"; // d->defs += imagename; // d->defs += "_ref\"\n"; // d->defs += " patternTransform="; // d->defs += current_matrix(d, 0.0, 0.0, 0); //j use offset 0,0 // d->defs += " />\n"; // } // g_free(base64String); // } // // return(idx-1); //} // // Add another 100 blank slots to the gradients array. //void Emf::enlarge_gradients(PEMF_CALLBACK_DATA d) //{ // d->gradients.size += 100; // d->gradients.strings = (char **) realloc(d->gradients.strings,d->gradients.size * sizeof(char *)); //} // // See if the gradient name is already in the list. If it is return its position (1->n, not 1-n-1) //int Emf::in_gradients(PEMF_CALLBACK_DATA d, const char *test) //{ // int i; // for(i=0; igradients.count; i++){ // if(strcmp(test,d->gradients.strings[i])==0)return(i+1); // } // return(0); //} // //ODCOLORREF trivertex_to_colorref(U_TRIVERTEX tv) //{ // ODCOLORREF uc; // uc.Red = tv.Red >> 8; // uc.Green = tv.Green >> 8; // uc.Blue = tv.Blue >> 8; // uc.Reserved = tv.Alpha >> 8; // Not used // return(uc); //} // // (Conditionally) add a gradient. If a matching gradient already exists nothing happens. If one // does not exist it is added to the gradients list and also entered into . // Only call this with H or V gradient, not a triangle. //OdUInt32 Emf::add_gradient(PEMF_CALLBACK_DATA d, OdUInt32 gradientType, U_TRIVERTEX tv1, U_TRIVERTEX tv2) //{ // char hgradname[64]; // big enough // char tmpcolor1[8]; // char tmpcolor2[8]; // char gradc; // OdUInt32 idx; // std::string x2,y2; // // ODCOLORREF gradientColor1 = trivertex_to_colorref(tv1); // ODCOLORREF gradientColor2 = trivertex_to_colorref(tv2); // // // sprintf(tmpcolor1,"%6.6X",sethexcolor(gradientColor1)); // sprintf(tmpcolor2,"%6.6X",sethexcolor(gradientColor2)); // switch(gradientType) // { // case U_GRADIENT_FILL_RECT_H: // gradc='H'; // x2="100"; // y2="0"; // break; // case U_GRADIENT_FILL_RECT_V: // gradc='V'; // x2="0"; // y2="100"; // break; // default: // this should never happen, but fill these in to avoid compiler warnings // gradc='!'; // x2="0"; // y2="0"; // break; // } // // // Even though the gradient was defined as Horizontal or Vertical if the rectangle is rotated it needs to // // be at some other alignment, and that needs gradienttransform. Set the name using the same sort of hack // // as for add_image. // int tangle = round(current_rotation(d)*1000000.0); // sprintf(hgradname,"LinGrd%c_%s_%s_%d",gradc,tmpcolor1,tmpcolor2,tangle); // // idx = in_gradients(d,hgradname); // if(!idx) // gradient does not yet exist // { // if(d->gradients.count == d->gradients.size) // { // enlarge_gradients(d); // } // d->gradients.strings[d->gradients.count++]=strdup(hgradname); // idx = d->gradients.count; // SVGOStringStream stmp; // stmp << " \n"; // stmp << " \n"; // stmp << " \n"; // stmp << " \n"; // d->defs += stmp.str().c_str(); // } // // return(idx-1); //} // // Add another 100 blank slots to the clips array. //void Emf::enlarge_clips(PEMF_CALLBACK_DATA d) //{ // d->clips.size += 100; // d->clips.strings = (char **) realloc(d->clips.strings,d->clips.size * sizeof(char *)); //} // // See if the pattern name is already in the list. If it is return its position (1->n, not 1-n-1) //int Emf::in_clips(PEMF_CALLBACK_DATA d, const char *test) //{ // int i; // for(i=0; iclips.count; i++) // { // if(strcmp(test,d->clips.strings[i])==0)return(i+1); // } // return(0); //} // // (Conditionally) add a clip. // If a matching clip already exists nothing happens // If one does exist it is added to the clips list, entered into . // //void Emf::add_clips(PEMF_CALLBACK_DATA d, const char *clippath, unsigned int logic) //{ // int op = combine_ops_to_livarot(logic); // Geom::PathVector combined_vect; // char *combined = NULL; // if (op >= 0 && cur_ctx.clip_id) // { // unsigned int real_idx = cur_ctx.clip_id - 1; // Geom::PathVector old_vect = sp_svg_read_pathv(d->clips.strings[real_idx]); // Geom::PathVector new_vect = sp_svg_read_pathv(clippath); // combined_vect = sp_pathvector_boolop(new_vect, old_vect, (bool_op) op , (FillRule) fill_oddEven, (FillRule) fill_oddEven); // combined = sp_svg_write_path(combined_vect); // } // else // { // combined = strdup(clippath); // COPY operation, erases everything and starts a new one // } // // OdUInt32 idx = in_clips(d, combined); // if(!idx) // { // // add clip if not already present // if(d->clips.count == d->clips.size) // { enlarge_clips(d); } // d->clips.strings[d->clips.count++]=strdup(combined); // cur_ctx.clip_id = d->clips.count; // one more than the slot where it is actually stored // SVGOStringStream tmp_clippath; // tmp_clippath << "\n"; // tmp_clippath << "\n\t"; // tmp_clippath << "\n"; // d->outdef += tmp_clippath.str().c_str(); // } // else // { // cur_ctx.clip_id = idx; // } // free(combined); //} // //void Emf::output_style(PEMF_CALLBACK_DATA d, int iType) //{ // EMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; // // SVGOStringStream tmp_id; // SVGOStringStream tmp_style; // char tmp[1024] = {0}; // // float fill_rgb[3]; // sp_color_get_rgb_floatv( &(cur_ctx.style.fill_color), fill_rgb ); // float stroke_rgb[3]; // sp_color_get_rgb_floatv(&(cur_ctx.style.stroke.value.color), stroke_rgb); // // // for _EMR_BITBLT with no image, try to approximate some of these operations/ // // Assume src color is "white" // if(d->dwRop3) // { // switch(d->dwRop3){ // case U_PATINVERT: // invert pattern // fill_rgb[0] = 1.0 - fill_rgb[0]; // fill_rgb[1] = 1.0 - fill_rgb[1]; // fill_rgb[2] = 1.0 - fill_rgb[2]; // break; // case U_SRCINVERT: // treat all of these as black // case U_DSTINVERT: // case U_BLACKNESS: // case U_SRCERASE: // case U_NOTSRCCOPY: // fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=0.0; // break; // case U_SRCCOPY: // treat all of these as white // case U_NOTSRCERASE: // case U_WHITENESS: // fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=1.0; // break; // case U_SRCPAINT: // use the existing color // case U_SRCAND: // case U_MERGECOPY: // case U_MERGEPAINT: // case U_PATPAINT: // case U_PATCOPY: // default: // break; // } // d->dwRop3 = 0; // might as well reset it here, it must be set for each BITBLT // } // // // Implement some of these, the ones where the original screen color does not matter. // // The options that merge screen and pen colors cannot be done correctly because we // // have no way of knowing what color is already on the screen. For those just pass the // // pen color through. // switch(d->dwRop2) // { // case U_R2_BLACK: // fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 0.0; // stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 0.0; // break; // case U_R2_NOTMERGEPEN: // case U_R2_MASKNOTPEN: // break; // case U_R2_NOTCOPYPEN: // fill_rgb[0] = 1.0 - fill_rgb[0]; // fill_rgb[1] = 1.0 - fill_rgb[1]; // fill_rgb[2] = 1.0 - fill_rgb[2]; // stroke_rgb[0] = 1.0 - stroke_rgb[0]; // stroke_rgb[1] = 1.0 - stroke_rgb[1]; // stroke_rgb[2] = 1.0 - stroke_rgb[2]; // break; // case U_R2_MASKPENNOT: // case U_R2_NOT: // case U_R2_XORPEN: // case U_R2_NOTMASKPEN: // case U_R2_NOTXORPEN: // case U_R2_NOP: // case U_R2_MERGENOTPEN: // case U_R2_COPYPEN: // case U_R2_MASKPEN: // case U_R2_MERGEPENNOT: // case U_R2_MERGEPEN: // break; // case U_R2_WHITE: // fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 1.0; // stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 1.0; // break; // default: // break; // } // // // tmp_id << "\n\tid=\"" << (d->id++) << "\""; // // d->outsvg += tmp_id.str().c_str(); // d->outsvg += "\n\tstyle=\""; // if (iType == _EMR_STROKEPATH || !cur_ctx.fill_set) // { // tmp_style << "fill:none;"; // } // else // { // switch(cur_ctx.fill_mode) // { // // both of these use the url(#) method // case DRAW_PATTERN: // snprintf(tmp, 1023, "fill:url(#%s); ",d->hatches.strings[cur_ctx.fill_idx]); // tmp_style << tmp; // break; // case DRAW_IMAGE: // snprintf(tmp, 1023, "fill:url(#EMFimage%d_ref); ",cur_ctx.fill_idx); // tmp_style << tmp; // break; // case DRAW_LINEAR_GRADIENT: // case DRAW_PAINT: // default: // <-- this should never happen, but just in case... // snprintf( // tmp, 1023, // "fill:#%02x%02x%02x;", // SP_COLOR_F_TO_U(fill_rgb[0]), // SP_COLOR_F_TO_U(fill_rgb[1]), // SP_COLOR_F_TO_U(fill_rgb[2]) // ); // tmp_style << tmp; // break; // } // snprintf( // tmp, 1023, // "fill-rule:%s;", // (cur_ctx.style.fill_rule.value == 0 ? "evenodd" : "nonzero") // ); // tmp_style << tmp; // tmp_style << "fill-opacity:1;"; // // // if the stroke is the same as the fill, and the right size not to change the end size of the object, do not do it separately // if( // (cur_ctx.fill_set ) && // (cur_ctx.stroke_set ) && // (cur_ctx.style.stroke_width.value == 1 ) && // (cur_ctx.fill_mode == cur_ctx.stroke_mode) && // ( // (cur_ctx.fill_mode != DRAW_PAINT) || // ( // (fill_rgb[0]==stroke_rgb[0]) && // (fill_rgb[1]==stroke_rgb[1]) && // (fill_rgb[2]==stroke_rgb[2]) // ) // ) // ) // { // cur_ctx.stroke_set = false; // } // } // // if (iType == _EMR_FILLPATH || !cur_ctx.stroke_set) // { // tmp_style << "stroke:none;"; // } // else // { // switch(cur_ctx.stroke_mode) // { // // both of these use the url(#) method // case DRAW_PATTERN: // snprintf(tmp, 1023, "stroke:url(#%s); ",d->hatches.strings[cur_ctx.stroke_idx]); // tmp_style << tmp; // break; // case DRAW_IMAGE: // snprintf(tmp, 1023, "stroke:url(#EMFimage%d_ref); ",cur_ctx.stroke_idx); // tmp_style << tmp; // break; // case DRAW_LINEAR_GRADIENT: // case DRAW_PAINT: // default: // <-- this should never happen, but just in case... // snprintf( // tmp, 1023, // "stroke:#%02x%02x%02x;", // SP_COLOR_F_TO_U(stroke_rgb[0]), // SP_COLOR_F_TO_U(stroke_rgb[1]), // SP_COLOR_F_TO_U(stroke_rgb[2]) // ); // tmp_style << tmp; // break; // } // tmp_style << "stroke-width:" << // MAX( 0.001, cur_ctx.style.stroke_width.value ) << "px;"; // // tmp_style << "stroke-linecap:" << // ( // cur_ctx.style.stroke_linecap.computed == 0 ? "butt" : // cur_ctx.style.stroke_linecap.computed == 1 ? "round" : // cur_ctx.style.stroke_linecap.computed == 2 ? "square" : // "unknown" // ) << ";"; // // tmp_style << "stroke-linejoin:" << // ( // cur_ctx.style.stroke_linejoin.computed == 0 ? "miter" : // cur_ctx.style.stroke_linejoin.computed == 1 ? "round" : // cur_ctx.style.stroke_linejoin.computed == 2 ? "bevel" : // "unknown" // ) << ";"; // // // Set miter limit if known, even if it is not needed immediately (not miter) // tmp_style << "stroke-miterlimit:" << // MAX( 2.0, cur_ctx.style.stroke_miterlimit.value ) << ";"; // // if (cur_ctx.style.stroke_dasharray.set && // !cur_ctx.style.stroke_dasharray.values.empty() ) // { // tmp_style << "stroke-dasharray:"; // for (unsigned i=0; ioutsvg += tmp_style.str().c_str(); //} double Emf::_pix_x_to_point(PEMF_CALLBACK_DATA d, double px) { EMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; double scale = (cur_ctx.ScaleInX ? cur_ctx.ScaleInX : 1.0); double tmp; tmp = ((((double) (px - cur_ctx.winorg.x))*scale) + cur_ctx.vieworg.x) * d->D2PscaleX; tmp -= d->ulCornerOutX; //The EMF boundary rectangle can be anywhere, place its upper left corner in the Inkscape upper left corner return(tmp); } double Emf::_pix_y_to_point(PEMF_CALLBACK_DATA d, double py) { EMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; double scale = (cur_ctx.ScaleInY ? cur_ctx.ScaleInY : 1.0); double tmp; tmp = ((((double) (py - cur_ctx.winorg.y))*scale) * d->E2IdirY + cur_ctx.vieworg.y) * d->D2PscaleY; tmp -= d->ulCornerOutY; //The EMF boundary rectangle can be anywhere, place its upper left corner in the Inkscape upper left corner return(tmp); } double Emf::pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py) { EMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; double wpx = px * cur_ctx.worldTransform.eM11 + py * cur_ctx.worldTransform.eM21 + cur_ctx.worldTransform.eDx; double x = _pix_x_to_point(d, wpx); return x; } double Emf::pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py) { EMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; double wpy = px * cur_ctx.worldTransform.eM12 + py * cur_ctx.worldTransform.eM22 + cur_ctx.worldTransform.eDy; double y = _pix_y_to_point(d, wpy); return y; } double Emf::pix_to_abs_size(PEMF_CALLBACK_DATA d, double px) { EMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; double ppx = fabs(px * (cur_ctx.ScaleInX ? cur_ctx.ScaleInX : 1.0) * d->D2PscaleX * current_scale(d)); return ppx; } // snaps coordinate pairs made up of values near +/-faraway, +/-faraway to exactly faraway. // This eliminates coordinate drift on repeated clipping cycles which use exclude. // It should not affect internals of normal drawings because the value of faraway is so large. //void Emf::snap_to_faraway_pair(double *x, double *y) //{ // if((abs(abs(*x) - faraway)/faraway <= 1e-4) && (abs(abs(*y) - faraway)/faraway <= 1e-4)) // { // *x = (*x > 0 ? faraway : -faraway); // *y = (*y > 0 ? faraway : -faraway); // } //} // // returns "x,y" (without the quotes) in inkscape coordinates for a pair of EMF x,y coordinates. // Since exclude clip can go through here, it calls snap_to_faraway_pair for numerical stability. // //std::string Emf::pix_to_xy(PEMF_CALLBACK_DATA d, double x, double y) //{ // SVGOStringStream cxform; // double tx = pix_to_x_point(d,x,y); // double ty = pix_to_y_point(d,x,y); // snap_to_faraway_pair(&tx,&ty); // cxform << tx; // cxform << ","; // cxform << ty; // return(cxform.str()); //} // //void Emf::select_pen(PEMF_CALLBACK_DATA d, int index) //{ // PU_EMRCREATEPEN pEmr = NULL; // // if (index >= 0 && index < d->n_obj) // { // pEmr = (PU_EMRCREATEPEN) d->emf_obj[index].lpEMFR; // } // // if (!pEmr) // return; // EMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; // // switch (pEmr->lopn.lopnStyle & U_PS_STYLE_MASK) // { // case U_PS_DASH: // case U_PS_DOT: // case U_PS_DASHDOT: // case U_PS_DASHDOTDOT: // { // int penstyle = (pEmr->lopn.lopnStyle & U_PS_STYLE_MASK); // if (!cur_ctx.style.stroke_dasharray.values.empty() && (d->level==0 || (d->level>0 && cur_ctx.style.stroke_dasharray.values!=d->dc[d->level-1].style.stroke_dasharray.values))) // cur_ctx.style.stroke_dasharray.values.clear(); // if (penstyle==U_PS_DASH || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) // { // cur_ctx.style.stroke_dasharray.values.push_back( 3 ); // cur_ctx.style.stroke_dasharray.values.push_back( 1 ); // } // if (penstyle==U_PS_DOT || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) // { // cur_ctx.style.stroke_dasharray.values.push_back( 1 ); // cur_ctx.style.stroke_dasharray.values.push_back( 1 ); // } // if (penstyle==U_PS_DASHDOTDOT) // { // cur_ctx.style.stroke_dasharray.values.push_back( 1 ); // cur_ctx.style.stroke_dasharray.values.push_back( 1 ); // } // // cur_ctx.style.stroke_dasharray.set = 1; // break; // } // case U_PS_SOLID: // default: // cur_ctx.style.stroke_dasharray.set = 0; // break; // } // // switch (pEmr->lopn.lopnStyle & U_PS_ENDCAP_MASK) // { // case U_PS_ENDCAP_ROUND: { cur_ctx.style.stroke_linecap.computed = 1; break; } // case U_PS_ENDCAP_SQUARE: { cur_ctx.style.stroke_linecap.computed = 2; break; } // case U_PS_ENDCAP_FLAT: // default: // cur_ctx.style.stroke_linecap.computed = 0; // break; // } // // switch (pEmr->lopn.lopnStyle & U_PS_JOIN_MASK) // { // case U_PS_JOIN_BEVEL: // cur_ctx.style.stroke_linejoin.computed = 2; // break; // case U_PS_JOIN_MITER: // cur_ctx.style.stroke_linejoin.computed = 0; // break; // case U_PS_JOIN_ROUND: // default: // cur_ctx.style.stroke_linejoin.computed = 1; // break; // } // // cur_ctx.stroke_set = true; // // if (pEmr->lopn.lopnStyle == U_PS_NULL) // { // cur_ctx.style.stroke_width.value = 0; // cur_ctx.stroke_set = false; // } // else if (pEmr->lopn.lopnWidth.x) // { // int cur_level = d->level; // d->level = d->emf_obj[index].level; // double pen_width = pix_to_abs_size( d, pEmr->lopn.lopnWidth.x ); // d->level = cur_level; // cur_ctx.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?) // //cur_ctx.style.stroke_width.value = 1.0; // int cur_level = d->level; // d->level = d->emf_obj[index].level; // double pen_width = pix_to_abs_size( d, 1 ); // d->level = cur_level; // cur_ctx.style.stroke_width.value = pen_width; // } // // double r, g, b; // r = SP_COLOR_U_TO_F( U_RGBAGetR(pEmr->lopn.lopnColor) ); // g = SP_COLOR_U_TO_F( U_RGBAGetG(pEmr->lopn.lopnColor) ); // b = SP_COLOR_U_TO_F( U_RGBAGetB(pEmr->lopn.lopnColor) ); // cur_ctx.style.stroke.value.color.set( r, g, b ); //} // //void Emf::select_extpen(PEMF_CALLBACK_DATA d, int index) //{ // PU_EMREXTCREATEPEN pEmr = NULL; // // if (index >= 0 && index < d->n_obj) // pEmr = (PU_EMREXTCREATEPEN) d->emf_obj[index].lpEMFR; // // if (!pEmr) // return; // EMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; // // switch (pEmr->elp.elpPenStyle & U_PS_STYLE_MASK) // { // case U_PS_USERSTYLE: // { // if (pEmr->elp.elpNumEntries) // { // if (!cur_ctx.style.stroke_dasharray.values.empty() && (d->level==0 || (d->level>0 && cur_ctx.style.stroke_dasharray.values!=d->dc[d->level-1].style.stroke_dasharray.values))) // cur_ctx.style.stroke_dasharray.values.clear(); // for (unsigned int i=0; ielp.elpNumEntries; i++) // { // // Doing it this way typically results in a pattern that is tiny, better to assume the array // // is the same scale as for dot/dash below, that is, no scaling should be applied // // double dash_length = pix_to_abs_size( d, pEmr->elp.elpStyleEntry[i] ); // double dash_length = pEmr->elp.elpStyleEntry[i]; // cur_ctx.style.stroke_dasharray.values.push_back(dash_length); // } // cur_ctx.style.stroke_dasharray.set = 1; // } // else // { // cur_ctx.style.stroke_dasharray.set = 0; // } // break; // } // case U_PS_DASH: // case U_PS_DOT: // case U_PS_DASHDOT: // case U_PS_DASHDOTDOT: // { // int penstyle = (pEmr->elp.elpPenStyle & U_PS_STYLE_MASK); // if (!cur_ctx.style.stroke_dasharray.values.empty() && (d->level==0 || (d->level>0 && cur_ctx.style.stroke_dasharray.values!=d->dc[d->level-1].style.stroke_dasharray.values))) // cur_ctx.style.stroke_dasharray.values.clear(); // if (penstyle==U_PS_DASH || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) // { // cur_ctx.style.stroke_dasharray.values.push_back( 3 ); // cur_ctx.style.stroke_dasharray.values.push_back( 2 ); // } // if (penstyle==U_PS_DOT || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) // { // cur_ctx.style.stroke_dasharray.values.push_back( 1 ); // cur_ctx.style.stroke_dasharray.values.push_back( 2 ); // } // if (penstyle==U_PS_DASHDOTDOT) // { // cur_ctx.style.stroke_dasharray.values.push_back( 1 ); // cur_ctx.style.stroke_dasharray.values.push_back( 2 ); // } // // cur_ctx.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: // cur_ctx.style.stroke_dasharray.set = 0; // break; // } // // switch (pEmr->elp.elpPenStyle & U_PS_ENDCAP_MASK) // { // case U_PS_ENDCAP_ROUND: // cur_ctx.style.stroke_linecap.computed = 1; // break; // case U_PS_ENDCAP_SQUARE: // cur_ctx.style.stroke_linecap.computed = 2; // break; // case U_PS_ENDCAP_FLAT: // default: // cur_ctx.style.stroke_linecap.computed = 0; // break; // } // // switch (pEmr->elp.elpPenStyle & U_PS_JOIN_MASK) // { // case U_PS_JOIN_BEVEL: // cur_ctx.style.stroke_linejoin.computed = 2; // break; // case U_PS_JOIN_MITER: // cur_ctx.style.stroke_linejoin.computed = 0; // break; // case U_PS_JOIN_ROUND: // default: // cur_ctx.style.stroke_linejoin.computed = 1; // break; // } // // cur_ctx.stroke_set = true; // // 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(cur_ctx.textColor)); // g = SP_COLOR_U_TO_F( U_RGBAGetG(cur_ctx.textColor)); // b = SP_COLOR_U_TO_F( U_RGBAGetB(cur_ctx.textColor)); // cur_ctx.style.stroke.value.color.set( r, g, b ); // cur_ctx.style.stroke_width.value = 0; // cur_ctx.stroke_set = false; // cur_ctx.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_abs_size( d, pEmr->elp.elpWidth ); // d->level = cur_level; // cur_ctx.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?) // //cur_ctx.style.stroke_width.value = 1.0; // int cur_level = d->level; // d->level = d->emf_obj[index].level; // double pen_width = pix_to_abs_size( d, 1 ); // d->level = cur_level; // cur_ctx.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) ); // cur_ctx.style.stroke.value.color.set( r, g, b ); // cur_ctx.stroke_mode = DRAW_PAINT; // cur_ctx.stroke_set = true; // } // else if(pEmr->elp.elpBrushStyle == U_BS_HATCHED) // { // cur_ctx.stroke_idx = add_hatch(d, pEmr->elp.elpHatch, pEmr->elp.elpColor); // cur_ctx.stroke_recidx = index; // used if the hatch needs to be redone due to bkMode, textmode, etc. changes // cur_ctx.stroke_mode = DRAW_PATTERN; // cur_ctx.stroke_set = true; // } // else if(pEmr->elp.elpBrushStyle == U_BS_DIBPATTERN || pEmr->elp.elpBrushStyle == U_BS_DIBPATTERNPT) // { // cur_ctx.stroke_idx = add_image(d, (void *)pEmr, pEmr->cbBits, pEmr->cbBmi, *(OdUInt32 *) &(pEmr->elp.elpColor), pEmr->offBits, pEmr->offBmi); // cur_ctx.stroke_mode = DRAW_IMAGE; // cur_ctx.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(cur_ctx.textColor)); // g = SP_COLOR_U_TO_F( U_RGBAGetG(cur_ctx.textColor)); // b = SP_COLOR_U_TO_F( U_RGBAGetB(cur_ctx.textColor)); // cur_ctx.style.stroke.value.color.set( r, g, b ); // cur_ctx.stroke_mode = DRAW_PAINT; // cur_ctx.stroke_set = true; // } // } //} // //void Emf::select_brush(PEMF_CALLBACK_DATA d, int index) //{ // OdUInt32 tidx; // OdUInt32 iType; // // if (index >= 0 && index < d->n_obj) // { // iType = ((PU_EMR) (d->emf_obj[index].lpEMFR))->iType; // if(iType == _EMR_CREATEBRUSHINDIRECT) // { // PU_EMRCREATEBRUSHINDIRECT pEmr = (PU_EMRCREATEBRUSHINDIRECT) d->emf_obj[index].lpEMFR; // if(pEmr->lb.lbStyle == U_BS_SOLID) // { // double r, g, b; // r = SP_COLOR_U_TO_F( U_RGBAGetR(pEmr->lb.lbColor) ); // g = SP_COLOR_U_TO_F( U_RGBAGetG(pEmr->lb.lbColor) ); // b = SP_COLOR_U_TO_F( U_RGBAGetB(pEmr->lb.lbColor) ); // cur_ctx.style.fill_color.set( r, g, b ); // cur_ctx.fill_mode = DRAW_PAINT; // cur_ctx.fill_set = true; // } // else if(pEmr->lb.lbStyle == U_BS_HATCHED) // { // cur_ctx.fill_idx = add_hatch(d, pEmr->lb.lbHatch, pEmr->lb.lbColor); // cur_ctx.fill_recidx = index; // used if the hatch needs to be redone due to bkMode, textmode, etc. changes // cur_ctx.fill_mode = DRAW_PATTERN; // cur_ctx.fill_set = true; // } // } // else if(iType == _EMR_CREATEDIBPATTERNBRUSHPT || iType == _EMR_CREATEMONOBRUSH) // { // PU_EMRCREATEDIBPATTERNBRUSHPT pEmr = (PU_EMRCREATEDIBPATTERNBRUSHPT) d->emf_obj[index].lpEMFR; // tidx = add_image(d, (void *) pEmr, pEmr->cbBits, pEmr->cbBmi, pEmr->iUsage, pEmr->offBits, pEmr->offBmi); // if(tidx == _EMR_INVALID) // { // // This happens if createmonobrush has a DIB that isn't monochrome // double r, g, b; // r = SP_COLOR_U_TO_F( U_RGBAGetR(cur_ctx.textColor)); // g = SP_COLOR_U_TO_F( U_RGBAGetG(cur_ctx.textColor)); // b = SP_COLOR_U_TO_F( U_RGBAGetB(cur_ctx.textColor)); // cur_ctx.style.fill_color.set( r, g, b ); // cur_ctx.fill_mode = DRAW_PAINT; // } // else // { // cur_ctx.fill_idx = tidx; // cur_ctx.fill_mode = DRAW_IMAGE; // } // cur_ctx.fill_set = true; // } // } //} // //void Emf::select_font(PEMF_CALLBACK_DATA d, int index) //{ // PU_EMREXTCREATEFONTINDIRECTW pEmr = NULL; // // if (index >= 0 && index < d->n_obj) // pEmr = (PU_EMREXTCREATEFONTINDIRECTW) d->emf_obj[index].lpEMFR; // // if (!pEmr) // return; // EMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; // // // The logfont information always starts with a U_LOGFONT structure but the U_EMREXTCREATEFONTINDIRECTW // // is defined as U_LOGFONT_PANOSE so it can handle one of those if that is actually present. Currently only logfont // // is supported, and the remainder, it it really is a U_LOGFONT_PANOSE record, is ignored // int cur_level = d->level; // d->level = d->emf_obj[index].level; // double font_size = pix_to_abs_size( d, pEmr->elfw.elfLogFont.lfHeight ); // // 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->D2Pscale[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 .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; // cur_ctx.style.font_size.computed = font_size; // cur_ctx.style.font_weight.value = // pEmr->elfw.elfLogFont.lfWeight == U_FW_THIN ? SP_CSS_FONT_WEIGHT_100 : // pEmr->elfw.elfLogFont.lfWeight == U_FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_200 : // pEmr->elfw.elfLogFont.lfWeight == U_FW_LIGHT ? SP_CSS_FONT_WEIGHT_300 : // pEmr->elfw.elfLogFont.lfWeight == U_FW_NORMAL ? SP_CSS_FONT_WEIGHT_400 : // pEmr->elfw.elfLogFont.lfWeight == U_FW_MEDIUM ? SP_CSS_FONT_WEIGHT_500 : // pEmr->elfw.elfLogFont.lfWeight == U_FW_SEMIBOLD ? SP_CSS_FONT_WEIGHT_600 : // pEmr->elfw.elfLogFont.lfWeight == U_FW_BOLD ? SP_CSS_FONT_WEIGHT_700 : // pEmr->elfw.elfLogFont.lfWeight == U_FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_800 : // pEmr->elfw.elfLogFont.lfWeight == U_FW_HEAVY ? SP_CSS_FONT_WEIGHT_900 : // pEmr->elfw.elfLogFont.lfWeight == U_FW_NORMAL ? SP_CSS_FONT_WEIGHT_NORMAL : // pEmr->elfw.elfLogFont.lfWeight == U_FW_BOLD ? SP_CSS_FONT_WEIGHT_BOLD : // pEmr->elfw.elfLogFont.lfWeight == U_FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_LIGHTER : // pEmr->elfw.elfLogFont.lfWeight == U_FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_BOLDER : // U_FW_NORMAL; // cur_ctx.style.font_style.value = (pEmr->elfw.elfLogFont.lfItalic ? SP_CSS_FONT_STYLE_ITALIC : SP_CSS_FONT_STYLE_NORMAL); // cur_ctx.style.text_decoration_line.underline = pEmr->elfw.elfLogFont.lfUnderline; // cur_ctx.style.text_decoration_line.line_through = pEmr->elfw.elfLogFont.lfStrikeOut; // cur_ctx.style.text_decoration_line.set = true; // cur_ctx.style.text_decoration_line.inherit = false; // // malformed EMF with empty filename may exist, ignore font change if encountered // char *ctmp = U_Utf16leToUtf8((OdUInt16 *) (pEmr->elfw.elfLogFont.lfFaceName), U_LF_FACESIZE, NULL); // if(ctmp) // { // if (cur_ctx.font_name) // { // free(cur_ctx.font_name); // } // if(*ctmp) // { // cur_ctx.font_name = ctmp; // } // else // { // Malformed EMF might specify an empty font name // free(ctmp); // cur_ctx.font_name = strdup("Arial"); // Default font, EMF spec says device can pick whatever it wants // } // } // cur_ctx.style.baseline_shift.value = round((double)((pEmr->elfw.elfLogFont.lfEscapement + 3600) % 3600)) / 10.0; // use baseline_shift instead of text_transform to avoid overflow //} void Emf::delete_object(PEMF_CALLBACK_DATA d, int index) { if (index >= 0 && index < d->n_obj) { d->emf_obj[index].type = 0; // We are keeping a copy of the EMR rather than just a structure. Currently that is not necessary as the entire // EMF is read in at once and is stored in a big malloc. However, in past versions it was handled // reord by record, and we might need to do that again at some point in the future if we start running into EMF // files too big to fit into memory. if (d->emf_obj[index].lpEMFR) free(d->emf_obj[index].lpEMFR); d->emf_obj[index].lpEMFR = NULL; } } //void Emf::insert_object(PEMF_CALLBACK_DATA d, int index, int type, OdEmfMetaRecord* pObj) //{ // if (index >= 0 && index < d->n_obj) // { // delete_object(d, index); // d->emf_obj[index].type = type; // d->emf_obj[index].level = d->level; // d->emf_obj[index].lpEMFR = emr_dup((char *) pObj); // } //} // // Identify probable Adobe Illustrator produced EMF files, which do strange things with the scaling. // The few so far observed all had this format. //int Emf::AI_hack(OdEmfHeader* pEmr) //{ // int ret=0; // char *ptr; // ptr = (char *)pEmr; // OdEmfSetMapMode* nEmr = (OdEmfSetMapMode*) (ptr + pEmr->emr.nSize); // char *string = NULL; // if(pEmr->nDescription) // string = U_Utf16leToUtf8((OdUInt16 *)((char *) pEmr + pEmr->offDescription), pEmr->nDescription, NULL); // if(string) // { // if((pEmr->nDescription >= 13) && // (0==strcmp("Adobe Systems",string)) && // (nEmr->emr.iType == _EMR_SETMAPMODE) && // (nEmr->iMode == U_MM_ANISOTROPIC)) // { // ret=1; // } // 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 //OdUInt32 *Emf::unknown_chars(size_t count) //{ // OdUInt32 *res = (OdUInt32 *) malloc(sizeof(OdUInt32) * (count + 1)); // if(!res) // throw "Inkscape fatal memory allocation error - cannot continue"; // for(OdUInt32 i=0; i(&type); const char *blimit = contents + length; OdEmfMetaRecord* lpEMFR; //TCHUNK_SPECS tsp; OdUInt32 tbkMode = _TRANSPARENT; // holds proposed change to bkMode, if text is involved saving these to the DC must wait until the text is written ODCOLORREF tbkColor = ODRGB(255, 255, 255); // holds proposed change to bkColor // initialize the tsp for text reassembly //tsp.string = NULL; //tsp.ori = 0.0; // degrees //tsp.fs = 12.0; // font size //tsp.x = 0.0; //tsp.y = 0.0; //tsp.boff = 0.0; // offset to baseline from LL corner of bounding rectangle, changes with fs and taln //tsp.vadvance = 0.0; // meaningful only when a complex contains two or more lines //tsp.taln = ALILEFT + ALIBASE; //tsp.ldir = LDIR_LR; //tsp.spaces = 0; // this field is only used for debugging //tsp.color.Red = 0; // RGB Black //tsp.color.Green = 0; // RGB Black //tsp.color.Blue = 0; // RGB Black //tsp.color.Reserved = 0; // not used //tsp.italics = 0; //tsp.weight = 80; //tsp.decoration = TXTDECOR_NONE; //tsp.condensed = 100; //tsp.co = 0; //tsp.fi_idx = -1; // set to an invalid ODA_ASSERT_VAR(OdArray types;) while(OK) { if(off>=length) return(0); //normally should exit from while after EMREOF sets OK to false. // check record sizes and types thoroughly int badrec = 0; if ( !getEmfRecordSize(contents + off, blimit, &iSize, &iType, 1) || !checkEmfRecord(contents + off)) { badrec = 1; } else { emr_mask = getEmfProperties(iType); if (emr_mask == _EMR_INVALID) { badrec = 1; } } nSize = size_t(iSize); if (badrec) { file_status = 0; break; } lpEMFR = (OdEmfMetaRecord*)(contents + off); // Uncomment the following to track down toxic records // std::cout << "record type: " << iType << " name " << U_emr_names(iType) << " length: " << iSize << " offset: " << off <dc[d->level]; //SVGOStringStream tmp_outsvg; //SVGOStringStream tmp_path; //SVGOStringStream tmp_str; //SVGOStringStream dbg_str; // Uncomment the following to track down text problems //std::cout << "tri->dirty:"<< d->tri->dirty << " emr_mask: " << std::hex << emr_mask << std::dec << std::endl; // incompatible change to text drawing detected (color or background change) forces out existing text // OR // next record is valid type and forces pending text to be drawn immediately //if ( (cur_ctx.dirty & DIRTY_TEXT) || ((emr_mask != _EMR_INVALID) // && (emr_mask & U_DRAW_TEXT) && d->tri->dirty)) //{ // TR_layout_analyze(d->tri); // if (cur_ctx.clip_id) // { // SVGOStringStream tmp_clip; // tmp_clip << "\n"; // d->outsvg += tmp_clip.str().c_str(); // } // TR_layout_2_svg(d->tri); // SVGOStringStream ts; // ts << d->tri->out; // d->outsvg += ts.str().c_str(); // d->tri = trinfo_clear(d->tri); // if (cur_ctx.clip_id) // { // d->outsvg += "\n\n"; // } //} if(cur_ctx.dirty) { //Apply the delayed background changes, clear the flag cur_ctx.bkMode = (OdUInt16) tbkMode; memcpy(&(cur_ctx.bkColor), &tbkColor, sizeof(ODCOLORREF)); //if(cur_ctx.dirty & DIRTY_TEXT) //{ // // ODCOLORREF and TRCOLORREF are exactly the same in memory, but the compiler needs some convincing... // if(tbkMode == U_TRANSPARENT) // { // (void) trinfo_load_bk(d->tri, BKCLR_NONE, *(TRCOLORREF *) &tbkColor); // } // else // { // (void) trinfo_load_bk(d->tri, BKCLR_LINE, *(TRCOLORREF *) &tbkColor); // } // Opaque //} // It is possible to have a series of EMF records that would result in // the following creating hash patterns which are never used. For instance, if // there were a series of records that changed the background color but did nothing // else. //if((cur_ctx.stroke_mode == DRAW_PATTERN) && (cur_ctx.dirty & DIRTY_STROKE)) //{ // select_extpen(d, cur_ctx.stroke_recidx); //} //if((cur_ctx.fill_mode == DRAW_PATTERN) && (cur_ctx.dirty & DIRTY_FILL)) //{ // select_brush(d, cur_ctx.fill_recidx); //} cur_ctx.dirty = 0; } // std::cout << "BEFORE DRAW logic d->mask: " << std::hex << d->mask << " emr_mask: " << emr_mask << std::dec << std::endl; //std::cout << "BEFORE DRAW" // << " test0 " << ( d->mask & U_DRAW_VISIBLE) // << " test1 " << ( d->mask & U_DRAW_FORCE) // << " test2 " << (emr_mask & U_DRAW_ALTERS) // << " test3 " << (emr_mask & U_DRAW_VISIBLE) // << " test4 " << !(d->mask & U_DRAW_ONLYTO) // << " test5 " << ((d->mask & U_DRAW_ONLYTO) && !(emr_mask & U_DRAW_ONLYTO) ) // << std::endl; if( (emr_mask != _EMR_INVALID) && // next record is valid type (d->mask & _DRAW_VISIBLE) && // Current set of objects are drawable ( (d->mask & _DRAW_FORCE) || // This draw is forced by STROKE/FILL/STROKEANDFILL PATH (emr_mask & _DRAW_ALTERS) || // Next record would alter the drawing environment in some way ( (emr_mask & _DRAW_VISIBLE) && // Next record is visible... ( ( !(d->mask & _DRAW_ONLYTO) ) || // Non *TO records cannot be followed by any Visible ((d->mask & _DRAW_ONLYTO) && !(emr_mask & _DRAW_ONLYTO) )// *TO records can only be followed by other *TO records ) ) ) ) { //// std::cout << "PATH DRAW at TOP path" << *(d->path) << std::endl; //if(!(d->path.empty())) //{ // d->outsvg += " drawtype) // { // explicit draw type EMR record // output_style(d, d->drawtype); // } // else if(d->mask & U_DRAW_CLOSED) // { // // implicit draw type // output_style(d, _EMR_STROKEANDFILLPATH); // } // else { // output_style(d, _EMR_STROKEPATH); // } // d->outsvg += "\n\t"; // d->outsvg += "\n\td=\""; // this is the ONLY place d=" should be used!!!! One exception, gradientfill. // d->outsvg += d->path; // d->outsvg += " \" /> \n"; // d->path = ""; //} // reset the flags d->mask = 0; d->drawtype = 0; } // std::cout << "AFTER DRAW logic d->mask: " << std::hex << d->mask << " emr_mask: " << emr_mask << std::dec << std::endl; ODA_ASSERT_VAR(types.push_back(type);) switch (type) // (iType) { case _EMR_HEADER: { //dbg_str << "\n"; //d->outdef += "\n"; //if (d->pDesc) //{ // d->outdef += "\n"; //} OdEmfHeader* pEmr = (OdEmfHeader*) lpEMFR; //SVGOStringStream tmp_outdef; //tmp_outdef << "MM100InX = float(pEmr->rclFrame.right - pEmr->rclFrame.left + 1); d->MM100InY = float(pEmr->rclFrame.bottom - pEmr->rclFrame.top + 1); d->PixelsInX = float(pEmr->rclBounds.right - pEmr->rclBounds.left + 1); d->PixelsInY = float(pEmr->rclBounds.bottom - pEmr->rclBounds.top + 1); //// calculate ratio of Inkscape dpi/EMF device dpi //// This can cause problems later due to accuracy limits in the EMF. A high resolution //// EMF might have a final D2Pscale[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->szlMillimeters.cy) && ( pEmr->szlDevice.cx + pEmr->szlDevice.cy)) //{ // d->E2IdirY = 1.0; // assume MM_TEXT, if not, this will be changed later // d->D2PscaleX = d->D2PscaleY = Inkscape::Util::Quantity::convert(1, "mm", "px") * // (double)(pEmr->szlMillimeters.cx + pEmr->szlMillimeters.cy)/ // (double)( pEmr->szlDevice.cx + pEmr->szlDevice.cy); //} //trinfo_load_qe(d->tri, d->D2PscaleX); // quantization error that will affect text positions //// 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->MM100InX *= 25.4/(10.0*3.0); // d->MM100InY *= 25.4/(10.0*3.0); // d->D2PscaleX *= 25.4/(10.0*3.0); // d->D2PscaleY *= 25.4/(10.0*3.0); //} //d->MMX = d->MM100InX / 100.0; //d->MMY = d->MM100InY / 100.0; //d->PixelsOutX = Inkscape::Util::Quantity::convert(d->MMX, "mm", "px"); //d->PixelsOutY = Inkscape::Util::Quantity::convert(d->MMY, "mm", "px"); //// 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->D2PscaleX; //d->ulCornerOutY = d->ulCornerInY * d->E2IdirY * d->D2PscaleY; //tmp_outdef << // " width=\"" << d->MMX << "mm\"\n" << // " height=\"" << d->MMY << "mm\">\n"; //d->outdef += tmp_outdef.str().c_str(); //d->outdef += ""; // temporary end of header //// d->defs holds any defines which are read in. //tmp_outsvg << "\n\n\n"; // start of main body if (pEmr->nHandles) { d->n_obj = pEmr->nHandles; d->emf_obj = new EMF_OBJECT[d->n_obj]; // Init the new emf_obj list elements to null, provided the // dynamic allocation succeeded. if ( d->emf_obj != NULL ) { for( int i=0; i < d->n_obj; ++i ) d->emf_obj[i].lpEMFR = NULL; } //if } else { d->emf_obj = NULL; } break; } case _EMR_POLYBEZIER: { //dbg_str << "\n"; OdEmfPolyBezier* pEmr = (OdEmfPolyBezier*) lpEMFR; OdUInt32 i,j; if (pEmr->cptl<4) break; d->mask |= emr_mask; //tmp_str << "\n\tM " << pix_to_xy( d, pEmr->aptl[0].x, pEmr->aptl[0].y) << " "; //for (i=1; icptl; ) //{ // tmp_str << "\n\tC "; // for (j=0; j<3 && icptl; j++,i++) // { // tmp_str << pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y) << " "; // } //} //tmp_path << tmp_str.str().c_str(); break; } case _EMR_POLYGON: { //dbg_str << "\n"; OdEmfPolygon* pEmr = (OdEmfPolygon*) lpEMFR; OdUInt32 i; if (pEmr->cptl < 2) break; d->mask |= emr_mask; //tmp_str << "\n\tM " << pix_to_xy( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " "; //for (i=1; icptl; i++) //{ // tmp_str << "\n\tL " << pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; //} //tmp_path << tmp_str.str().c_str(); //tmp_path << " z"; break; } case _EMR_POLYLINE: { // dbg_str << "\n"; OdEmfPolyline* pEmr = (OdEmfPolyline*) lpEMFR; OdUInt32 i; if (pEmr->cptl<2) break; d->mask |= emr_mask; //tmp_str << "\n\tM " << pix_to_xy( d, pEmr->aptl[0].x, pEmr->aptl[0].y ) << " "; //for (i=1; icptl; i++) //{ // tmp_str << "\n\tL " << pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; //} //tmp_path << tmp_str.str().c_str(); break; } case _EMR_POLYBEZIERTO: { // dbg_str << "\n"; OdEmfPolyBezierTo* pEmr = (OdEmfPolyBezierTo*) lpEMFR; OdUInt32 i,j; d->mask |= emr_mask; //for (i=0; icptl;) //{ // tmp_path << "\n\tC "; // for (j=0; j<3 && icptl; j++,i++) // { // tmp_path << pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; // } //} break; } case _EMR_POLYLINETO: { //dbg_str << "\n"; OdEmfPolylineTo* pEmr = (OdEmfPolylineTo*) lpEMFR; OdUInt32 i; d->mask |= emr_mask; //for (i=0; icptl;i++) { // tmp_path << "\n\tL " << pix_to_xy( d, pEmr->aptl[i].x, pEmr->aptl[i].y ) << " "; //} break; } case _EMR_POLYPOLYLINE: case _EMR_POLYPOLYGON: { //if (lpEMFR->iType == _EMR_POLYPOLYLINE) // dbg_str << "\n"; //if (lpEMFR->iType == _EMR_POLYPOLYGON) // dbg_str << "\n"; OdEmfPolyPolygon* pEmr = (OdEmfPolyPolygon*) lpEMFR; unsigned int n, i, j; d->mask |= emr_mask; OdWmfPointL *aptl = (OdWmfPointL*) &pEmr->aPolyCounts[pEmr->nPolys]; //i = 0; //for (n=0; nnPolys && icptl; n++) //{ // SVGOStringStream poly_path; // poly_path << "\n\tM " << pix_to_xy( d, aptl[i].x, aptl[i].y) << " "; // i++; // for (j=1; jaPolyCounts[n] && icptl; j++) // { // poly_path << "\n\tL " << pix_to_xy( d, aptl[i].x, aptl[i].y) << " "; // i++; // } // tmp_str << poly_path.str().c_str(); // if (lpEMFR->iType == _EMR_POLYPOLYGON) // tmp_str << " z"; // tmp_str << " \n"; //} //tmp_path << tmp_str.str().c_str(); break; } case _EMR_SETWINDOWEXTEX: { //dbg_str << "\n"; OdEmfSetWindowExt* pEmr = (OdEmfSetWindowExt*) lpEMFR; cur_ctx.sizeWnd = pEmr->szlExtent; if (!cur_ctx.sizeWnd.cx || !cur_ctx.sizeWnd.cy) { cur_ctx.sizeWnd = cur_ctx.sizeView; if (!cur_ctx.sizeWnd.cx || !cur_ctx.sizeWnd.cy) { cur_ctx.sizeWnd.cx = (int32_t) d->PixelsOutX; cur_ctx.sizeWnd.cy = (int32_t) d->PixelsOutY; } } if (!cur_ctx.sizeView.cx || !cur_ctx.sizeView.cy) { cur_ctx.sizeView = cur_ctx.sizeWnd; } // scales logical to EMF pixels, transfer a negative sign on Y, if any if (cur_ctx.sizeWnd.cx && cur_ctx.sizeWnd.cy) { cur_ctx.ScaleInX = (double) cur_ctx.sizeView.cx / (double) cur_ctx.sizeWnd.cx; cur_ctx.ScaleInY = (double) cur_ctx.sizeView.cy / (double) cur_ctx.sizeWnd.cy; if(cur_ctx.ScaleInY < 0) { cur_ctx.ScaleInY *= -1.0; d->E2IdirY = -1.0; } } else { cur_ctx.ScaleInX = 1; cur_ctx.ScaleInY = 1; } break; } case _EMR_SETWINDOWORGEX: { //dbg_str << "\n"; OdEmfSetWindowOrg* pEmr = (OdEmfSetWindowOrg*) lpEMFR; cur_ctx.winorg = pEmr->ptlOrigin; break; } case _EMR_SETVIEWPORTEXTEX: { //dbg_str << "\n"; OdEmfSetViewportExt* pEmr = (OdEmfSetViewportExt*) lpEMFR; cur_ctx.sizeView = pEmr->szlExtent; if (!cur_ctx.sizeView.cx || !cur_ctx.sizeView.cy) { cur_ctx.sizeView = cur_ctx.sizeWnd; if (!cur_ctx.sizeView.cx || !cur_ctx.sizeView.cy) { cur_ctx.sizeView.cx = (int32_t) d->PixelsOutX; cur_ctx.sizeView.cy = (int32_t) d->PixelsOutY; } } if (!cur_ctx.sizeWnd.cx || !cur_ctx.sizeWnd.cy) { cur_ctx.sizeWnd = cur_ctx.sizeView; } // scales logical to EMF pixels, transfer a negative sign on Y, if any if (cur_ctx.sizeWnd.cx && cur_ctx.sizeWnd.cy) { cur_ctx.ScaleInX = (double) cur_ctx.sizeView.cx / (double) cur_ctx.sizeWnd.cx; cur_ctx.ScaleInY = (double) cur_ctx.sizeView.cy / (double) cur_ctx.sizeWnd.cy; if (cur_ctx.ScaleInY < 0) { cur_ctx.ScaleInY *= -1.0; d->E2IdirY = -1.0; } } else { cur_ctx.ScaleInX = 1; cur_ctx.ScaleInY = 1; } break; } case _EMR_SETVIEWPORTORGEX: { //dbg_str << "\n"; OdEmfSetViewportOrg* pEmr = (OdEmfSetViewportOrg*) lpEMFR; cur_ctx.vieworg = pEmr->ptlOrigin; break; } case _EMR_SETBRUSHORGEX: //dbg_str << "\n"; break; case _EMR_EOF: { //dbg_str << "\n"; //tmp_outsvg << "\n"; //d->outsvg = d->outdef + d->defs + d->outsvg; OK=0; break; } case _EMR_SETPIXELV: //dbg_str << "\n"; break; case _EMR_SETMAPPERFLAGS: //dbg_str << "\n"; break; case _EMR_SETMAPMODE: { //dbg_str << "\n"; OdEmfSetMapMode* pEmr = (OdEmfSetMapMode*) lpEMFR; switch (pEmr->iMode) { case _MM_TEXT: default: // Use all values from the header. break; // For all of the following the indicated scale this will be encoded in WindowExtEx/ViewportExtex // and show up in ScaleIn[XY] case _MM_LOMETRIC: // 1 LU = 0.1 mm, case _MM_HIMETRIC: // 1 LU = 0.01 mm case _MM_LOENGLISH: // 1 LU = 0.1 in case _MM_HIENGLISH: // 1 LU = 0.01 in case _MM_TWIPS: // 1 LU = 1/1440 in d->E2IdirY = -1.0; // Use d->D2Pscale[XY] values from the header. break; case _MM_ISOTROPIC: // ScaleIn[XY] should be set elsewhere by SETVIEWPORTEXTEX and SETWINDOWEXTEX case _MM_ANISOTROPIC: break; } break; } case _EMR_SETBKMODE: { //dbg_str << "\n"; OdEmfSetBkMode* pEmr = (OdEmfSetBkMode*) lpEMFR; tbkMode = pEmr->iMode; if(tbkMode != cur_ctx.bkMode) { cur_ctx.dirty |= DIRTY_TEXT; if(tbkMode != cur_ctx.bkMode) { //if(cur_ctx.fill_mode == DRAW_PATTERN) //{ // cur_ctx.dirty |= DIRTY_FILL; //} //if(cur_ctx.stroke_mode == DRAW_PATTERN) //{ // cur_ctx.dirty |= DIRTY_STROKE; //} } memcpy(&tbkColor, &(cur_ctx.bkColor), sizeof(ODCOLORREF)); } break; } case _EMR_SETPOLYFILLMODE: { //dbg_str << "\n"; //OdEmfSetPolyFillMode* pEmr = (OdEmfSetPolyFillMode*) lpEMFR; //cur_ctx.style.fill_rule.value = // (pEmr->iMode == U_ALTERNATE ? 0 : (pEmr->iMode == U_WINDING ? 1 : 0)); break; } case _EMR_SETROP2: { //dbg_str << "\n"; OdEmfSetRop2* pEmr = (OdEmfSetRop2*) lpEMFR; d->dwRop2 = pEmr->iMode; break; } case _EMR_SETSTRETCHBLTMODE: { //dbg_str << "\n"; //OdEmfSetStretchBltMode* pEmr = (OdEmfSetStretchBltMode*) lpEMFR; // from wingdi.h //BLTmode = pEmr->iMode; break; } case _EMR_SETTEXTALIGN: { //sdbg_str << "\n"; OdEmfSetTextAlign* pEmr = (OdEmfSetTextAlign*) lpEMFR; cur_ctx.textAlign = pEmr->iMode; break; } case _EMR_SETCOLORADJUSTMENT: //dbg_str << "\n"; break; case _EMR_SETTEXTCOLOR: { //dbg_str << "\n"; OdEmfSetTextColor* pEmr = (OdEmfSetTextColor*) lpEMFR; cur_ctx.textColor = *(ODCOLORREF*)&pEmr->crColor; if(tbkMode != cur_ctx.bkMode) { //if(cur_ctx.fill_mode == DRAW_PATTERN) //{ // cur_ctx.dirty |= DIRTY_FILL; //} //if(cur_ctx.stroke_mode == DRAW_PATTERN) //{ // cur_ctx.dirty |= DIRTY_STROKE; //} } // not text_dirty, because multicolored complex text is supported in libTERE break; } case _EMR_SETBKCOLOR: { //dbg_str << "\n"; OdEmfSetBkColor* pEmr = (OdEmfSetBkColor*) lpEMFR; tbkColor = *(ODCOLORREF*)&pEmr->crColor; if(memcmp(&tbkColor, &(cur_ctx.bkColor), sizeof(ODCOLORREF))) { cur_ctx.dirty |= DIRTY_TEXT; //if(cur_ctx.fill_mode == DRAW_PATTERN) //{ // cur_ctx.dirty |= DIRTY_FILL; //} //if(cur_ctx.stroke_mode == DRAW_PATTERN) //{ // cur_ctx.dirty |= DIRTY_STROKE; //} tbkMode = cur_ctx.bkMode; } break; } case _EMR_OFFSETCLIPRGN: { //dbg_str << "\n"; if (cur_ctx.clip_id) { // can only offsetan existing clipping path OdEmfOffsetClipRgn* pEmr = (OdEmfOffsetClipRgn*) lpEMFR; //OdWmfPointL off = pEmr->ptlOffset; //unsigned int real_idx = cur_ctx.clip_id - 1; //Geom::PathVector tmp_vect = sp_svg_read_pathv(d->clips.strings[real_idx]); //double ox = pix_to_x_point(d, off.x, off.y) - pix_to_x_point(d, 0, 0); // take into account all active transforms //double oy = pix_to_y_point(d, off.x, off.y) - pix_to_y_point(d, 0, 0); //Geom::Affine tf = Geom::Translate(ox,oy); //tmp_vect *= tf; //char *tmp_path = sp_svg_write_path(tmp_vect); //add_clips(d, tmp_path, U_RGN_COPY); //free(tmp_path); } break; } case _EMR_MOVETOEX: { //dbg_str << "\n"; OdEmfMoveTo* pEmr = (OdEmfMoveTo*) lpEMFR; d->mask |= emr_mask; cur_ctx.cur = pEmr->ptl; //tmp_path << "\n\tM " << pix_to_xy( d, pEmr->ptl.x, pEmr->ptl.y ) << " "; break; } case _EMR_SETMETARGN: //dbg_str << "\n"; break; case _EMR_EXCLUDECLIPRECT: { //dbg_str << "\n"; OdEmfExcludeClipRect* pEmr = (OdEmfExcludeClipRect*) lpEMFR; OdWmfRectL rc = pEmr->rclClip; //SVGOStringStream tmp_path; ////outer rect, clockwise //tmp_path << "M " << faraway << "," << faraway << " "; //tmp_path << "L " << faraway << "," << -faraway << " "; //tmp_path << "L " << -faraway << "," << -faraway << " "; //tmp_path << "L " << -faraway << "," << faraway << " "; //tmp_path << "z "; ////inner rect, counterclockwise (sign of Y is reversed) //tmp_path << "M " << pix_to_xy( d, rc.left , rc.top ) << " "; //tmp_path << "L " << pix_to_xy( d, rc.right, rc.top ) << " "; //tmp_path << "L " << pix_to_xy( d, rc.right, rc.bottom ) << " "; //tmp_path << "L " << pix_to_xy( d, rc.left, rc.bottom ) << " "; //tmp_path << "z"; // //add_clips(d, tmp_path.str().c_str(), U_RGN_AND); //d->path = ""; d->drawtype = 0; break; } case _EMR_INTERSECTCLIPRECT: { //dbg_str << "\n"; OdEmfIntersectClipRect* pEmr = (OdEmfIntersectClipRect*) lpEMFR; OdWmfRectL rc = pEmr->rclClip; //SVGOStringStream tmp_path; //tmp_path << "M " << pix_to_xy( d, rc.left , rc.top ) << " "; //tmp_path << "L " << pix_to_xy( d, rc.right, rc.top ) << " "; //tmp_path << "L " << pix_to_xy( d, rc.right, rc.bottom ) << " "; //tmp_path << "L " << pix_to_xy( d, rc.left, rc.bottom ) << " "; //tmp_path << "z"; //add_clips(d, tmp_path.str().c_str(), U_RGN_AND); //d->path = ""; d->drawtype = 0; break; } case _EMR_SCALEVIEWPORTEXTEX: //dbg_str << "\n"; break; case _EMR_SCALEWINDOWEXTEX: //dbg_str << "\n"; break; case _EMR_SAVEDC: //dbg_str << "\n"; if (d->level < EMF_MAX_DC) { d->dc[d->level + 1] = cur_ctx; // = d->dc[d->level]; if(cur_ctx.font_name) { d->dc[d->level + 1].font_name = strdup(cur_ctx.font_name); // or memory access problems because font name pointer duplicated } d->level = d->level + 1; } break; case _EMR_RESTOREDC: { //dbg_str << "\n"; OdEmfRestoreDc* pEmr = (OdEmfRestoreDc*) lpEMFR; int old_level = d->level; if (pEmr->iRelative >= 0) { if (pEmr->iRelative < d->level) d->level = pEmr->iRelative; } else { if (d->level + pEmr->iRelative >= 0) d->level = d->level + pEmr->iRelative; } while (old_level > d->level) { //if ( !d->dc[old_level].style.stroke_dasharray.values.empty() // && ( old_level==0 // || ( old_level>0 // && d->dc[old_level].style.stroke_dasharray.values!=d->dc[old_level-1].style.stroke_dasharray.values))) //{ // d->dc[old_level].style.stroke_dasharray.values.clear(); //} if(d->dc[old_level].font_name) { free(d->dc[old_level].font_name); // else memory leak d->dc[old_level].font_name = NULL; } old_level--; } break; } case _EMR_SETWORLDTRANSFORM: { //dbg_str << "\n"; OdEmfSetWorldTransform* pEmr = (OdEmfSetWorldTransform*) lpEMFR; cur_ctx.worldTransform = pEmr->xform; break; } case _EMR_MODIFYWORLDTRANSFORM: { //dbg_str << "\n"; OdEmfModifyWorldTransform* pEmr = (OdEmfModifyWorldTransform*) lpEMFR; switch (pEmr->iMode) { case _MWT_IDENTITY: cur_ctx.worldTransform.eM11 = 1.0; cur_ctx.worldTransform.eM12 = 0.0; cur_ctx.worldTransform.eM21 = 0.0; cur_ctx.worldTransform.eM22 = 1.0; cur_ctx.worldTransform.eDx = 0.0; cur_ctx.worldTransform.eDy = 0.0; break; case _MWT_LEFTMULTIPLY: { //cur_ctx.worldTransform = pEmr->xform * worldTransform; float a11 = pEmr->xform.eM11; float a12 = pEmr->xform.eM12; float a13 = 0.0; float a21 = pEmr->xform.eM21; float a22 = pEmr->xform.eM22; float a23 = 0.0; float a31 = pEmr->xform.eDx; float a32 = pEmr->xform.eDy; float a33 = 1.0; float b11 = cur_ctx.worldTransform.eM11; float b12 = cur_ctx.worldTransform.eM12; //float b13 = 0.0; float b21 = cur_ctx.worldTransform.eM21; float b22 = cur_ctx.worldTransform.eM22; //float b23 = 0.0; float b31 = cur_ctx.worldTransform.eDx; float b32 = cur_ctx.worldTransform.eDy; //float b33 = 1.0; float c11 = a11*b11 + a12*b21 + a13*b31;; float c12 = a11*b12 + a12*b22 + a13*b32;; //float c13 = a11*b13 + a12*b23 + a13*b33;; float c21 = a21*b11 + a22*b21 + a23*b31;; float c22 = a21*b12 + a22*b22 + a23*b32;; //float c23 = a21*b13 + a22*b23 + a23*b33;; float c31 = a31*b11 + a32*b21 + a33*b31;; float c32 = a31*b12 + a32*b22 + a33*b32;; //float c33 = a31*b13 + a32*b23 + a33*b33;; cur_ctx.worldTransform.eM11 = c11;; cur_ctx.worldTransform.eM12 = c12;; cur_ctx.worldTransform.eM21 = c21;; cur_ctx.worldTransform.eM22 = c22;; cur_ctx.worldTransform.eDx = c31; cur_ctx.worldTransform.eDy = c32; break; } case _MWT_RIGHTMULTIPLY: { //cur_ctx.worldTransform = worldTransform * pEmr->xform; float a11 = cur_ctx.worldTransform.eM11; float a12 = cur_ctx.worldTransform.eM12; float a13 = 0.0; float a21 = cur_ctx.worldTransform.eM21; float a22 = cur_ctx.worldTransform.eM22; float a23 = 0.0; float a31 = cur_ctx.worldTransform.eDx; float a32 = cur_ctx.worldTransform.eDy; float a33 = 1.0; float b11 = pEmr->xform.eM11; float b12 = pEmr->xform.eM12; //float b13 = 0.0; float b21 = pEmr->xform.eM21; float b22 = pEmr->xform.eM22; //float b23 = 0.0; float b31 = pEmr->xform.eDx; float b32 = pEmr->xform.eDy; //float b33 = 1.0; float c11 = a11*b11 + a12*b21 + a13*b31;; float c12 = a11*b12 + a12*b22 + a13*b32;; //float c13 = a11*b13 + a12*b23 + a13*b33;; float c21 = a21*b11 + a22*b21 + a23*b31;; float c22 = a21*b12 + a22*b22 + a23*b32;; //float c23 = a21*b13 + a22*b23 + a23*b33;; float c31 = a31*b11 + a32*b21 + a33*b31;; float c32 = a31*b12 + a32*b22 + a33*b32;; //float c33 = a31*b13 + a32*b23 + a33*b33;; cur_ctx.worldTransform.eM11 = c11;; cur_ctx.worldTransform.eM12 = c12;; cur_ctx.worldTransform.eM21 = c21;; cur_ctx.worldTransform.eM22 = c22;; cur_ctx.worldTransform.eDx = c31; cur_ctx.worldTransform.eDy = c32; break; } //case MWT_SET: default: cur_ctx.worldTransform = pEmr->xform; break; } break; } case _EMR_SELECTOBJECT: { //dbg_str << "\n"; OdEmfSelectObject* pEmr = (OdEmfSelectObject*) lpEMFR; unsigned int index = pEmr->ihObject; if (index & _STOCK_OBJECT) { switch (index) { case _NULL_BRUSH: //cur_ctx.fill_mode = DRAW_PAINT; //cur_ctx.fill_set = false; break; case _BLACK_BRUSH: case _DKGRAY_BRUSH: case _GRAY_BRUSH: case _LTGRAY_BRUSH: case _WHITE_BRUSH: { float val = 0; switch (index) { case _BLACK_BRUSH: val = float(0.0 / 255.0); break; case _DKGRAY_BRUSH: val = float(64.0 / 255.0); break; case _GRAY_BRUSH: val = float(128.0 / 255.0); break; case _LTGRAY_BRUSH: val = float(192.0 / 255.0); break; case _WHITE_BRUSH: val = float(255.0 / 255.0); break; } //cur_ctx.style.fill_color.set( val, val, val ); //cur_ctx.fill_mode = DRAW_PAINT; //cur_ctx.fill_set = true; break; } case _NULL_PEN: //cur_ctx.stroke_mode = DRAW_PAINT; //cur_ctx.stroke_set = false; break; case _BLACK_PEN: case _WHITE_PEN: { //float val = index == U_BLACK_PEN ? 0 : 1; //cur_ctx.style.stroke_dasharray.set = 0; //cur_ctx.style.stroke_width.value = 1.0; //cur_ctx.style.stroke.value.color.set( val, val, val ); //cur_ctx.stroke_mode = DRAW_PAINT; //cur_ctx.stroke_set = true; break; } } // sw } else { if (//index >= 0 && index < (unsigned int) d->n_obj) { switch (d->emf_obj[index].type) { case _EMR_CREATEPEN: //select_pen(d, index); break; case _EMR_CREATEBRUSHINDIRECT: case _EMR_CREATEDIBPATTERNBRUSHPT: case _EMR_CREATEMONOBRUSH: //select_brush(d, index); break; case _EMR_EXTCREATEPEN: //select_extpen(d, index); break; case _EMR_EXTCREATEFONTINDIRECTW: //select_font(d, index); break; } } } break; } case _EMR_CREATEPEN: { //dbg_str << "\n"; //PU_EMRCREATEPEN pEmr = (PU_EMRCREATEPEN) lpEMFR; //insert_object(d, pEmr->ihPen, _EMR_CREATEPEN, lpEMFR); break; } case _EMR_CREATEBRUSHINDIRECT: { //dbg_str << "\n"; //PU_EMRCREATEBRUSHINDIRECT pEmr = (PU_EMRCREATEBRUSHINDIRECT) lpEMFR; //insert_object(d, pEmr->ihBrush, _EMR_CREATEBRUSHINDIRECT, lpEMFR); break; } case _EMR_DELETEOBJECT: //dbg_str << "\n"; // Objects here are not deleted until the draw completes, new ones may write over an existing one. break; case _EMR_ANGLEARC: //dbg_str << "\n"; break; case _EMR_ELLIPSE: { //dbg_str << "\n"; //PU_EMRELLIPSE pEmr = (PU_EMRELLIPSE) lpEMFR; //OdWmfRectL rclBox = pEmr->rclBox; //double cx = pix_to_x_point( d, (rclBox.left + rclBox.right)/2.0, (rclBox.bottom + rclBox.top)/2.0 ); //double cy = pix_to_y_point( d, (rclBox.left + rclBox.right)/2.0, (rclBox.bottom + rclBox.top)/2.0 ); //double rx = pix_to_abs_size( d, std::abs(rclBox.right - rclBox.left )/2.0 ); //double ry = pix_to_abs_size( d, std::abs(rclBox.top - rclBox.bottom)/2.0 ); //SVGOStringStream tmp_ellipse; //tmp_ellipse << "cx=\"" << cx << "\" "; //tmp_ellipse << "cy=\"" << cy << "\" "; //tmp_ellipse << "rx=\"" << rx << "\" "; //tmp_ellipse << "ry=\"" << ry << "\" "; d->mask |= emr_mask; //d->outsvg += " iType); // //d->outsvg += "\n\t"; //d->outsvg += tmp_ellipse.str().c_str(); //d->outsvg += "/> \n"; //d->path = ""; break; } case _EMR_RECTANGLE: { //dbg_str << "\n"; //PU_EMRRECTANGLE pEmr = (PU_EMRRECTANGLE) lpEMFR; //OdWmfRectL rc = pEmr->rclBox; //SVGOStringStream tmp_rectangle; //tmp_rectangle << "\n\tM " << pix_to_xy( d, rc.left , rc.top ) << " "; //tmp_rectangle << "\n\tL " << pix_to_xy( d, rc.right, rc.top ) << " "; //tmp_rectangle << "\n\tL " << pix_to_xy( d, rc.right, rc.bottom ) << " "; //tmp_rectangle << "\n\tL " << pix_to_xy( d, rc.left, rc.bottom ) << " "; //tmp_rectangle << "\n\tz"; d->mask |= emr_mask; //tmp_path << tmp_rectangle.str().c_str(); break; } case _EMR_ROUNDRECT: { //dbg_str << "\n"; //PU_EMRROUNDRECT pEmr = (PU_EMRROUNDRECT) lpEMFR; //OdWmfRectL rc = pEmr->rclBox; //OdEmfSizeXY corner = pEmr->szlCorner; //double f = 4.*(sqrt(2) - 1)/3; //double f1 = 1.0 - f; //double cnx = corner.cx/2; //double cny = corner.cy/2; //SVGOStringStream tmp_rectangle; //tmp_rectangle << "\n" // << " M " // << pix_to_xy(d, rc.left , rc.top + cny ) // << "\n"; //tmp_rectangle << " C " // << pix_to_xy(d, rc.left , rc.top + cny*f1 ) // << " " // << pix_to_xy(d, rc.left + cnx*f1 , rc.top ) // << " " // << pix_to_xy(d, rc.left + cnx , rc.top ) // << "\n"; //tmp_rectangle << " L " // << pix_to_xy(d, rc.right - cnx , rc.top ) // << "\n"; //tmp_rectangle << " C " // << pix_to_xy(d, rc.right - cnx*f1 , rc.top ) // << " " // << pix_to_xy(d, rc.right , rc.top + cny*f1 ) // << " " // << pix_to_xy(d, rc.right , rc.top + cny ) // << "\n"; //tmp_rectangle << " L " // << pix_to_xy(d, rc.right , rc.bottom - cny ) // << "\n"; //tmp_rectangle << " C " // << pix_to_xy(d, rc.right , rc.bottom - cny*f1 ) // << " " // << pix_to_xy(d, rc.right - cnx*f1 , rc.bottom ) // << " " // << pix_to_xy(d, rc.right - cnx , rc.bottom ) // << "\n"; //tmp_rectangle << " L " // << pix_to_xy(d, rc.left + cnx , rc.bottom ) // << "\n"; //tmp_rectangle << " C " // << pix_to_xy(d, rc.left + cnx*f1 , rc.bottom ) // << " " // << pix_to_xy(d, rc.left , rc.bottom - cny*f1 ) // << " " // << pix_to_xy(d, rc.left , rc.bottom - cny ) // << "\n"; //tmp_rectangle << " z\n"; d->mask |= emr_mask; //tmp_path << tmp_rectangle.str().c_str(); break; } case _EMR_ARC: { //dbg_str << "\n"; //OdWmfPointF center,start,end,size; //int f1; //int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1); //int stat = emr_arc_points( lpEMFR, &f1, f2, ¢er, &start, &end, &size); //if(!stat){ // tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y); // tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0; // tmp_path << " "; // tmp_path << 180.0 * current_rotation(d)/M_PI; // tmp_path << " "; // tmp_path << " " << f1 << "," << f2 << " "; // tmp_path << pix_to_xy(d, end.x, end.y) << " \n"; // d->mask |= emr_mask; //} //else { // dbg_str << "\n"; //} break; } case _EMR_CHORD: { //dbg_str << "\n"; //OdWmfPointF center,start,end,size; //int f1; //int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1); //if(!emr_arc_points( lpEMFR, &f1, f2, ¢er, &start, &end, &size)){ // tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y); // tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0; // tmp_path << " "; // tmp_path << 180.0 * current_rotation(d)/M_PI; // tmp_path << " "; // tmp_path << " " << f1 << "," << f2 << " "; // tmp_path << pix_to_xy(d, end.x, end.y) << " \n"; // tmp_path << " z "; // d->mask |= emr_mask; //} //else { // dbg_str << "\n"; //} break; } case _EMR_PIE: { //dbg_str << "\n"; //OdWmfPointF center,start,end,size; //int f1; //int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1); //if(!emr_arc_points( lpEMFR, &f1, f2, ¢er, &start, &end, &size)) //{ // tmp_path << "\n\tM " << pix_to_xy(d, center.x, center.y); // tmp_path << "\n\tL " << pix_to_xy(d, start.x, start.y); // tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0; // tmp_path << " "; // tmp_path << 180.0 * current_rotation(d)/M_PI; // tmp_path << " "; // tmp_path << " " << f1 << "," << f2 << " "; // tmp_path << pix_to_xy(d, end.x, end.y) << " \n"; // tmp_path << " z "; // d->mask |= emr_mask; //} //else //{ // dbg_str << "\n"; //} break; } case _EMR_SELECTPALETTE: //dbg_str << "\n"; break; case _EMR_CREATEPALETTE: //dbg_str << "\n"; break; case _EMR_SETPALETTEENTRIES: //dbg_str << "\n"; break; case _EMR_RESIZEPALETTE: //dbg_str << "\n"; break; case _EMR_REALIZEPALETTE: //dbg_str << "\n"; break; case _EMR_EXTFLOODFILL: //dbg_str << "\n"; break; case _EMR_LINETO: { //dbg_str << "\n"; //OdEmfLineTo* pEmr = (OdEmfLineTo*) lpEMFR; d->mask |= emr_mask; //tmp_path << // "\n\tL " << pix_to_xy( d, pEmr->ptl.x, pEmr->ptl.y) << " "; break; } case _EMR_ARCTO: { //dbg_str << "\n"; //OdWmfPointF center,start,end,size; //int f1; //int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1); //if(!emr_arc_points( lpEMFR, &f1, f2, ¢er, &start, &end, &size)) //{ // // draw a line from current position to start, arc from there // tmp_path << "\n\tL " << pix_to_xy(d, start.x, start.y); // tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0; // tmp_path << " "; // tmp_path << 180.0 * current_rotation(d)/M_PI; // tmp_path << " "; // tmp_path << " " << f1 << "," << f2 << " "; // tmp_path << pix_to_xy(d, end.x, end.y)<< " "; d->mask |= emr_mask; //} //else //{ // dbg_str << "\n"; //} break; } case _EMR_POLYDRAW: //dbg_str << "\n"; break; case _EMR_SETARCDIRECTION: { //dbg_str << "\n"; OdEmfSetArcDirection* pEmr = (OdEmfSetArcDirection*) lpEMFR; if(d->arcdir == _AD_CLOCKWISE || d->arcdir == _AD_COUNTERCLOCKWISE) { // EMF file could be corrupt d->arcdir = pEmr->iArcDirection; } break; } case _EMR_SETMITERLIMIT: { //dbg_str << "\n"; //PU_EMRSETMITERLIMIT pEmr = (PU_EMRSETMITERLIMIT) lpEMFR; //The function takes a float but saves a 32 bit int in the _EMR_SETMITERLIMIT record. //float miterlimit = *((int32_t *) &(pEmr->eMiterLimit)); //cur_ctx.style.stroke_miterlimit.value = miterlimit; //ratio, not a pt size //if (cur_ctx.style.stroke_miterlimit.value < 2) // cur_ctx.style.stroke_miterlimit.value = 2.0; break; } case _EMR_BEGINPATH: { ////dbg_str << "\n"; //// The next line should never be needed, should have been handled before main switch //// qualifier added because EMF's encountered where moveto preceded beginpath followed by lineto //if(d->mask & U_DRAW_VISIBLE) //{ // d->path = ""; //} d->mask |= emr_mask; break; } case _EMR_ENDPATH: { //dbg_str << "\n"; d->mask &= (0xFFFFFFFF - _DRAW_ONLYTO); // clear the OnlyTo bit (it might not have been set), prevents any further path extension break; } case _EMR_CLOSEFIGURE: { //dbg_str << "\n"; // EMF may contain multiple closefigures on one path //tmp_path << "\n\tz"; d->mask |= _DRAW_CLOSED; break; } case _EMR_FILLPATH: { //dbg_str << "\n"; if(d->mask & _DRAW_PATH) { // Operation only effects declared paths if(!(d->mask & _DRAW_CLOSED)) { // Close a path not explicitly closed by an EMRCLOSEFIGURE, otherwise fill makes no sense //tmp_path << "\n\tz"; d->mask |= _DRAW_CLOSED; } d->mask |= emr_mask; d->drawtype = _EMR_FILLPATH; } break; } case _EMR_STROKEANDFILLPATH: { //dbg_str << "\n"; if(d->mask & _DRAW_PATH) { // Operation only effects declared paths if(!(d->mask & _DRAW_CLOSED)) { // Close a path not explicitly closed by an EMRCLOSEFIGURE, otherwise fill makes no sense //tmp_path << "\n\tz"; d->mask |= _DRAW_CLOSED; } d->mask |= emr_mask; d->drawtype = _EMR_STROKEANDFILLPATH; } break; } case _EMR_STROKEPATH: { //dbg_str << "\n"; if(d->mask & _DRAW_PATH) { // Operation only effects declared paths d->mask |= emr_mask; d->drawtype = _EMR_STROKEPATH; } break; } case _EMR_FLATTENPATH: //dbg_str << "\n"; break; case _EMR_WIDENPATH: //dbg_str << "\n"; break; case _EMR_SELECTCLIPPATH: { //dbg_str << "\n"; OdEmfSelectClipPath* pEmr = (OdEmfSelectClipPath*) lpEMFR; int logic = pEmr->iMode; if ((logic < _RGN_MIN) || (logic > _RGN_MAX)) { break; } //add_clips(d, d->path.c_str(), logic); // finds an existing one or stores this, sets clip_id //d->path = ""; d->drawtype = 0; break; } case _EMR_ABORTPATH: { //dbg_str << "\n"; //d->path = ""; d->drawtype = 0; break; } case _EMR_UNDEF69: //dbg_str << "\n"; break; case _EMR_COMMENT: { //dbg_str << "\n"; //PU_EMRCOMMENT pEmr = (PU_EMRCOMMENT) lpEMFR; //char *szTxt = (char *) pEmr->Data; //for (OdUInt32 i = 0; i < pEmr->cbData; i++) //{ // if ( *szTxt) // { // if ( *szTxt >= ' ' && *szTxt < 'z' && *szTxt != '<' && *szTxt != '>' ) // { // tmp_str << *szTxt; // } // szTxt++; // } //} //if (0 && strlen(tmp_str.str().c_str())) //{ // tmp_outsvg << " \n"; //} break; } case _EMR_FILLRGN: //dbg_str << "\n"; break; case _EMR_FRAMERGN: //dbg_str << "\n"; break; case _EMR_INVERTRGN: //dbg_str << "\n"; break; case _EMR_PAINTRGN: //dbg_str << "\n"; break; case _EMR_EXTSELECTCLIPRGN: { //dbg_str << "\n"; OdEmfExtSelectClipRgn* pEmr = (OdEmfExtSelectClipRgn*) lpEMFR; // the only mode we implement - this clears the clipping region if (pEmr->iMode == _RGN_COPY) { cur_ctx.clip_id = 0; } break; } case _EMR_BITBLT: { //dbg_str << "\n"; OdEmfBitBlt* pEmr = (OdEmfBitBlt*) lpEMFR; // 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 if(pEmr->dwRop == _NOOP) break; // GDI applications apparently often end with this as a sort of flush(), nothing should be drawn int32_t dx = pEmr->Dest.x; int32_t dy = pEmr->Dest.y; int32_t dw = pEmr->cDest.x; int32_t dh = pEmr->cDest.y; //SVGOStringStream tmp_rectangle; //tmp_rectangle << "\n\tM " << pix_to_xy( d, dx, dy ) << " "; //tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy ) << " "; //tmp_rectangle << "\n\tL " << pix_to_xy( d, dx + dw, dy + dh ) << " "; //tmp_rectangle << "\n\tL " << pix_to_xy( d, dx, dy + dh ) << " "; //tmp_rectangle << "\n\tz"; d->mask |= emr_mask; d->dwRop3 = pEmr->dwRop; // we will try to approximate SOME of these d->mask |= _DRAW_CLOSED; // Bitblit is not really open or closed, but we need it to fill, and this is the flag for that //tmp_path << tmp_rectangle.str().c_str(); } else { //double dx = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y); //double dy = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y); //double dw = pix_to_abs_size( d, pEmr->cDest.x); //double dh = pix_to_abs_size( d, pEmr->cDest.y); ////source position within the bitmap, in pixels //int sx = pEmr->Src.x + pEmr->xformSrc.eDx; //int sy = pEmr->Src.y + pEmr->xformSrc.eDy; //int sw = 0; // extract all of the image //int sh = 0; //if(sx<0)sx=0; //if(sy<0)sy=0; //common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh, // pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc); } break; } case _EMR_STRETCHBLT: { //dbg_str << "\n"; OdEmfStretchBlt* pEmr = (OdEmfStretchBlt*) lpEMFR; // Always grab image, ignore modes. if (pEmr->cbBmiSrc) { //double dx = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y); //double dy = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y); //double dw = pix_to_abs_size( d, pEmr->cDest.x); //double dh = pix_to_abs_size( d, pEmr->cDest.y); ////source position within the bitmap, in pixels //int sx = pEmr->Src.x + pEmr->xformSrc.eDx; //int sy = pEmr->Src.y + pEmr->xformSrc.eDy; //int sw = pEmr->cSrc.x; // extract the specified amount of the image //int sh = pEmr->cSrc.y; //common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh, // pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc); } break; } case _EMR_MASKBLT: { //dbg_str << "\n"; OdEmfMaskBlt* pEmr = (OdEmfMaskBlt*) lpEMFR; // Always grab image, ignore masks and modes. if (pEmr->cbBmiSrc) { //double dx = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y); //double dy = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y); //double dw = pix_to_abs_size( d, pEmr->cDest.x); //double dh = pix_to_abs_size( d, pEmr->cDest.y); //int sx = pEmr->Src.x + pEmr->xformSrc.eDx; //source position within the bitmap, in pixels //int sy = pEmr->Src.y + pEmr->xformSrc.eDy; //int sw = 0; // extract all of the image //int sh = 0; //common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh, // pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc); } break; } case _EMR_PLGBLT: //dbg_str << "\n"; break; case _EMR_SETDIBITSTODEVICE: //dbg_str << "\n"; break; case _EMR_STRETCHDIBITS: { // Some applications use multiple EMF operations, including multiple STRETCHDIBITS to create // images with transparent regions. PowerPoint does this with rotated images, for instance. // Parsing all of that to derive a single resultant image object is left for a later version // of this code. In the meantime, every STRETCHDIBITS goes directly to an image. The Inkscape // user can sort out transparency later using Gimp, if need be. OdEmfStretchDibits* pEmr = (OdEmfStretchDibits*) lpEMFR; double dx = pix_to_x_point( d, pEmr->Dest.x, pEmr->Dest.y ); double dy = pix_to_y_point( d, pEmr->Dest.x, pEmr->Dest.y ); double dw = pix_to_abs_size( d, pEmr->cDest.x); double dh = pix_to_abs_size( d, pEmr->cDest.y); int sx = pEmr->Src.x; //source position within the bitmap, in pixels int sy = pEmr->Src.y; int sw = pEmr->cSrc.x; // extract the specified amount of the image int sh = pEmr->cSrc.y; common_image_extraction(d, pEmr, dx, dy, dw, dh, sx, sy, sw, sh, pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc); //dbg_str << "\n"; break; } case _EMR_EXTCREATEFONTINDIRECTW: { //dbg_str << "\n"; //PU_EMREXTCREATEFONTINDIRECTW pEmr = (PU_EMREXTCREATEFONTINDIRECTW) lpEMFR; //insert_object(d, pEmr->ihFont, _EMR_EXTCREATEFONTINDIRECTW, lpEMFR); break; } case _EMR_EXTTEXTOUTA: case _EMR_EXTTEXTOUTW: case _EMR_SMALLTEXTOUT: { //dbg_str << "\n"; //PU_EMREXTTEXTOUTW pEmr = (PU_EMREXTTEXTOUTW) lpEMFR; //PU_EMRSMALLTEXTOUT pEmrS = (PU_EMRSMALLTEXTOUT) lpEMFR; //double x1,y1; //int roff = sizeof(U_EMRSMALLTEXTOUT); //offset to the start of the variable fields, only used with _EMR_SMALLTEXTOUT //int cChars; //if(lpEMFR->iType==_EMR_SMALLTEXTOUT) //{ // x1 = pEmrS->Dest.x; // y1 = pEmrS->Dest.y; // cChars = pEmrS->cChars; // if(!(pEmrS->fuOptions & U_ETO_NO_RECT)) // { // roff += sizeof(OdWmfRectL); // } //} //else { // x1 = pEmr->emrtext.ptlReference.x; // y1 = pEmr->emrtext.ptlReference.y; // cChars = 0; //} //OdUInt32 fOptions = pEmr->emrtext.fOptions; //if (cur_ctx.textAlign & U_TA_UPDATECP) //{ // x1 = cur_ctx.cur.x; // y1 = cur_ctx.cur.y; //} //double x = pix_to_x_point(d, x1, y1); //double y = pix_to_y_point(d, x1, y1); //// Rotation issues are handled entirely in libTERE now //OdUInt32 *dup_wt = NULL; //if (lpEMFR->iType==_EMR_EXTTEXTOUTA) //{ // // These should be JUST ASCII, but they might not be... // // If it holds Utf-8 or plain ASCII the first call will succeed. // // If not, assume that it holds Latin1. // // If that fails then someting is really screwed up! // dup_wt = U_Utf8ToUtf32le((char *) pEmr + pEmr->emrtext.offString, pEmr->emrtext.nChars, NULL); // if(!dup_wt)dup_wt = U_Latin1ToUtf32le((char *) pEmr + pEmr->emrtext.offString, pEmr->emrtext.nChars, NULL); // if(!dup_wt)dup_wt = unknown_chars(pEmr->emrtext.nChars); //} //else if( lpEMFR->iType==_EMR_EXTTEXTOUTW) //{ // dup_wt = U_Utf16leToUtf32le((OdUInt16 *)((char *) pEmr + pEmr->emrtext.offString), pEmr->emrtext.nChars, NULL); // if(!dup_wt) // dup_wt = unknown_chars(pEmr->emrtext.nChars); //} //else //{ // // _EMR_SMALLTEXTOUT // if(pEmrS->fuOptions & U_ETO_SMALL_CHARS) // { // dup_wt = U_Utf8ToUtf32le((char *) pEmrS + roff, cChars, NULL); // } // else { // dup_wt = U_Utf16leToUtf32le((OdUInt16 *)((char *) pEmrS + roff), cChars, NULL); // } // if(!dup_wt) // dup_wt = unknown_chars(cChars); //} //msdepua(dup_wt); //convert everything in Microsoft's private use area. For Symbol, Wingdings, Dingbats //if(NonToUnicode(dup_wt, cur_ctx.font_name)) //{ // free(cur_ctx.font_name); // cur_ctx.font_name = strdup("Times New Roman"); //} //char *ansi_text; //ansi_text = (char *) U_Utf32leToUtf8((OdUInt32 *)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(*((OdUInt8 *)ansi_text) <= 0x1F) //{ // free(ansi_text); // ansi_text=NULL; //} //if (ansi_text) //{ // SVGOStringStream ts; // gchar *escaped_text = g_markup_escape_text(ansi_text, -1); // tsp.x = x*0.8; // TERE expects sizes in points. // tsp.y = y*0.8; // tsp.color.Red = cur_ctx.textColor.Red; // tsp.color.Green = cur_ctx.textColor.Green; // tsp.color.Blue = cur_ctx.textColor.Blue; // tsp.color.Reserved = 0; // switch(cur_ctx.style.font_style.value) // { // case SP_CSS_FONT_STYLE_OBLIQUE: // tsp.italics = FC_SLANT_OBLIQUE; break; // case SP_CSS_FONT_STYLE_ITALIC: // tsp.italics = FC_SLANT_ITALIC; break; // default: // case SP_CSS_FONT_STYLE_NORMAL: // tsp.italics = FC_SLANT_ROMAN; break; // } // switch(cur_ctx.style.font_weight.value) // { // case SP_CSS_FONT_WEIGHT_100: tsp.weight = FC_WEIGHT_THIN ; break; // case SP_CSS_FONT_WEIGHT_200: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break; // case SP_CSS_FONT_WEIGHT_300: tsp.weight = FC_WEIGHT_LIGHT ; break; // case SP_CSS_FONT_WEIGHT_400: tsp.weight = FC_WEIGHT_NORMAL ; break; // case SP_CSS_FONT_WEIGHT_500: tsp.weight = FC_WEIGHT_MEDIUM ; break; // case SP_CSS_FONT_WEIGHT_600: tsp.weight = FC_WEIGHT_SEMIBOLD ; break; // case SP_CSS_FONT_WEIGHT_700: tsp.weight = FC_WEIGHT_BOLD ; break; // case SP_CSS_FONT_WEIGHT_800: tsp.weight = FC_WEIGHT_EXTRABOLD ; break; // case SP_CSS_FONT_WEIGHT_900: tsp.weight = FC_WEIGHT_HEAVY ; break; // case SP_CSS_FONT_WEIGHT_NORMAL: tsp.weight = FC_WEIGHT_NORMAL ; break; // case SP_CSS_FONT_WEIGHT_BOLD: tsp.weight = FC_WEIGHT_BOLD ; break; // case SP_CSS_FONT_WEIGHT_LIGHTER: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break; // case SP_CSS_FONT_WEIGHT_BOLDER: tsp.weight = FC_WEIGHT_EXTRABOLD ; break; // default: tsp.weight = FC_WEIGHT_NORMAL ; break; // } // // EMF only supports two types of text decoration // tsp.decoration = TXTDECOR_NONE; // if(cur_ctx.style.text_decoration_line.underline){ tsp.decoration |= TXTDECOR_UNDER; } // if(cur_ctx.style.text_decoration_line.line_through){ tsp.decoration |= TXTDECOR_STRIKE;} // // EMF textalignment is a bit strange: 0x6 is center, 0x2 is right, 0x0 is left, the value 0x4 is also drawn left // tsp.taln = ((cur_ctx.textAlign & U_TA_CENTER) == U_TA_CENTER) ? ALICENTER : // (((cur_ctx.textAlign & U_TA_CENTER) == U_TA_LEFT) ? ALILEFT : // ALIRIGHT); // tsp.taln |= ((cur_ctx.textAlign & U_TA_BASEBIT) ? ALIBASE : // ((cur_ctx.textAlign & U_TA_BOTTOM) ? ALIBOT : // ALITOP)); // // language direction can be encoded two ways, U_TA_RTLREADING is preferred // if( (fOptions & U_ETO_RTLREADING) // || (cur_ctx.textAlign & U_TA_RTLREADING) ) // { // tsp.ldir = LDIR_RL; // } // else // { // tsp.ldir = LDIR_LR; // } // tsp.condensed = FC_WIDTH_NORMAL; // Not implemented well in libTERE (yet) // tsp.ori = cur_ctx.style.baseline_shift.value; // For now orientation is always the same as escapement // tsp.ori += 180.0 * current_rotation(d)/ M_PI; // radians to degrees // tsp.string = (OdUInt8 *) U_strdup(escaped_text); // this will be free'd much later at a trinfo_clear(). // tsp.fs = cur_ctx.style.font_size.computed * 0.8; // Font size in points // char *fontspec = TR_construct_fontspec(&tsp, cur_ctx.font_name); // tsp.fi_idx = ftinfo_load_fontname(d->tri->fti,fontspec); // free(fontspec); // // when font name includes narrow it may not be set to "condensed". Narrow fonts do not work well anyway though // // as the metrics from fontconfig may not match, or the font may not be present. // if(0<= TR_findcasesub(cur_ctx.font_name, (char *) "Narrow")) // { // tsp.co=1; // } // else // { // tsp.co=0; // } // int status = trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ori is actually escapement // if(status==-1) // { // // change of escapement, emit what we have and reset // TR_layout_analyze(d->tri); // if (cur_ctx.clip_id) // { // SVGOStringStream tmp_clip; // tmp_clip << "\n"; // d->outsvg += tmp_clip.str().c_str(); // } // TR_layout_2_svg(d->tri); // ts << d->tri->out; // d->outsvg += ts.str().c_str(); // d->tri = trinfo_clear(d->tri); // (void) trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ignore return status, it must work // if (cur_ctx.clip_id) // { // d->outsvg += "\n\n"; // } // } // g_free(escaped_text); // free(ansi_text); //} break; } case _EMR_POLYBEZIER16: { //dbg_str << "\n"; //PU_EMRPOLYBEZIER16 pEmr = (PU_EMRPOLYBEZIER16) lpEMFR; //OdWmfPoint* apts = (OdWmfPoint*) pEmr->apts; // Bug in MinGW wingdi.h ? //OdUInt32 i,j; //if (pEmr->cpts<4) // break; //d->mask |= emr_mask; //tmp_str << "\n\tM " << pix_to_xy( d, apts[0].x, apts[0].y ) << " "; //for (i=1; icpts; ) //{ // tmp_str << "\n\tC "; // for (j=0; j<3 && icpts; j++,i++) // { // tmp_str << pix_to_xy( d, apts[i].x, apts[i].y ) << " "; // } //} //tmp_path << tmp_str.str().c_str(); break; } case _EMR_POLYGON16: { ////dbg_str << "\n"; //PU_EMRPOLYGON16 pEmr = (PU_EMRPOLYGON16) lpEMFR; //OdWmfPoint* apts = (OdWmfPoint*) pEmr->apts; // Bug in MinGW wingdi.h ? //SVGOStringStream tmp_poly; //unsigned int i; //unsigned int first = 0; //d->mask |= emr_mask; //// skip the first point? //tmp_poly << "\n\tM " << pix_to_xy( d, apts[first].x, apts[first].y ) << " "; //for (i=first+1; icpts; i++) //{ // tmp_poly << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y ) << " "; //} //tmp_path << tmp_poly.str().c_str(); //tmp_path << "\n\tz"; //d->mask |= U_DRAW_CLOSED; break; } case _EMR_POLYLINE16: { ////dbg_str << "\n"; //PU_EMRPOLYLINE16 pEmr = (PU_EMRPOLYLINE16) lpEMFR; //OdWmfPoint* apts = (OdWmfPoint*) pEmr->apts; // Bug in MinGW wingdi.h ? //OdUInt32 i; //if (pEmr->cpts<2) // break; //d->mask |= emr_mask; //tmp_str << "\n\tM " << pix_to_xy( d, apts[0].x, apts[0].y ) << " "; //for (i=1; icpts; i++) { // tmp_str << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y ) << " "; //} //tmp_path << tmp_str.str().c_str(); break; } case _EMR_POLYBEZIERTO16: { ////dbg_str << "\n"; //PU_EMRPOLYBEZIERTO16 pEmr = (PU_EMRPOLYBEZIERTO16) lpEMFR; //OdWmfPoint* apts = (OdWmfPoint*) pEmr->apts; // Bug in MinGW wingdi.h ? //OdUInt32 i,j; //d->mask |= emr_mask; //for (i=0; icpts;) //{ // tmp_path << "\n\tC "; // for (j=0; j<3 && icpts; j++,i++) // { // tmp_path << pix_to_xy( d, apts[i].x, apts[i].y) << " "; // } //} break; } case _EMR_POLYLINETO16: { ////dbg_str << "\n"; //PU_EMRPOLYLINETO16 pEmr = (PU_EMRPOLYLINETO16) lpEMFR; //OdWmfPoint* apts = (OdWmfPoint*) pEmr->apts; // Bug in MinGW wingdi.h ? //OdUInt32 i; //d->mask |= emr_mask; //for (i=0; icpts;i++) //{ // tmp_path << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y) << " "; //} break; } case _EMR_POLYPOLYLINE16: case _EMR_POLYPOLYGON16: { //if (lpEMFR->iType == _EMR_POLYPOLYLINE16) // dbg_str << "\n"; //if (lpEMFR->iType == _EMR_POLYPOLYGON16) // dbg_str << "\n"; //PU_EMRPOLYPOLYGON16 pEmr = (PU_EMRPOLYPOLYGON16) lpEMFR; //unsigned int n, i, j; //d->mask |= emr_mask; //OdWmfPoint* apts = (OdWmfPoint*) &pEmr->aPolyCounts[pEmr->nPolys]; //i = 0; //for (n=0; nnPolys && icpts; n++) //{ // SVGOStringStream poly_path; // poly_path << "\n\tM " << pix_to_xy( d, apts[i].x, apts[i].y) << " "; // i++; // for (j=1; jaPolyCounts[n] && icpts; j++) // { // poly_path << "\n\tL " << pix_to_xy( d, apts[i].x, apts[i].y) << " "; // i++; // } // tmp_str << poly_path.str().c_str(); // if (lpEMFR->iType == _EMR_POLYPOLYGON16) // tmp_str << " z"; // tmp_str << " \n"; //} //tmp_path << tmp_str.str().c_str(); break; } case _EMR_POLYDRAW16: //dbg_str << "\n"; break; case _EMR_CREATEMONOBRUSH: { ////dbg_str << "\n"; //PU_EMRCREATEMONOBRUSH pEmr = (PU_EMRCREATEMONOBRUSH) lpEMFR; //insert_object(d, pEmr->ihBrush, _EMR_CREATEMONOBRUSH, lpEMFR); break; } case _EMR_CREATEDIBPATTERNBRUSHPT: { ////dbg_str << "\n"; //PU_EMRCREATEDIBPATTERNBRUSHPT pEmr = (PU_EMRCREATEDIBPATTERNBRUSHPT) lpEMFR; //insert_object(d, pEmr->ihBrush, _EMR_CREATEDIBPATTERNBRUSHPT, lpEMFR); break; } case _EMR_EXTCREATEPEN: { ////dbg_str << "\n"; //PU_EMREXTCREATEPEN pEmr = (PU_EMREXTCREATEPEN) lpEMFR; //insert_object(d, pEmr->ihPen, _EMR_EXTCREATEPEN, lpEMFR); break; } case _EMR_POLYTEXTOUTA: //dbg_str << "\n"; break; case _EMR_POLYTEXTOUTW: //dbg_str << "\n"; break; case _EMR_SETICMMODE: { ////dbg_str << "\n"; //OdEmdSetIcmMode* pEmr = (OdEmdSetIcmMode*) lpEMFR; //ICMmode= pEmr->iMode; break; } case _EMR_CREATECOLORSPACE: //dbg_str << "\n"; break; case _EMR_SETCOLORSPACE: //dbg_str << "\n"; break; case _EMR_DELETECOLORSPACE: //dbg_str << "\n"; break; case _EMR_GLSRECORD: //dbg_str << "\n"; break; case _EMR_GLSBOUNDEDRECORD: //dbg_str << "\n"; break; case _EMR_PIXELFORMAT: //dbg_str << "\n"; break; case _EMR_DRAWESCAPE: //dbg_str << "\n"; break; case _EMR_EXTESCAPE: //dbg_str << "\n"; break; case _EMR_UNDEF107: //dbg_str << "\n"; break; // _EMR_SMALLTEXTOUT is handled with _EMR_EXTTEXTOUTA/W above case _EMR_FORCEUFIMAPPING: //dbg_str << "\n"; break; case _EMR_NAMEDESCAPE: //dbg_str << "\n"; break; case _EMR_COLORCORRECTPALETTE: //dbg_str << "\n"; break; case _EMR_SETICMPROFILEA: //dbg_str << "\n"; break; case _EMR_SETICMPROFILEW: //dbg_str << "\n"; break; case _EMR_ALPHABLEND: //dbg_str << "\n"; break; case _EMR_SETLAYOUT: //dbg_str << "\n"; break; case _EMR_TRANSPARENTBLT: //dbg_str << "\n"; break; case _EMR_UNDEF117: //dbg_str << "\n"; break; case _EMR_GRADIENTFILL: { // Gradient fill is doable for rectangles because those correspond to linear gradients. However, // the general case for the triangle fill, with a different color in each corner of the triangle, // has no SVG equivalent and cannot be easily emulated with SVG gradients. So the linear gradient // is implemented, and the triangle fill just paints with the color of the first corner. // // This record can hold a series of gradients so we are forced to add path elements directly here, // it cannot wait for the top of the main loop. Any existing path is erased. ////dbg_str << "\n"; //PU_EMRGRADIENTFILL pEmr = (PU_EMRGRADIENTFILL) lpEMFR; //int nV = pEmr->nTriVert; // Number of TriVertex objects //int nG = pEmr->nGradObj; // Number of gradient triangle/rectangle objects //U_TRIVERTEX *tv = (U_TRIVERTEX *)(((char *)lpEMFR) + sizeof(U_EMRGRADIENTFILL)); //if( pEmr->ulMode == U_GRADIENT_FILL_RECT_H || pEmr->ulMode == U_GRADIENT_FILL_RECT_V) //{ // SVGOStringStream tmp_rectangle; // int i,fill_idx; // U_GRADIENT4 *rcs = (U_GRADIENT4 *)(((char *)lpEMFR) + sizeof(U_EMRGRADIENTFILL) + sizeof(U_TRIVERTEX)*nV); // for(i=0;iulMode, tv[rcs[i].UpperLeft], tv[rcs[i].LowerRight]); // tmp_rectangle << "\n\tM " << pix_to_xy( d, tv[rcs[i].UpperLeft ].x , tv[rcs[i].UpperLeft ].y ) << " "; // tmp_rectangle << "\n\tL " << pix_to_xy( d, tv[rcs[i].LowerRight].x , tv[rcs[i].UpperLeft ].y ) << " "; // tmp_rectangle << "\n\tL " << pix_to_xy( d, tv[rcs[i].LowerRight].x , tv[rcs[i].LowerRight].y ) << " "; // tmp_rectangle << "\n\tL " << pix_to_xy( d, tv[rcs[i].UpperLeft ].x , tv[rcs[i].LowerRight].y ) << " "; // tmp_rectangle << "\n\tz\""; // tmp_rectangle << "\n\tstyle=\"stroke:none;fill:url(#"; // tmp_rectangle << d->gradients.strings[fill_idx]; // tmp_rectangle << ");\"\n"; // if (cur_ctx.clip_id) // { // tmp_rectangle << "\tclip-path=\"url(#clipEmfPath" << cur_ctx.clip_id << ")\"\n"; // } // tmp_rectangle << "/>\n"; // } // d->outsvg += tmp_rectangle.str().c_str(); //} //else if(pEmr->ulMode == U_GRADIENT_FILL_TRIANGLE) //{ // SVGOStringStream tmp_triangle; // char tmpcolor[8]; // int i; // U_GRADIENT3 *tris = (U_GRADIENT3 *)(((char *)lpEMFR) + sizeof(U_EMRGRADIENTFILL) + sizeof(U_TRIVERTEX)*nV); // for(i=0;i\n"; // } // d->outsvg += tmp_triangle.str().c_str(); //} //d->path = ""; //// if it is anything else the record is bogus, so ignore it break; } case _EMR_SETLINKEDUFIS: //dbg_str << "\n"; break; case _EMR_SETTEXTJUSTIFICATION: //dbg_str << "\n"; break; case _EMR_COLORMATCHTOTARGETW: //dbg_str << "\n"; break; case _EMR_CREATECOLORSPACEW: //dbg_str << "\n"; break; default: //dbg_str << "\n"; break; } //end of switch //// When testing, uncomment the following to place a comment for each processed EMR record in the SVG //// d->outsvg += dbg_str.str().c_str(); //d->outsvg += tmp_outsvg.str().c_str(); //d->path += tmp_path.str().c_str(); } //end of while // see here collected types of ODA_ASSERT_VAR(OdArray types;) // When testing, uncomment the following to show the final SVG derived from the EMF // std::cout << d->outsvg << std::endl; getEmfProperties((OdUInt32)_EMR_INVALID); // force the release of the lookup table memory, returned value is irrelevant return(file_status); } //void Emf::free_emf_strings(EMF_STRINGS name) //{ // if(name.count) // { // for(int i=0; i< name.count; i++) // { // free(name.strings[i]); // } // free(name.strings); // } // name.count = 0; // name.size = 0; //} //SPDocument* Emf::open(Inkscape::Extension::Input*, //mod, // const gchar *uri ) //{ // if (uri == NULL) // { // return NULL; // } // // EMF_CALLBACK_DATA d; // // d.n_obj = 0; //these might not be set otherwise if the input file is corrupt // d.emf_obj = NULL; // d.dc[0].font_name = strdup("Arial"); // Default font, set only on lowest level, it copies up from there EMF spec says device can pick whatever it wants // // // set up the size default for patterns in defs. This might not be referenced if there are no patterns defined in the drawing. // // d.defs += "\n"; // d.defs += " \n"; // d.defs += " \n"; // // // size_t length; // char *contents; // if(emf_readdata(uri, &contents, &length))return(NULL); // // d.pDesc = NULL; // // // set up the text reassembly system // if(!(d.tri = trinfo_init(NULL)))return(NULL); // (void) trinfo_load_ft_opts(d.tri, 1, // FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP, // FT_KERNING_UNSCALED); // // int good = emfMetaFileProc(contents,length, &d); // free(contents); // // if (d.pDesc){ free( d.pDesc ); } // //// std::cout << "SVG Output: " << std::endl << d.outsvg << std::endl; // // SPDocument *doc = NULL; // if (good) { // doc = SPDocument::createNewDocFromMem(d.outsvg.c_str(), strlen(d.outsvg.c_str()), TRUE); // } // // free_emf_strings(d.hatches); // free_emf_strings(d.images); // free_emf_strings(d.gradients); // free_emf_strings(d.clips); // // if (d.emf_obj) { // int i; // for (i=0; i\n" // "" N_("EMF Input") "\n" // "org.inkscape.input.emf\n" // "\n" // ".emf\n" // "image/x-emf\n" // "" N_("Enhanced Metafiles (*.emf)") "\n" // "" N_("Enhanced Metafiles") "\n" // "org.inkscape.output.emf\n" // "\n" // "", new Emf()); // // // EMF out // Inkscape::Extension::build_from_mem( // "\n" // "" N_("EMF Output") "\n" // "org.inkscape.output.emf\n" // "true\n" // "true\n" // "true\n" // "true\n" // "false\n" // "false\n" // "false\n" // "false\n" // "false\n" // "false\n" // "false\n" // "\n" // ".emf\n" // "image/x-emf\n" // "" N_("Enhanced Metafile (*.emf)") "\n" // "" N_("Enhanced Metafile") "\n" // "\n" // "", new Emf()); // // return; //} //} } } // namespace Inkscape, Extension, Implementation /////////////////////////////////////////////////////////////////////////////// // // see readwmf.c & reademf.c // \fn wmfMetaFilePrintProc(char *contents, unsigned int length, PWMF_WORKING_DATA lpData) // \returns 0 on normal exit, -1 on error // \param contents binary contents of an WMF file // \param length length in bytes of contents size_t wmfMetaFilePrintProc(char *contents, size_t length) { OdUInt32 result = 0; int OK = 1; int recnum = 0; char* blimit = contents + length; OdUInt32 off = (OdUInt32) getWmfHeaderPrint(contents, blimit); while (OK) { result = getWmfOneRecPrint(contents, blimit, recnum, off); if (result == (OdUInt32)-1) { printf("ABORTING on invalid record - corrupt file?\n"); OK = 0; } else if (!result) { OK = 0; } else { off += result; recnum++; } } //end of while return (size_t) result; } size_t emfMetaFilePrintProc(char *contents, size_t length) { OdUInt32 off = 0; OdUInt32 result; int OK = 1; int recnum = 0; OdEmfMetaRecord* pEmr; char *blimit; blimit = contents + length; while (OK) { if (off >= length) { //normally should exit from while after EMREOF sets OK to false, this is most likely a corrupt EMF printf("WARNING: record claims to extend beyond the end of the EMF file\n"); return(0); } pEmr = (OdEmfMetaRecord*)(contents + off); if (!recnum && (pEmr->iType != _EMR_HEADER)) { printf("WARNING: EMF file does not begin with an _EMR_HEADER record\n"); } result = (OdUInt32) getEmfOneRecPrint(contents, blimit, recnum, (int) off); if (result == (OdUInt32) -1) { printf("ABORTING on invalid record - corrupt file?\n"); OK = 0; } else if (!result) { OK = 0; } else { off += result; recnum++; } } //end of while return 1; } /////////////////////////////////////////////////////////////////////////////// void OdMetafileParser::select_brush(PWMF_CALLBACK_DATA d, int index) { if (!m_pDestGeom) return; if (index < 0 || index >= d->n_obj) return; const char* record = d->wmf_obj[index].record; if(!record) return; WMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; cur_ctx.active_brush = index; const char* membrush; OdWmfRecord* pRec = (OdWmfRecord*) record; OdUInt8 iType = *(OdUInt8 *)(record + offsetof(OdWmfRecord, iType)); ODA_ASSERT_ONCE_X(WMF, indexToWmr(iType) == _META_CREATEBRUSHINDIRECT); // TODO if (indexToWmr(iType) == _META_CREATEBRUSHINDIRECT) { getWmfCreateBrushIndirect(record, &membrush); OdWmfLogBrush lb; // OdWmfBrush lb; memcpy(&lb, membrush, OdWmfLogBrushSize); // memcpy(&lb, membrush, OdWmfBrushSize); ODA_ASSERT_ONCE_X(WMF, lb.Style == _BS_SOLID); // TODO if (lb.Style == _BS_SOLID) { cur_ctx.style.fill_color.setRGB(ODGETRED(lb.Color), ODGETGREEN(lb.Color), ODGETBLUE(lb.Color)); cur_ctx.fill_mode = DRAW_PAINT; cur_ctx.fill_set = true; } //else if(lb.Style == U_BS_HATCHED) //{ // cur_ctx.fill_idx = add_hatch(d, lb.Hatch, lb.Color); // cur_ctx.fill_recidx = index; // used if the hatch needs to be redone due to bkMode, textmode, etc. changes // cur_ctx.fill_mode = DRAW_PATTERN; // cur_ctx.fill_set = true; //} //else if(lb.Style == U_BS_NULL) //{ // cur_ctx.fill_mode = DRAW_PAINT; // set it to something // cur_ctx.fill_set = false; //} } else if(indexToWmr(iType) == _META_DIBCREATEPATTERNBRUSH) { ODA_ASSERT(true); // brk // TODO // OdUInt32 tidx; // OdUInt16 Style; // OdUInt16 cUsage; // const char *Bm16h; // Pointer to Bitmap16 header (px follows) // const char *dib; // Pointer to DIB // (void) getWmfDibCreatePatternBrush(record, &Style, &cUsage, &Bm16h, &dib); // // Bm16 not handled yet // if (dib || Bm16h) // { // if (dib) // tidx = add_dib_image(d, dib, cUsage); // else if (Bm16h) // { // OdWmfBitmap Bm16; // const char *px; // memcpy(&Bm16, Bm16h, U_SIZE_BITMAP16); // px = Bm16h + U_SIZE_BITMAP16; // tidx = add_bm16_image(d, Bm16, px); // } // if (tidx == 0xFFFFFFFF) // Problem with the image, for instance, an unsupported bitmap16 type // { // cur_ctx.style.fill_color.setRGB(cur_ctx.textColor.Red, cur_ctx.textColor.Green, cur_ctx.textColor.Blue); // cur_ctx.fill_mode = DRAW_PAINT; // } // else // { // cur_ctx.fill_idx = tidx; // cur_ctx.fill_mode = DRAW_IMAGE; // } // cur_ctx.fill_set = true; // } // else // { // g_message("Please send WMF file to developers - select_brush _META_DIBCREATEPATTERNBRUSH not bm16 or dib, not handled"); // } } } void OdMetafileParser::select_font(PWMF_CALLBACK_DATA d, int index) { if (!m_pDestGeom) return; if (index < 0 || index >= d->n_obj) return; const char* record = d->wmf_obj[index].record; if (!record) return; const char* memfont = NULL; getWmfCreateFontIndirect(record, &memfont); OdWmfFont font; memcpy(&font,memfont, OdWmfFontCoreSize); //make sure it is in a properly aligned structure before touching it const char* facename = memfont + OdWmfFontCoreSize; double font_size = pix_to_abs_size(d, font.Height); // 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->D2Pscale[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 .03125 off, which is unlikely to be a problem. font_size = round(20.0 * 0.8 * font_size) / (20.0 * 0.8); d->dc[d->level].active_font = index; // The logfont information always starts with a U_LOGFONT structure but the U_WMRCREATEFONTINDIRECT // is defined as U_LOGFONT_PANOSE so it can handle one of those if that is actually present. Currently only logfont // is supported, and the remainder, it it really is a U_LOGFONT_PANOSE record, is ignored int cur_level = d->level; d->level = d->wmf_obj[index].level; d->level = cur_level; WMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; cur_ctx.style.text_style = new OdGiTextStyle(); //OdFont* pFont = cur_ctx.style.text_style->getFont(); //cur_ctx.style.font_weight.value = // font.Weight == U_FW_THIN ? SP_CSS_FONT_WEIGHT_100 : // font.Weight == U_FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_200 : // font.Weight == U_FW_LIGHT ? SP_CSS_FONT_WEIGHT_300 : // font.Weight == U_FW_NORMAL ? SP_CSS_FONT_WEIGHT_400 : // font.Weight == U_FW_MEDIUM ? SP_CSS_FONT_WEIGHT_500 : // font.Weight == U_FW_SEMIBOLD ? SP_CSS_FONT_WEIGHT_600 : // font.Weight == U_FW_BOLD ? SP_CSS_FONT_WEIGHT_700 : // font.Weight == U_FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_800 : // font.Weight == U_FW_HEAVY ? SP_CSS_FONT_WEIGHT_900 : // font.Weight == U_FW_NORMAL ? SP_CSS_FONT_WEIGHT_NORMAL : // font.Weight == U_FW_BOLD ? SP_CSS_FONT_WEIGHT_BOLD : // font.Weight == U_FW_EXTRALIGHT ? SP_CSS_FONT_WEIGHT_LIGHTER : // font.Weight == U_FW_EXTRABOLD ? SP_CSS_FONT_WEIGHT_BOLDER : // U_FW_NORMAL; //cur_ctx.style.font_style.value = (font.Italic ? SP_CSS_FONT_STYLE_ITALIC : SP_CSS_FONT_STYLE_NORMAL); //cur_ctx.style.text_decoration.underline = font.Underline; //cur_ctx.style.text_decoration.line_through = font.StrikeOut; // malformed WMF with empty filename may exist, ignore font change if encountered if(cur_ctx.font_name)free(cur_ctx.font_name); if(*facename){ cur_ctx.font_name = strdup(facename); } else { // Malformed WMF might specify an empty font name cur_ctx.font_name = strdup("Arial"); // Default font, WMF spec says device can pick whatever it wants } //cur_ctx.style.baseline_shift.value = round((double)((font.Escapement + 3600) % 3600) / 10.0); // use baseline_shift instead of text_transform to avoid overflow int charset = font.CharSet, pitchAndFamily = font.PitchAndFamily; double obliqueAngle = 0.0, xScale = 1.0; bool isBold = false, isItalic = (font.Italic != 0), isBackward = false, isUpsideDown = false, isVertical = (font.Orientation == 900), isOverlined = (font.StrikeOut != 0), isUnderlined = (font.Underline != 0); switch (font.Weight) { case _FW_SEMIBOLD: //!< Semibold // case U_FW_DEMIBOLD: //!< Demibold case _FW_BOLD: //!< Bold case _FW_EXTRABOLD: //!< Extrabold // case U_FW_ULTRABOLD: //!< Ultrabold case _FW_HEAVY: //!< Heavy // case U_FW_BLACK: //!< Black isBold = true; break; } //cur_ctx.style.text_style->set(cur_ctx.font_name, // OdString::kEmpty, // bigFontName, // 100.0, // textSize // xScale, obliqueAngle, // 1.0, //trackingPercent // isBackward, isUpsideDown, isVertical, isOverlined, isUnderlined); cur_ctx.style.text_style->setFont(cur_ctx.font_name, isBold, isItalic, charset, pitchAndFamily); //ODA_ASSERT_ONCE_X(WMF, !cur_ctx.style.text_style->getFont()); // cur_ctx.style.text_style = OdGiTextStyle(); cur_ctx.style.text_style->setTextSize(font_size); // cur_ctx.style.font_size.computed = font_size; //cur_ctx.style.text_style->setTextSize(font_size / 20.0); // test cur_ctx.style.text_style->loadStyleRec(NULL); //OdTtfDescriptor& ttfdescr = cur_ctx.style.text_style->ttfdescriptor(); double size = cur_ctx.style.text_style->textSize(); ODA_ASSERT_ONCE_X(WMF, OdEqual(size, font_size)); ///if (false) { double currentTextHeight = size; // = font.height().height(); if (false) { // recalculating text height, because in ACAD text height == 'A' height double ascentRatio = (cur_ctx.style.text_style->getFont()->getHeight() - cur_ctx.style.text_style->getFont()->getInternalLeading()) / cur_ctx.style.text_style->getFont()->getAbove(); currentTextHeight /= ascentRatio; } currentTextHeight /= 0.8; //*** //pText->m_textStyle.setTrackingPercent() cur_ctx.style.text_style->setTextSize(currentTextHeight); } //----- //cur_ctx.style.text_style->set(sFontName, // OdString::kEmpty, // 100, // textSize // xScale, oblique, // 1., //trackingPercent // isBackward, isUpsideDown, isVertical, isOverlined, isUnderlined); //cur_ctx.style.text_style->setIsShape(false); //cur_ctx.style.text_style->setFont(sFontName, // font.style().bold() != 0, font.style().italic() != 0, // font.charset().charset(), // int(font.pitch().pitch()) | int(font.family().family())); //cur_ctx.style.text_style->loadStyleRec(pRxDb); //// moved upper //double currentTextHeight = font.height().height(); //// recalculating text height, because in ACAD text height == 'A' height //double ascentRatio = (cur_ctx.style.text_style->getFont()->getHeight() - cur_ctx.style.text_style->getFont()->getInternalLeading()) // / cur_ctx.style.text_style->getFont()->getAbove(); //currentTextHeight /= ascentRatio; ////pText->m_textStyle.setTrackingPercent() //cur_ctx.style.text_style->setTextSize(currentTextHeight); } void OdMetafileParser::select_pen(PWMF_CALLBACK_DATA d, int index) { //if (!m_pDestGeom) // return; ODA_ASSERT(true); // brk } // \brief store SVG for an image given the pixmap and various coordinate information // \param d // \param Bm16 core Bitmap16 header // \param px pointer to Bitmap16 image data // \param dx (double) destination x in inkscape pixels // \param dy (double) destination y in inkscape pixels // \param dw (double) destination width in inkscape pixels // \param dh (double) destination height in inkscape pixels // \param sx (int) source x in src image pixels // \param sy (int) source y in src image pixels // \param iUsage void OdMetafileParser::common_bm16_to_image(PWMF_CALLBACK_DATA d, OdWmfBitmap Bm16, const char *px, double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh) { ODA_ASSERT_ONCE(m_pRasterImage.isNull()); OdRxRasterServicesPtr pRasSvcs = ::odrxDynamicLinker()->loadApp(RX_RASTER_SERVICES_APPNAME); if (pRasSvcs.get()) { ODA_ASSERT(true); // brk //m_pRasterImage = pRasSvcs->loadRasterImage( // OdFlatMemStream::createNew(dataImageNative.asArrayPtr(), dataImageNative.size())); } // SVGOStringStream tmp_image; // // tmp_image << " y=\"" << dy << "\"\n x=\"" << dx <<"\"\n "; // // // The image ID is filled in much later when tmp_image is converted // // MEMPNG mempng; // PNG in memory comes back in this // mempng.buffer = NULL; // // char *rgba_px = NULL; // RGBA pixels // char *sub_px = NULL; // RGBA pixels, subarray // const OdWmfQuad *ct = NULL; // color table // int32_t width, height, colortype, numCt, invert; // // numCt = 0; // width = Bm16.Width; // bitmap width in pixels. // height = Bm16.Height; // bitmap height in scan lines. // colortype = Bm16.BitsPixel; // seems to be BitCount Enumeration // invert = 0; // // if(sw == 0 || sh == 0){ // sw = width; // sh = height; // } // // if(colortype < 16)return; // these would need a colortable if they were a dib, no idea what bm16 is supposed to do instead. // if(!DIB_to_RGBA( // This is not really a dib, but close enough... // px, // DIB pixel array // ct, // DIB color table (always NULL here) // numCt, // DIB color table number of entries (always 0) // &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 // colortype, // DIB BitCount Enumeration // numCt, // Color table used if not 0 // 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 // sx,sy, // 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 // sub_px // ); // free(sub_px); // } // if(mempng.buffer){ // tmp_image << " xlink:href=\"data:image/png;base64,"; // gchar *base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size ); // free(mempng.buffer); // tmp_image << base64String; // g_free(base64String); // } // else { // tmp_image << " xlink:href=\"data:image/png;base64,"; // // insert a random 3x4 blotch otherwise // tmp_image << "iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII="; // } // // tmp_image << "\"\n height=\"" << dh << "\"\n width=\"" << dw << "\"\n"; // // tmp_image << " transform=" << current_matrix(d, 0.0, 0.0, 0); // returns an identity matrix, no offsets. // *(d->outsvg) += "\n\t outsvg) += tmp_image.str().c_str(); // // *(d->outsvg) += "/> \n"; // *(d->path) = ""; } // \brief store SVG for an image given the pixmap and various coordinate information // \param d // \param dib packed DIB in memory // \param dx (double) destination x in inkscape pixels // \param dy (double) destination y in inkscape pixels // \param dw (double) destination width in inkscape pixels // \param dh (double) destination height in inkscape pixels // \param sx (int) source x in src image pixels // \param sy (int) source y in src image pixels // \param iUsage void OdMetafileParser::common_dib_to_image(PWMF_CALLBACK_DATA d, const char *dib, double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh, OdUInt32 iUsage) { ODA_ASSERT_ONCE(m_pRasterImage.isNull()); OdRxRasterServicesPtr pRasSvcs = ::odrxDynamicLinker()->loadApp(RX_RASTER_SERVICES_APPNAME); if (pRasSvcs.get()) { OdStreamBufPtr pStream = createBitmapByDib(//int bpp = 1; // bytes per pixel // int format, (const unsigned char *) dib, int(nSize) - int(dib - contents), // dib sw, sh); m_pRasterImage = pRasSvcs->loadRasterImage(pStream); ODA_ASSERT_ONCE(m_pRasterImage.get()); if (m_pDestGeom && m_pRasterImage.get()) m_pDestGeom->rasterImageProc(m_origin, m_u / (double)m_pRasterImage->pixelWidth(), m_v / (double)m_pRasterImage->pixelHeight(), m_pRasterImage.get(), 0, 0, !m_isExport); } } // \fn store SVG for an image given the pixmap and various coordinate information // \param d // \param pEmr // \param dx (double) destination x in inkscape pixels // \param dy (double) destination y in inkscape pixels // \param dw (double) destination width in inkscape pixels // \param dh (double) destination height in inkscape pixels // \param sx (int) source x in src image pixels // \param sy (int) source y in src image pixels // \param iUsage // \param offBits // \param cbBits // \param offBmi // \param cbBmi void OdMetafileParser::common_image_extraction(PEMF_CALLBACK_DATA d, void *pEmr, double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh, OdUInt32 iUsage, OdUInt32 offBits, OdUInt32 cbBits, OdUInt32 offBmi, OdUInt32 cbBmi) { //SVGOStringStream tmp_image; int dibparams = _BI_UNKNOWN; // type of image not yet determined //tmp_image << "\n\t dc[d->level].clip_id) //{ // tmp_image << "\tclip-path=\"url(#clipEmfPath" << d->dc[d->level].clip_id << ")\"\n"; //} //tmp_image << " y=\"" << dy << "\"\n x=\"" << dx <<"\"\n "; // //MEMPNG mempng; // PNG in memory comes back in this //mempng.buffer = NULL; char *rgba_px = NULL; // RGBA pixels char *sub_px = NULL; // RGBA pixels, subarray const char *px = NULL; // DIB pixels const OdWmfQuad *ct = NULL; // DIB color table OdUInt32 width, height, colortype, numCt, invert; // if needed these values will be set in get_DIB_params if (cbBits && cbBmi && (iUsage == _DIB_RGB_COLORS)) { // next call returns pointers and values, but allocates no memory dibparams = getEmfDibParams((const char *)pEmr, offBits, offBmi, &px, &ct, &numCt, &width, &height, &colortype, &invert); if(dibparams == _BI_RGB) { if(sw == 0 || sh == 0) { sw = width; sh = height; } ODA_ASSERT_ONCE(m_pRasterImage.isNull()); OdRxRasterServicesPtr pRasSvcs = ::odrxDynamicLinker()->loadApp(RX_RASTER_SERVICES_APPNAME); if (pRasSvcs.get()) { const unsigned char* data = (const unsigned char*)pEmr + offBmi; int dataSize = int((contents + off) - (const char*) data); // off was already shifted for text type OdStreamBufPtr pStream = createBitmapByDib(data, dataSize, sw, sh); m_pRasterImage = pRasSvcs->loadRasterImage(pStream); ODA_ASSERT_ONCE(m_pRasterImage.get()); if (m_pDestGeom && m_pRasterImage.get()) m_pDestGeom->rasterImageProc(m_origin, m_u / (double)m_pRasterImage->pixelWidth(), m_v / (double)m_pRasterImage->pixelHeight(), m_pRasterImage.get(), 0, 0, !m_isExport); } //if(!DIB_to_RGBA( // px, // DIB pixel array // 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 // colortype, // DIB BitCount Enumeration // numCt, // Color table used if not 0 // invert // If DIB rows are in opposite order from RGBA rows //)) //{ //sub_px = RGBA_to_RGBA( // returns either a subset (side effect: frees rgba_px) or NULL (for subset == entire image) // rgba_px, // full pixel array from DIB // width, // Width of pixel array // height, // Height of pixel array // sx,sy, // 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 // sub_px //); //free(sub_px); //} } } //gchar *base64String=NULL; //if(dibparams == U_BI_JPEG) //{ // // image was binary jpg in source file // tmp_image << " xlink:href=\"data:image/jpeg;base64,"; // base64String = g_base64_encode((guchar*) px, numCt ); //} //else if(dibparams==U_BI_PNG) //{ // // image was binary png in source file // tmp_image << " xlink:href=\"data:image/png;base64,"; // base64String = g_base64_encode((guchar*) px, numCt ); //} //else if(mempng.buffer) //{ // // image was DIB in source file, converted to png in this routine // tmp_image << " xlink:href=\"data:image/png;base64,"; // base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size ); // free(mempng.buffer); //} //else //{ // // unknown or unsupported image type or failed conversion, insert the common bad image picture // tmp_image << " xlink:href=\"data:image/png;base64,"; // base64String = bad_image_png(); //} //tmp_image << base64String; //g_free(base64String); // //tmp_image << "\"\n height=\"" << dh << "\"\n width=\"" << dw << "\"\n"; // //tmp_image << " transform=" << current_matrix(d, dx, dy, 1); // calculate appropriate offset //tmp_image << " preserveAspectRatio=\"none\"\n"; //tmp_image << "/> \n"; // //d->outsvg += tmp_image.str().c_str(); //d->path = ""; } // \param d // \param dx (double) destination x in inkscape pixels // \param dy (double) destination y in inkscape pixels // \param dw (double) destination width in inkscape pixels // \param dh (double) destination height in inkscape pixels bool OdMetafileParser::hasDrawCtx() { if (!m_pDestGeom || !m_pContext || m_regenType == kOdGiForExtents) return false; return true; } void OdMetafileParser::rectangle_clip(PWMF_CALLBACK_DATA d, double dx, double dy, double dw, double dh) { if (!hasDrawCtx() || OdZero(dw) || OdZero(dh)) return; WMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; // TODO } void OdMetafileParser::rectangle_brush(PWMF_CALLBACK_DATA d, double dx, double dy, double dw, double dh) { if (!hasDrawCtx() || OdZero(dw) || OdZero(dh)) return; ODA_ASSERT_ONCE_X(WMF, !OdZero(m_u.length()) && !OdZero(m_v.length())); WMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; OdGiSubEntityTraits& traits = m_pContext->subEntityTraits(); OdGiFillType svFillType = traits.fillType(); // Store previous if (svFillType != kOdGiFillAlways) traits.setFillType(kOdGiFillAlways); // Modify //OdUInt32 svDrawFlags = traits.drawFlags(); //if (!GETBIT(svDrawFlags, OdGiSubEntityTraits::kDrawSolidFill)) // traits.setDrawFlags(svDrawFlags | OdGiSubEntityTraits::kDrawSolidFill); // TODO? cur_ctx.active_brush OdCmEntityColor color(ODGETRED(cur_ctx.bkColor), ODGETGREEN(cur_ctx.bkColor), ODGETBLUE(cur_ctx.bkColor)); if (cur_ctx.fill_set && cur_ctx.fill_mode == DRAW_PAINT) color = cur_ctx.style.fill_color; ODA_ASSERT_VAR(else) ODA_ASSERT(true); // brk traits.setTrueColor(color); traits.setMaterial(NULL); traits.setLineWeight(OdDb::kLnWt000); m_pContext->onTraitsModified(); //OdUInt32 tbkMode = U_TRANSPARENT; // holds proposed change to bkMode, if text is involved saving these to the DC must wait until the text is written //ODCOLORREF tbkColor = ODRGB(255, 255, 255); // holds proposed change to bkColor //if (false) if (cur_ctx.sizeWnd.x && cur_ctx.sizeWnd.y) { dx = m_u.x * (dx / cur_ctx.sizeWnd.x); //dy = m_v.y * (dy / cur_ctx.sizeWnd.y); dh = m_v.y * (dh / cur_ctx.sizeWnd.y); dy = m_v.y * ((cur_ctx.sizeWnd.y - dy) / cur_ctx.sizeWnd.y); if ((double(cur_ctx.sizeWnd.x) / cur_ctx.sizeWnd.y) <= 7.0) { dw = m_u.x * (dw / cur_ctx.sizeWnd.x); //dw = m_u.x * (dw / U_ROUND(cur_ctx.sizeWnd.x)); dh = -m_v.y * (dh / cur_ctx.sizeWnd.y); //dh = -m_v.y * (dh / U_ROUND(cur_ctx.sizeWnd.y)); } else { // correction for rectangles with large ratio // (for bitmap tests OleSsItemHandlerTxtDraw_CORE25425_YM 1 & OleSsItemHandlerWmfDraw_CORE26194_YM 3) dw = m_u.x * (dw / (cur_ctx.sizeWnd.x + 1)); dh = -m_v.y * (dh / (cur_ctx.sizeWnd.y + 2)); } dx += m_origin.x; dy += m_origin.y; } //else //{ // double dCoeffY = 1.0; // if (cur_ctx.sizeWnd.x && !OdZero(m_u.length())) // { // //double ratioWmf = double(cur_ctx.sizeWnd.y) / cur_ctx.sizeWnd.x, // double ratioWmf = double(cur_ctx.sizeView.y) / cur_ctx.sizeView.x, // ratioDraw = m_v.length() / m_u.length(); // if (!OdZero(ratioWmf) && ratioWmf <= 1.0 && ratioDraw <= 1.0) // dCoeffY = ratioDraw / ratioWmf; // ODA_ASSERT_VAR(else) // ODA_ASSERT(true); // TODO // } // ODA_ASSERT_VAR(else) // ODA_ASSERT(true); // brk // // dy *= dCoeffY; dh *= dCoeffY; // dy -= dh; // dh *= dCoeffY; // ? strange but I see incorrect result without it // // TODO //dw = m_u / dw; dh = m_v / dh; // dx += m_origin.x; dy += m_origin.y; //} OdGePoint3d vertexes[4]; vertexes[0].x = dx; vertexes[0].y = dy; vertexes[0].z = m_origin.z; vertexes[1].x = dx + dw; vertexes[1].y = dy; vertexes[1].z = m_origin.z; vertexes[2].x = dx + dw; vertexes[2].y = dy + dh; vertexes[2].z = m_origin.z; vertexes[3].x = dx; vertexes[3].y = dy + dh; vertexes[3].z = m_origin.z; m_pDestGeom->polygonProc(4, vertexes); // restore traits.setFillType(svFillType); // traits.setDrawFlags(svDrawFlags); m_pContext->onTraitsModified(); } void OdMetafileParser::text_out(PWMF_CALLBACK_DATA d, const OdString& sText, double dx, double dy) { if (!hasDrawCtx()) return; WMF_DEVICE_CONTEXT& cur_ctx = d->dc[d->level]; ODA_ASSERT_ONCE_X(WMF, cur_ctx.style.text_style.get()); if (cur_ctx.style.text_style.isNull()) return; OdGiSubEntityTraits& traits = m_pContext->subEntityTraits(); OdGiFillType svFillType = traits.fillType(); if (svFillType != kOdGiFillAlways) traits.setFillType(kOdGiFillAlways); // Modify OdUInt32 svDrawFlags = traits.drawFlags(); //if (!GETBIT(svDrawFlags, OdGiSubEntityTraits::kDrawSolidFill)) // traits.setDrawFlags(svDrawFlags | OdGiSubEntityTraits::kDrawSolidFill); //traits.setFillType(kOdGiFillNever); // tsp.color.Red = cur_ctx.textColor.Red; tsp.color.Green = cur_ctx.textColor.Green; tsp.color.Blue = cur_ctx.textColor.Blue; //OdCmEntityColor color(255, 0, 0); // test OdCmEntityColor color(ODGETRED(cur_ctx.textColor), ODGETGREEN(cur_ctx.textColor), ODGETBLUE(cur_ctx.textColor)); traits.setTrueColor(color); m_pContext->onTraitsModified(); OdGiTextStyle& style = *cur_ctx.style.text_style.get(); // correction via //cur_ctx.sizeWnd & cur_ctx.sizeView // (575, 67) // or // d->PixelsInX, d->PixelsInY & d->PixelsOutX, d->PixelsOutY // (576, 68) double xScale = style.textSize() * 0.5 / cur_ctx.sizeWnd.x, // 800.0, yScale = style.textSize() * 0.5 / cur_ctx.sizeWnd.y; // 200.0; double sizeSv = style.textSize(); OdGePoint3d pos = m_origin; OdGeVector3d vU = m_u, vV = m_v; vU *= xScale; vV *= yScale; //if (false) //{ // dx = m_u.x * (dx / cur_ctx.sizeWnd.x); // dy = m_v.y * ((cur_ctx.sizeWnd.y - dy) / cur_ctx.sizeWnd.y); // pos.y -= m_v.y * (sizeSv * 0.75 / cur_ctx.sizeWnd.y); // //vU.x = vU.x * (vU.x / cur_ctx.sizeWnd.x); // //vV.y = -vV.y * (vV.y / cur_ctx.sizeWnd.y); // pos.x += dx; pos.y += dy; //} //else { pos += m_u * (dx / cur_ctx.sizeWnd.x); pos -= m_v * (dy / cur_ctx.sizeWnd.y); pos += m_v; if (cur_ctx.textAlign & _TA_BASEBIT) pos += m_v * (sizeSv * 0.125 / cur_ctx.sizeWnd.y); // ALIBASE else if (cur_ctx.textAlign & _TA_BOTTOM) { ODA_ASSERT(true); // TODO // ALIBOT } else pos -= m_v * (sizeSv * 0.75 / cur_ctx.sizeWnd.y); // ALITOP // 0x6 is center, 0x2 is right, 0x0 is left, the value 0x4 is also drawn left ODA_ASSERT_VAR(if ((cur_ctx.textAlign & _TA_CENTER) == _TA_CENTER)) { ODA_ASSERT(true); // TODO // ALICENTER } ODA_ASSERT_VAR(else if ((cur_ctx.textAlign & _TA_CENTER) == _TA_LEFT)) { ODA_ASSERT(true); // brk // ALILEFT - ok } ODA_ASSERT_VAR(else) { ODA_ASSERT(true); // TODO // ALIRIGHT } } m_pDestGeom->textProc(pos, vU, vV, sText.c_str(), sText.getLength(), false, &style); // restore traits.setFillType(svFillType); // traits.setDrawFlags(svDrawFlags); m_pContext->onTraitsModified(); style.setTextSize(sizeSv); } static void initWmfData(Wmf& parserWmf, WMF_CALLBACK_DATA& d) { parserWmf.m_pDestGeom = NULL; parserWmf.m_pContext = NULL; parserWmf.m_regenType = eOdGiRegenTypeInvalid; parserWmf.m_isExport = false; // simple initial //d.level = 0; d.D2PscaleX = d.D2PscaleY = 1.0; // see Wmf::open memset(&d, 0, sizeof(WMF_CALLBACK_DATA)); for(int i = 0; i < WMF_MAX_DC+1; i++) { // be sure all values and pointers are empty to start with memset(&(d.dc[i]),0,sizeof(WMF_DEVICE_CONTEXT)); } //// set default drawing objects, these are active if no object has been selected //d.dc[0].active_pen = -1; // -1 when the default is used instead of a selected object //d.dc[0].active_brush = -1; //d.dc[0].active_font = -1; // Default font, WMF spec says device can pick whatever it wants. WMF files that do not specify a font are unlikely to look very good! d.dc[0].font_name = strdup("Arial"); //d.dc[0].style.font_size.computed = 16.0; //d.dc[0].style.font_weight.value = SP_CSS_FONT_WEIGHT_400; //d.dc[0].style.font_style.value = SP_CSS_FONT_STYLE_NORMAL; //d.dc[0].style.text_decoration.underline = 0; //d.dc[0].style.text_decoration.line_through = 0; //d.dc[0].style.baseline_shift.value = 0; //d.dc[0].textColor = ODRGB(0, 0, 0); // default foreground color (black) //d.dc[0].bkColor = ODRGB(255, 255, 255); // default background color (white) //d.dc[0].bkMode = U_TRANSPARENT; //d.dc[0].dirty = 0; //// Default pen, WMF files that do not specify a pen are unlikely to look very good! //d.dc[0].style.stroke_dasharray_set = 0; //d.dc[0].style.stroke_linecap.computed = 2; // U_PS_ENDCAP_SQUARE; //d.dc[0].style.stroke_linejoin.computed = 0; // U_PS_JOIN_MITER; //d.dc[0].stroke_set = true; //d.dc[0].style.stroke_width.value = 1.0; // will be reset to something reasonable once WMF draying size is known //d.dc[0].style.stroke.value.color.set( 0, 0, 0 ); //// Default brush = none, WMF files that do not specify a brush are unlikely to look very good! //d.dc[0].fill_set = false; // //if (uri == NULL) { // return NULL; //} // //d.outsvg = new Glib::ustring(""); //d.path = new Glib::ustring(""); //d.outdef = new Glib::ustring(""); //d.defs = new Glib::ustring(""); //d.mask = 0; //d.drawtype = 0; //d.arcdir = U_AD_COUNTERCLOCKWISE; //d.dwRop2 = U_R2_COPYPEN; //d.dwRop3 = 0; //d.E2IdirY = 1.0; d.D2PscaleX = 1.0; d.D2PscaleY = 1.0; //d.hatches.size = 0; //d.hatches.count = 0; //d.hatches.strings = NULL; //d.images.size = 0; //d.images.count = 0; //d.images.strings = NULL; // //// set up the size default for patterns in defs. This might not be referenced if there are no patterns defined in the drawing. // //*(d.defs) += "\n"; //*(d.defs) += " \n"; //*(d.defs) += " \n"; // //// set up the text reassembly system //if(!(d.tri = trinfo_init(NULL))) // return(NULL); //(void) trinfo_load_ft_opts(d.tri, 1, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP, FT_KERNING_UNSCALED); } static void uninitWmfData(WMF_CALLBACK_DATA& d) { // see Wmf::open //delete d.outsvg; //delete d.path; //delete d.outdef; //delete d.defs; //free_wmf_strings(d.hatches); //free_wmf_strings(d.images); if (d.wmf_obj) { int i; for (i=0; i \n"; //d.defs += " \n"; d.pDesc = NULL; // set up the text reassembly system //if(!(d.tri = trinfo_init(NULL))) // return(NULL); //trinfo_load_ft_opts(d.tri, 1, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP, FT_KERNING_UNSCALED); } static void uninitEmfData(EMF_CALLBACK_DATA& d) { // see Emf::open if (d.pDesc) { free( d.pDesc ); } //free_emf_strings(d.hatches); //free_emf_strings(d.images); //free_emf_strings(d.gradients); //free_emf_strings(d.clips); if (d.emf_obj) { int i; for (i=0; i #include #endif OdGiRasterImagePtr getMetafileRaster(const OdBinaryData& data, const OdString& sExt) { // instead wmf_readdata size_t length = data.size(); char* contents = const_cast((const char*)data.asArrayPtr()); #ifdef _DEBUG static bool s_bFirst = true; if (false) { if (s_bFirst) { s_bFirst = false; // https://stackoverflow.com/questions/16703835/how-can-i-see-cout-output-in-a-non-console-application AllocConsole(); freopen("CONOUT$", "w", stdout); freopen("CONOUT$", "w", stderr); } if (sExt == L".emf") emfMetaFilePrintProc(contents, length); else wmfMetaFilePrintProc(contents, length); return OdGiRasterImagePtr(); } #endif if (sExt == L".emf") { //ODA_ASSERT(true); // TODO via Emf parserEmf Emf parserEmf; EMF_CALLBACK_DATA d; initEmfData(parserEmf, d); try { ODA_ASSERT_VAR(int res = ) parserEmf.emfMetaFileProc(contents, (unsigned int)length, &d); ODA_ASSERT_ONCE(res); } catch (const char* ODA_ASSERT_VAR(asErr)) { ODA_FAIL_ONCE(); } uninitEmfData(d); //return OdGiRasterImagePtr(); // test - direct draw inside parsing (is repeated eacjh time) return parserEmf.m_pRasterImage; // draw this cache image instead next parsing } Wmf parserWmf; WMF_CALLBACK_DATA d; initWmfData(parserWmf, d); try { ODA_ASSERT_VAR(int res = ) parserWmf.wmfMetaFileProc(contents, (unsigned int)length, &d); ODA_ASSERT_ONCE(res); } catch (const char* ODA_ASSERT_VAR(asErr)) { ODA_FAIL_ONCE(); } uninitWmfData(d); //return OdGiRasterImagePtr(); // test - direct draw inside parsing (is repeated eacjh time) return parserWmf.m_pRasterImage; // draw this cache image instead next parsing } bool drawMetafile(const OdBinaryData& data, const OdString& sExt, class OdGiConveyorGeometry* pDestGeom, class OdGiConveyorContext* pContext, OdGiRegenType regenType, const OdGePoint3d& origin, const OdGeVector3d& u, const OdGeVector3d& v, const OdGsDCRect& rect, bool isExport) { ODA_ASSERT_ONCE_X(WMF, pDestGeom && pContext); if (!pDestGeom || !pContext || regenType == kOdGiForExtents) return false; // save OdGiSubEntityTraits& traits = pContext->subEntityTraits(); OdCmEntityColor svColor = traits.trueColor(); OdDbStub* svMaterialId = traits.material(); OdDb::LineWeight svLineWeight = traits.lineWeight(); OdGiFillType svFillType = traits.fillType(); // instead wmf_readdata size_t length = data.size(); char* contents = const_cast((const char*)data.asArrayPtr()); if (sExt == L".emf") { Emf parserEmf; EMF_CALLBACK_DATA d; initEmfData(parserEmf, d); parserEmf.m_pDestGeom = pDestGeom; parserEmf.m_pContext = pContext; parserEmf.m_regenType = regenType, parserEmf.m_origin = origin; parserEmf.m_u = u; parserEmf.m_v = v; parserEmf.m_rect = rect; parserEmf.m_isExport = isExport; try { int res = parserEmf.emfMetaFileProc(contents, (unsigned int)length, &d); ODA_ASSERT_ONCE(res); uninitEmfData(d); return res != 0; } catch (const char* ODA_ASSERT_VAR(asErr)) { ODA_FAIL_ONCE(); } uninitEmfData(d); } else { Wmf parserWmf; WMF_CALLBACK_DATA d; initWmfData(parserWmf, d); parserWmf.m_pDestGeom = pDestGeom; parserWmf.m_pContext = pContext; parserWmf.m_regenType = regenType, parserWmf.m_origin = origin; parserWmf.m_u = u; parserWmf.m_v = v; parserWmf.m_rect = rect; parserWmf.m_isExport = isExport; try { int res = parserWmf.wmfMetaFileProc(contents, (unsigned int)length, &d); ODA_ASSERT_ONCE(res); uninitWmfData(d); return res != 0; } catch (const char* ODA_ASSERT_VAR(asErr)) { ODA_FAIL_ONCE(); } uninitWmfData(d); } // restore traits.setTrueColor(svColor); traits.setMaterial(svMaterialId); traits.setLineWeight(svLineWeight); traits.setFillType(svFillType); pContext->onTraitsModified(); return false; }