diff options
| author | Jabier Arraiza Cenoz <jabier.arraiza@marker.es> | 2014-01-18 09:11:04 +0000 |
|---|---|---|
| committer | Jabiertxof <jtx@jtx.marker.es> | 2014-01-18 09:11:04 +0000 |
| commit | f12d6a57fe5cc18be5afd164061578d8e00d75ce (patch) | |
| tree | 7fd1a501a8a545fbf2326ead48cd041928699c5e /src/extension | |
| parent | update to trunk (diff) | |
| parent | Fix missing embeded image condition, kindly caught by suv in bug #1270334 (diff) | |
| download | inkscape-f12d6a57fe5cc18be5afd164061578d8e00d75ce.tar.gz inkscape-f12d6a57fe5cc18be5afd164061578d8e00d75ce.zip | |
update to trunk
(bzr r11950.1.235)
Diffstat (limited to 'src/extension')
| -rw-r--r-- | src/extension/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/extension/internal/Makefile_insert | 2 | ||||
| -rw-r--r-- | src/extension/internal/cairo-ps-out.cpp | 4 | ||||
| -rw-r--r-- | src/extension/internal/cairo-render-context.cpp | 4 | ||||
| -rw-r--r-- | src/extension/internal/cairo-renderer.cpp | 6 | ||||
| -rw-r--r-- | src/extension/internal/emf-inout.cpp | 618 | ||||
| -rw-r--r-- | src/extension/internal/emf-inout.h | 43 | ||||
| -rw-r--r-- | src/extension/internal/emf-print.cpp | 417 | ||||
| -rw-r--r-- | src/extension/internal/emf-print.h | 5 | ||||
| -rw-r--r-- | src/extension/internal/metafile-inout.cpp | 210 | ||||
| -rw-r--r-- | src/extension/internal/metafile-inout.h | 93 | ||||
| -rw-r--r-- | src/extension/internal/metafile-print.cpp | 4 | ||||
| -rw-r--r-- | src/extension/internal/wmf-inout.cpp | 150 | ||||
| -rw-r--r-- | src/extension/internal/wmf-inout.h | 39 | ||||
| -rw-r--r-- | src/extension/internal/wmf-print.cpp | 116 |
15 files changed, 1037 insertions, 675 deletions
diff --git a/src/extension/CMakeLists.txt b/src/extension/CMakeLists.txt index 6310ceaea..9bc30a592 100644 --- a/src/extension/CMakeLists.txt +++ b/src/extension/CMakeLists.txt @@ -45,6 +45,7 @@ set(extension_SRC internal/image-resolution.cpp internal/latex-pstricks.cpp internal/latex-pstricks-out.cpp + internal/metafile-inout.cpp internal/metafile-print.cpp internal/odf.cpp internal/latex-text-renderer.cpp diff --git a/src/extension/internal/Makefile_insert b/src/extension/internal/Makefile_insert index 726bca28f..a31843114 100644 --- a/src/extension/internal/Makefile_insert +++ b/src/extension/internal/Makefile_insert @@ -162,6 +162,8 @@ ink_common_sources += \ extension/internal/emf-print.cpp \ extension/internal/emf-inout.h \ extension/internal/emf-inout.cpp \ + extension/internal/metafile-inout.h \ + extension/internal/metafile-inout.cpp \ extension/internal/metafile-print.h \ extension/internal/metafile-print.cpp \ extension/internal/wmf-print.h \ diff --git a/src/extension/internal/cairo-ps-out.cpp b/src/extension/internal/cairo-ps-out.cpp index 5f535dc64..055a30add 100644 --- a/src/extension/internal/cairo-ps-out.cpp +++ b/src/extension/internal/cairo-ps-out.cpp @@ -328,9 +328,7 @@ CairoPsOutput::init (void) "<id>" SP_MODULE_KEY_PRINT_CAIRO_PS "</id>\n" "<param name=\"PSlevel\" gui-text=\"" N_("Restrict to PS level:") "\" type=\"enum\" >\n" "<_item value='PS3'>" N_("PostScript level 3") "</_item>\n" -#if (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 5, 2)) "<_item value='PS2'>" N_("PostScript level 2") "</_item>\n" -#endif "</param>\n" "<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">false</param>\n" "<param name=\"textToLaTeX\" gui-text=\"" N_("PS+LaTeX: Omit text in PS, and create LaTeX file") "\" type=\"boolean\">false</param>\n" @@ -369,9 +367,7 @@ CairoEpsOutput::init (void) "<id>" SP_MODULE_KEY_PRINT_CAIRO_EPS "</id>\n" "<param name=\"PSlevel\" gui-text=\"" N_("Restrict to PS level:") "\" type=\"enum\" >\n" "<_item value='PS3'>" N_("PostScript level 3") "</_item>\n" -#if (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 5, 2)) "<_item value='PS2'>" N_("PostScript level 2") "</_item>\n" -#endif "</param>\n" "<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">false</param>\n" "<param name=\"textToLaTeX\" gui-text=\"" N_("EPS+LaTeX: Omit text in EPS, and create LaTeX file") "\" type=\"boolean\">false</param>\n" diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index 4f9273cbb..47de62ac0 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -803,9 +803,7 @@ CairoRenderContext::setupSurface(double width, double height) #ifdef CAIRO_HAS_PDF_SURFACE case CAIRO_SURFACE_TYPE_PDF: surface = cairo_pdf_surface_create_for_stream(Inkscape::Extension::Internal::_write_callback, _stream, width, height); -#if (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0)) cairo_pdf_surface_restrict_to_version(surface, (cairo_pdf_version_t)_pdf_level); -#endif break; #endif #ifdef CAIRO_HAS_PS_SURFACE @@ -814,10 +812,8 @@ CairoRenderContext::setupSurface(double width, double height) if(CAIRO_STATUS_SUCCESS != cairo_surface_status(surface)) { return FALSE; } -#if (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 5, 2)) cairo_ps_surface_restrict_to_level(surface, (cairo_ps_level_t)_ps_level); cairo_ps_surface_set_eps(surface, (cairo_bool_t) _eps); -#endif // Cairo calculates the bounding box itself, however we want to override this. See Launchpad bug #380501 #if (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 11, 2)) // cairo_ps_dsc_comment(surface, os_bbox.str().c_str()); diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp index 0a4c86f0b..6fbc85c05 100644 --- a/src/extension/internal/cairo-renderer.cpp +++ b/src/extension/internal/cairo-renderer.cpp @@ -580,9 +580,9 @@ void CairoRenderer::renderItem(CairoRenderContext *ctx, SPItem *item) setStateForItem(ctx, item); CairoRenderState *state = ctx->getCurrentState(); - state->need_layer = ( state->mask || state->opacity != 1.0 ); + state->need_layer = ( state->mask || state->clip_path || state->opacity != 1.0 ); - // Draw item on a temporary surface so a mask or opacity can be applied to it. + // Draw item on a temporary surface so a mask, clip-path, or opacity can be applied to it. if (state->need_layer) { state->merge_opacity = FALSE; ctx->pushLayer(); @@ -591,7 +591,7 @@ void CairoRenderer::renderItem(CairoRenderContext *ctx, SPItem *item) sp_item_invoke_render(item, ctx); if (state->need_layer) - ctx->popLayer(); + ctx->popLayer(); // This applies clipping/masking ctx->popState(); } diff --git a/src/extension/internal/emf-inout.cpp b/src/extension/internal/emf-inout.cpp index c8c708051..cca541c5b 100644 --- a/src/extension/internal/emf-inout.cpp +++ b/src/extension/internal/emf-inout.cpp @@ -26,7 +26,7 @@ # include "config.h" #endif -#include <png.h> //This must precede text_reassemble.h or it blows up in pngconf.h when compiling +//#include <png.h> //This must precede text_reassemble.h or it blows up in pngconf.h when compiling #include <stdio.h> #include <stdlib.h> #include <stdint.h> @@ -69,154 +69,6 @@ static bool clipset = false; static uint32_t ICMmode = 0; // not used yet, but code to read it from EMF implemented static uint32_t BLTmode = 0; -/** Construct a PNG in memory from an RGB from the EMF file - -from: -http://www.lemoda.net/c/write-png/ - -which was based on: -http://stackoverflow.com/questions/1821806/how-to-encode-png-to-buffer-using-libpng - -gcc -Wall -o testpng testpng.c -lpng - -Originally here, but moved up - -#include <png.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -*/ - - -/* Given "bitmap", this returns the pixel of bitmap at the point - ("x", "y"). */ - -pixel_t * Emf::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 -Emf::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 Emf::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 (uint8_t) * bitmap->width * pixel_size); - row_pointers[bitmap->height - y - 1] = row; // Row order in EMF 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 EMF RGB(A) color to 0RGB -inverse of gethexcolor() in emf-print.cpp -*/ -uint32_t Emf::sethexcolor(U_COLORREF color){ - - uint32_t out; - out = (U_RGBAGetR(color) << 16) + - (U_RGBAGetG(color) << 8 ) + - (U_RGBAGetB(color) ); - return(out); -} - - Emf::Emf (void) // The null constructor { return; @@ -298,6 +150,7 @@ Emf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filena // 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 @@ -311,6 +164,7 @@ Emf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filena 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); @@ -615,10 +469,10 @@ uint32_t Emf::add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint uint32_t iUsage, uint32_t offBits, uint32_t offBmi){ uint32_t idx; - char imagename[64]; // big enough - char imrotname[64]; // big enough - char xywh[64]; // big enough - int dibparams; + char imagename[64]; // big enough + char imrotname[64]; // big enough + char xywh[64]; // big enough + int dibparams = U_BI_UNKNOWN; // type of image not yet determined MEMPNG mempng; // PNG in memory comes back in this mempng.buffer = NULL; @@ -627,74 +481,60 @@ uint32_t Emf::add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint const char *px = NULL; // DIB pixels const U_RGBQUAD *ct = NULL; // DIB color table U_RGBQUAD ct2[2]; - uint32_t width, height, colortype, numCt, invert; - if( !cbBits || - !cbBmi || - (iUsage != U_DIB_RGB_COLORS) || - !(dibparams = get_DIB_params( // this returns pointers and values, but allocates no memory - pEmr, - offBits, - offBmi, - &px, - (const U_RGBQUAD **) &ct, - &numCt, - &width, - &height, - &colortype, - &invert - )) - ){ + uint32_t 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(pEmr, offBits, offBmi, &px, (const U_RGBQUAD **) &ct, + &numCt, &width, &height, &colortype, &invert); + if(dibparams ==U_BI_RGB){ + // U_EMRCREATEMONOBRUSH uses text/bk colors instead of what is in the color map. + if(((PU_EMR)pEmr)->iType == U_EMR_CREATEMONOBRUSH){ + if(numCt==2){ + ct2[0] = U_RGB2BGR(d->dc[d->level].textColor); + ct2[1] = U_RGB2BGR(d->dc[d->level].bkColor); + ct = &ct2[0]; + } + else { // This record is invalid, nothing more to do here, let caller handle it + return(U_EMR_INVALID); + } + } - // U_EMRCREATEMONOBRUSH uses text/bk colors instead of what is in the color map. - if(((PU_EMR)pEmr)->iType == U_EMR_CREATEMONOBRUSH){ - if(numCt==2){ - ct2[0] = U_RGB2BGR(d->dc[d->level].textColor); - ct2[1] = U_RGB2BGR(d->dc[d->level].bkColor); - ct = &ct2[0]; - } - else { // createmonobrush renders on other platforms this way - return(0xFFFFFFFF); - } - } - - 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); + 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; - if(dibparams == U_BI_JPEG || dibparams==U_BI_PNG){ + + 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 ); - idx = in_images(d, (char *) base64String); } - else if(mempng.buffer){ + 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); - idx = in_images(d, (char *) base64String); } - else { - // insert a random 3x4 blotch otherwise + else { // unknown or unsupported image type or failed conversion, insert the common bad image picture width = 3; height = 4; - base64String = g_strdup("iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII="); - idx = in_images(d, (char *) base64String); + 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; @@ -732,7 +572,7 @@ uint32_t Emf::add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint *(d->defs) += " "; *(d->defs) += " </pattern>\n"; } - g_free(base64String); + 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 @@ -772,6 +612,115 @@ uint32_t Emf::add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint 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, char *test){ + int i; + for(i=0; i<d->gradients.count; i++){ + if(strcmp(test,d->gradients.strings[i])==0)return(i+1); + } + return(0); +} + +U_COLORREF trivertex_to_colorref(U_TRIVERTEX tv){ + U_COLORREF 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 <defs>. + Only call this with H or V gradient, not a triangle. +*/ +uint32_t Emf::add_gradient(PEMF_CALLBACK_DATA d, uint32_t gradientType, U_TRIVERTEX tv1, U_TRIVERTEX tv2){ + char hgradname[64]; // big enough + char tmpcolor1[8]; + char tmpcolor2[8]; + char gradc; + uint32_t idx; + std::string x2,y2; + + U_COLORREF gradientColor1 = trivertex_to_colorref(tv1); + U_COLORREF 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 << " <linearGradient id=\""; + stmp << hgradname; + stmp << "\" x1=\""; + stmp << pix_to_x_point(d, tv1.x , tv1.y); + stmp << "\" y1=\""; + stmp << pix_to_y_point(d, tv1.x , tv1.y); + stmp << "\" x2=\""; + if(gradc=='H'){ // UR corner + stmp << pix_to_x_point(d, tv2.x , tv1.y); + stmp << "\" y2=\""; + stmp << pix_to_y_point(d, tv2.x , tv1.y); + } + else { // LL corner + stmp << pix_to_x_point(d, tv1.x , tv2.y); + stmp << "\" y2=\""; + stmp << pix_to_y_point(d, tv1.x , tv2.y); + } + stmp << "\" gradientTransform=\"(1,0,0,1,0,0)\""; + stmp << " gradientUnits=\"userSpaceOnUse\"\n"; + stmp << ">\n"; + stmp << " <stop offset=\"0\" style=\"stop-color:#"; + stmp << tmpcolor1; + stmp << ";stop-opacity:1\" />\n"; + stmp << " <stop offset=\"1\" style=\"stop-color:#"; + stmp << tmpcolor2; + stmp << ";stop-opacity:1\" />\n"; + stmp << " </linearGradient>\n"; + *(d->defs) += stmp.str().c_str(); + } + + return(idx-1); +} + + void Emf::output_style(PEMF_CALLBACK_DATA d, int iType) @@ -871,10 +820,11 @@ Emf::output_style(PEMF_CALLBACK_DATA d, int iType) snprintf(tmp, 1023, "fill:url(#%s); ",d->hatches.strings[d->dc[d->level].fill_idx]); tmp_style << tmp; break; - case DRAW_IMAGE: + case DRAW_IMAGE: snprintf(tmp, 1023, "fill:url(#EMFimage%d_ref); ",d->dc[d->level].fill_idx); tmp_style << tmp; break; + case DRAW_LINEAR_GRADIENT: case DRAW_PAINT: default: // <-- this should never happen, but just in case... snprintf( @@ -927,6 +877,7 @@ Emf::output_style(PEMF_CALLBACK_DATA d, int iType) snprintf(tmp, 1023, "stroke:url(#EMFimage%d_ref); ",d->dc[d->level].stroke_idx); tmp_style << tmp; break; + case DRAW_LINEAR_GRADIENT: case DRAW_PAINT: default: // <-- this should never happen, but just in case... snprintf( @@ -1343,7 +1294,7 @@ Emf::select_brush(PEMF_CALLBACK_DATA d, int index) else if(iType == U_EMR_CREATEDIBPATTERNBRUSHPT || iType == U_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 == 0xFFFFFFFF){ // This happens if createmonobrush has a DIB that isn't monochrome + if(tidx == U_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(d->dc[d->level].textColor)); g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor)); @@ -1502,13 +1453,11 @@ void Emf::common_image_extraction(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t iUsage, uint32_t offBits, uint32_t cbBits, uint32_t offBmi, uint32_t cbBmi){ SVGOStringStream tmp_image; - int dibparams; + int dibparams = U_BI_UNKNOWN; // type of image not yet determined + tmp_image << "\n\t <image\n"; 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; @@ -1516,91 +1465,74 @@ void Emf::common_image_extraction(PEMF_CALLBACK_DATA d, void *pEmr, char *sub_px = NULL; // RGBA pixels, subarray const char *px = NULL; // DIB pixels const U_RGBQUAD *ct = NULL; // DIB color table - uint32_t width, height, colortype, numCt, invert; - if(!cbBits || - !cbBmi || - (iUsage != U_DIB_RGB_COLORS) || - !(dibparams = get_DIB_params( // this returns pointers and values, but allocates no memory - pEmr, - offBits, - offBmi, - &px, - (const U_RGBQUAD **) &ct, - &numCt, - &width, - &height, - &colortype, - &invert - )) - ){ - if(sw == 0 || sh == 0){ - sw = width; - sh = height; - } - - 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 - ) && - rgba_px - ){ - sub_px = RGBA_to_RGBA( - rgba_px, // full pixel array from DIB + uint32_t 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(pEmr, offBits, offBmi, &px, (const U_RGBQUAD **) &ct, + &numCt, &width, &height, &colortype, &invert); + if(dibparams ==U_BI_RGB){ + if(sw == 0 || sh == 0){ + sw = width; + sh = height; + } + + 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 - 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); + 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; - if(dibparams == U_BI_JPEG){ + + 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 ); - tmp_image << base64String ; - g_free(base64String); } - else if(dibparams==U_BI_PNG){ + 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 ); - tmp_image << base64String ; - g_free(base64String); } - else if(mempng.buffer){ + else if(mempng.buffer){ // image was DIB in source file, converted to png in this routine tmp_image << " xlink:href=\"data:image/png;base64,"; - gchar *base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size ); + base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size ); free(mempng.buffer); - tmp_image << base64String ; - g_free(base64String); } - else { + else { // unknown or unsupported image type or failed conversion, insert the common bad image picture tmp_image << " xlink:href=\"data:image/png;base64,"; - // insert a random 3x4 blotch otherwise - tmp_image << "iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII="; + 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 - *(d->outsvg) += "\n\t <image\n"; - *(d->outsvg) += tmp_image.str().c_str(); + tmp_image << "/> \n"; - *(d->outsvg) += "/> \n"; + *(d->outsvg) += tmp_image.str().c_str(); *(d->path) = ""; } @@ -1664,7 +1596,7 @@ int Emf::myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DA // 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 ((d->dc[d->level].dirty & DIRTY_TEXT) || ((emr_mask != 0xFFFFFFFF) && (emr_mask & U_DRAW_TEXT) && d->tri->dirty)){ + if ((d->dc[d->level].dirty & DIRTY_TEXT) || ((emr_mask != U_EMR_INVALID) && (emr_mask & U_DRAW_TEXT) && d->tri->dirty)){ TR_layout_analyze(d->tri); TR_layout_2_svg(d->tri); SVGOStringStream ts; @@ -1711,7 +1643,7 @@ std::cout << "BEFORE DRAW" */ if( - (emr_mask != 0xFFFFFFFF) && // next record is valid type + (emr_mask != U_EMR_INVALID) && // next record is valid type (d->mask & U_DRAW_VISIBLE) && // Current set of objects are drawable ( (d->mask & U_DRAW_FORCE) || // This draw is forced by STROKE/FILL/STROKEANDFILL PATH @@ -1726,7 +1658,7 @@ std::cout << "BEFORE DRAW" ) ){ // std::cout << "PATH DRAW at TOP" << std::endl; - *(d->outsvg) += " <path "; // this is the ONLY place <path should be used!!!! + *(d->outsvg) += " <path "; // this is the ONLY place <path should be used!!! One exception, gradientfill. if(d->drawtype){ // explicit draw type EMR record output_style(d, d->drawtype); } @@ -1737,7 +1669,7 @@ std::cout << "BEFORE DRAW" output_style(d, U_EMR_STROKEPATH); } *(d->outsvg) += "\n\t"; - *(d->outsvg) += "\n\td=\""; // this is the ONLY place d=" should be used!!!! + *(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) = ""; @@ -2625,7 +2557,7 @@ std::cout << "BEFORE DRAW" 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 << " 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 << " "; @@ -2646,7 +2578,7 @@ std::cout << "BEFORE DRAW" 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 << " 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 << " "; @@ -2669,7 +2601,7 @@ std::cout << "BEFORE DRAW" 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 << " 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 << " "; @@ -2710,7 +2642,7 @@ std::cout << "BEFORE DRAW" 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 << " 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 << " "; @@ -3332,13 +3264,64 @@ std::cout << "BEFORE DRAW" case U_EMR_SETLAYOUT: dbg_str << "<!-- U_EMR_SETLAYOUT -->\n"; break; case U_EMR_TRANSPARENTBLT: dbg_str << "<!-- U_EMR_TRANSPARENTBLT -->\n"; break; case U_EMR_UNDEF117: dbg_str << "<!-- U_EMR_UNDEF117 -->\n"; break; - case U_EMR_GRADIENTFILL: dbg_str << "<!-- U_EMR_GRADIENTFILL -->\n"; break; - /* 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. Except that so far - I (DM) have not been able to make an EMF with a rectangular gradientfill record which is not - completely toxic to other EMF readers. So far now, do nothing. - */ + case U_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 << "<!-- U_EMR_GRADIENTFILL -->\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;i<nG;i++){ + tmp_rectangle << "\n<path d=\""; + fill_idx = add_gradient(d, pEmr->ulMode, 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/>\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<nG;i++){ + tmp_triangle << "\n<path d=\""; + sprintf(tmpcolor,"%6.6X",sethexcolor(trivertex_to_colorref(tv[tris[i].Vertex1]))); + tmp_triangle << "\n\tM " << pix_to_xy( d, tv[tris[i].Vertex1].x , tv[tris[i].Vertex1].y ) << " "; + tmp_triangle << "\n\tL " << pix_to_xy( d, tv[tris[i].Vertex2].x , tv[tris[i].Vertex2].y ) << " "; + tmp_triangle << "\n\tL " << pix_to_xy( d, tv[tris[i].Vertex3].x , tv[tris[i].Vertex3].y ) << " "; + tmp_triangle << "\n\tz\""; + tmp_triangle << "\n\tstyle=\"stroke:none;fill:#"; + tmp_triangle << tmpcolor; + tmp_triangle << ";\"\n/>\n"; + } + *(d->outsvg) += tmp_triangle.str().c_str(); + } + *(d->path) = ""; + // if it is anything else the record is bogus, so ignore it + break; + } case U_EMR_SETLINKEDUFIS: dbg_str << "<!-- U_EMR_SETLINKEDUFIS -->\n"; break; case U_EMR_SETTEXTJUSTIFICATION: dbg_str << "<!-- U_EMR_SETTEXTJUSTIFICATION -->\n"; break; case U_EMR_COLORMATCHTOTARGETW: dbg_str << "<!-- U_EMR_COLORMATCHTOTARGETW -->\n"; break; @@ -3354,37 +3337,12 @@ std::cout << "BEFORE DRAW" } //end of while // When testing, uncomment the following to show the final SVG derived from the EMF -//std::cout << *(d->outsvg) << std::endl; +// std::cout << *(d->outsvg) << std::endl; (void) emr_properties(U_EMR_INVALID); // force the release of the lookup table memory, returned value is irrelevant return 1; } - -// Aldus Placeable Header =================================================== -// Since we are a 32bit app, we have to be sure this structure compiles to -// be identical to a 16 bit app's version. To do this, we use the #pragma -// to adjust packing, we use a uint16_t for the hmf handle, and a SMALL_RECT -// for the bbox rectangle. -#pragma pack( push ) -#pragma pack( 2 ) -typedef struct _SMALL_RECT { - int16_t Left; - int16_t Top; - int16_t Right; - int16_t Bottom; -} SMALL_RECT, *PSMALL_RECT; -typedef struct -{ - uint32_t dwKey; - uint16_t hmf; - SMALL_RECT bbox; - uint16_t wInch; - uint32_t dwReserved; - uint16_t wCheckSum; -} APMHEADER, *PAPMHEADER; -#pragma pack( pop ) - void Emf::free_emf_strings(EMF_STRINGS name){ if(name.count){ for(int i=0; i< name.count; i++){ free(name.strings[i]); } @@ -3438,6 +3396,9 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) d.images.size = 0; d.images.count = 0; d.images.strings = NULL; + d.gradients.size = 0; + d.gradients.count = 0; + d.gradients.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. @@ -3478,6 +3439,7 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) delete d.defs; free_emf_strings(d.hatches); free_emf_strings(d.images); + free_emf_strings(d.gradients); if (d.emf_obj) { int i; @@ -3516,7 +3478,14 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) // Scale and translate objects double scale = Inkscape::Util::Quantity::convert(1, "px", doc_unit); ShapeEditor::blockSetItem(true); - doc->getRoot()->scaleChildItemsRec(Geom::Scale(scale), Geom::Point(0, doc->getHeight().value("px"))); + double dh; + if(SP_ACTIVE_DOCUMENT){ // for file menu open or import, or paste from clipboard + dh = SP_ACTIVE_DOCUMENT->getHeight().value("px"); + } + else { // for open via --file on command line + dh = doc->getHeight().value("px"); + } + doc->getRoot()->scaleChildItemsRec(Geom::Scale(scale), Geom::Point(0, dh)); ShapeEditor::blockSetItem(false); Inkscape::DocumentUndo::setUndoSensitive(doc, saved); @@ -3556,6 +3525,7 @@ Emf::init (void) "<param name=\"FixPPTCharPos\" gui-text=\"" N_("Compensate for PPT font bug") "\" type=\"boolean\">false</param>\n" "<param name=\"FixPPTDashLine\" gui-text=\"" N_("Convert dashed/dotted lines to single lines") "\" type=\"boolean\">false</param>\n" "<param name=\"FixPPTGrad2Polys\" gui-text=\"" N_("Convert gradients to colored polygon series") "\" type=\"boolean\">false</param>\n" + "<param name=\"FixPPTLinGrad\" gui-text=\"" N_("Use native rectangular linear gradients") "\" type=\"boolean\">false</param>\n" "<param name=\"FixPPTPatternAsHatch\" gui-text=\"" N_("Map all fill patterns to standard EMF hatches") "\" type=\"boolean\">false</param>\n" "<param name=\"FixImageRot\" gui-text=\"" N_("Ignore image rotations") "\" type=\"boolean\">false</param>\n" "<output>\n" diff --git a/src/extension/internal/emf-inout.h b/src/extension/internal/emf-inout.h index 787a2fdb3..97f93e71b 100644 --- a/src/extension/internal/emf-inout.h +++ b/src/extension/internal/emf-inout.h @@ -11,9 +11,8 @@ #ifndef SEEN_EXTENSION_INTERNAL_EMF_H #define SEEN_EXTENSION_INTERNAL_EMF_H -#define PNG_SKIP_SETJMP_CHECK // else any further png.h include blows up in the compiler -#include <png.h> #include <libuemf/uemf.h> +#include "extension/internal/metafile-inout.h" // picks up PNG #include "extension/implementation/implementation.h" #include "style.h" #include "text_reassemble.h" @@ -67,34 +66,6 @@ typedef struct emf_device_context { #define EMF_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 { - uint8_t red; - uint8_t green; - uint8_t blue; - uint8_t 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 - typedef struct { Glib::ustring *outsvg; Glib::ustring *path; @@ -126,6 +97,7 @@ typedef struct { // both of these end up in <defs> 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 TR_INFO *tri; // Text Reassembly data structure @@ -133,7 +105,8 @@ typedef struct { PEMF_OBJECT emf_obj; } EMF_CALLBACK_DATA, *PEMF_CALLBACK_DATA; -class Emf : Inkscape::Extension::Implementation::Implementation { //This is a derived class +class Emf : public Metafile +{ public: @@ -155,11 +128,6 @@ public: private: protected: - - static pixel_t *pixel_at (bitmap_t * bitmap, int x, int y); - static void my_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length); - static void toPNG(PMEMPNG accum, int width, int height, const char *px); - static uint32_t sethexcolor(U_COLORREF color); static void print_document_to_file(SPDocument *doc, const gchar *filename); static double current_scale(PEMF_CALLBACK_DATA d); static std::string current_matrix(PEMF_CALLBACK_DATA d, double x, double y, int useoffset); @@ -171,6 +139,9 @@ protected: static int in_images(PEMF_CALLBACK_DATA d, char *test); static uint32_t add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint32_t cbBmi, uint32_t iUsage, uint32_t offBits, uint32_t offBmi); + static void enlarge_gradients(PEMF_CALLBACK_DATA d); + static int in_gradients(PEMF_CALLBACK_DATA d, char *test); + static uint32_t add_gradient(PEMF_CALLBACK_DATA d, uint32_t gradientType, U_TRIVERTEX tv1, U_TRIVERTEX tv2); static void output_style(PEMF_CALLBACK_DATA d, int iType); static double _pix_x_to_point(PEMF_CALLBACK_DATA d, double px); static double _pix_y_to_point(PEMF_CALLBACK_DATA d, double py); diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp index 0df643130..3c27ac1b8 100644 --- a/src/extension/internal/emf-print.cpp +++ b/src/extension/internal/emf-print.cpp @@ -70,9 +70,8 @@ namespace Internal { /* globals */ -static double PX2WORLD = 20.0f; -static U_XFORM worldTransform; -static bool FixPPTCharPos, FixPPTDashLine, FixPPTGrad2Polys, FixPPTPatternAsHatch, FixImageRot; +static double PX2WORLD; +static bool FixPPTCharPos, FixPPTDashLine, FixPPTGrad2Polys, FixPPTLinGrad, FixPPTPatternAsHatch, FixImageRot; static EMFTRACK *et = NULL; static EMFHANDLES *eht = NULL; @@ -125,9 +124,12 @@ unsigned int PrintEmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc) char *rec; gchar const *utf8_fn = mod->get_param_string("destination"); + // Typially PX2WORLD is 1200/90, using inkscape's default dpi + PX2WORLD = 1200.0 / Inkscape::Util::Quantity::convert(1.0, "in", "px"); FixPPTCharPos = mod->get_param_bool("FixPPTCharPos"); FixPPTDashLine = mod->get_param_bool("FixPPTDashLine"); FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys"); + FixPPTLinGrad = mod->get_param_bool("FixPPTLinGrad"); FixPPTPatternAsHatch = mod->get_param_bool("FixPPTPatternAsHatch"); FixImageRot = mod->get_param_bool("FixImageRot"); @@ -179,12 +181,12 @@ unsigned int PrintEmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc) float dwInchesX = d.width(); float dwInchesY = d.height(); - // dwInchesX x dwInchesY in micrometer units, dpi=90 -> 3543.3 dpm - (void) drawing_size((int) ceil(dwInchesX * 25.4), (int) ceil(dwInchesY * 25.4), 3.543307, &rclBounds, &rclFrame); + // dwInchesX x dwInchesY in micrometer units, 1200 dpi/25.4 -> dpmm + (void) drawing_size((int) ceil(dwInchesX * 25.4), (int) ceil(dwInchesY * 25.4),1200.0/25.4, &rclBounds, &rclFrame); // set up the reference device as 100 X A4 horizontal, (1200 dpi/25.4 -> dpmm). Extra digits maintain dpi better in EMF - int MMX = 21600; - int MMY = 27900; + int MMX = 216; + int MMY = 279; (void) device_size(MMX, MMY, 1200.0 / 25.4, &szlDev, &szlMm); int PixelsX = szlDev.cx; int PixelsY = szlDev.cy; @@ -220,13 +222,16 @@ unsigned int PrintEmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc) } - // Correct for dpi in EMF (1200) vs dpi in Inkscape (always 90). - // Also correct for the scaling in PX2WORLD, which is set to 20. + // In earlier versions this was used to scale from inkscape's dpi of 90 to + // the files 1200 dpi, taking into account PX2WORLD which was 20. Now PX2WORLD + // is set so that this matrix is unitary. The usual value of PX2WORLD is 1200/90, + // but might be different if the internal dpi is changed. - worldTransform.eM11 = 1200. / (90.0 * PX2WORLD); + U_XFORM worldTransform; + worldTransform.eM11 = 1.0; worldTransform.eM12 = 0.0; worldTransform.eM21 = 0.0; - worldTransform.eM22 = 1200. / (90.0 * PX2WORLD); + worldTransform.eM22 = 1.0; worldTransform.eDx = 0; worldTransform.eDy = 0; @@ -420,7 +425,7 @@ int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) hatchColor = avg_stop_color(rg); } } else if (lg) { - if (FixPPTGrad2Polys) { + if (FixPPTGrad2Polys || FixPPTLinGrad) { return hold_gradient(lg, fill_mode); } else { hatchColor = avg_stop_color(lg); @@ -696,7 +701,7 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform) n_dash = style->stroke_dash.n_dash; dash = new uint32_t[n_dash]; for (i = 0; i < style->stroke_dash.n_dash; i++) { - dash[i] = (uint32_t)(style->stroke_dash.dash[i]); + dash[i] = (uint32_t)(Inkscape::Util::Quantity::convert(1, "mm", "px") * style->stroke_dash.dash[i]); } } } @@ -780,6 +785,182 @@ void PrintEmf::destroy_pen() } } +/* Return a Path consisting of just the corner points of the single path in a a PathVector. If the +PathVector has more than one path, or that one path is open, or any of its segments are curved, then the +returned PathVector is . If the input path is already just straight lines and vertices the output will be the +same as the sole path in the input. */ + +Geom::Path PrintEmf::pathv_to_simple_polygon(Geom::PathVector const &pathv, int *vertices) +{ + Geom::Point P1_trail; + Geom::Point P1; + Geom::Point P1_lead; + Geom::Point v1,v2; + Geom::Path output; + Geom::Path bad; + Geom::PathVector pv = pathv_to_linear_and_cubic_beziers(pathv); + Geom::PathVector::const_iterator pit = pv.begin(); + Geom::PathVector::const_iterator pit2 = pv.begin(); + ++pit2; + *vertices = 0; + if(pit->end_closed() != pit->end_default())return(bad); // path must be closed + if(pit2 != pv.end())return(bad); // there may only be one path + P1_trail = pit->finalPoint(); + Geom::Path::const_iterator cit = pit->begin(); + P1 = cit->initialPoint(); + for(;cit != pit->end_closed();++cit) { + if (!is_straight_curve(*cit)) { + *vertices = 0; + return(bad); + } + P1_lead = cit->finalPoint(); + if(Geom::are_near(P1_lead,P1))continue; // duplicate points at the same coordinate + v1 = unit_vector(P1 - P1_trail); + v2 = unit_vector(P1_lead - P1 ); + if(Geom::are_near(dot(v1,v2),1.0)){ // P1 is within a straight line + P1 = P1_lead; + continue; + } + // P1 is the center point of a turn of some angle + if(!*vertices){ + output.start( P1 ); + output.close( pit->closed() ); + } + *vertices += 1; + Geom::LineSegment ls(P1_trail, P1); + output.append(ls); + P1_trail = P1; + P1 = P1_lead; + } + return(output); +} + +/* Returns the simplified PathVector (no matter what). + Sets is_rect if it is a rectangle. + Sets angle that will rotate side closest to horizontal onto horizontal. +*/ +Geom::Path PrintEmf::pathv_to_rect(Geom::PathVector const &pathv, bool *is_rect, double *angle) +{ + Geom::Point P1_trail; + Geom::Point P1; + Geom::Point P1_lead; + Geom::Point v1,v2; + int vertices; + Geom::Path pR = pathv_to_simple_polygon(pathv, &vertices); + *is_rect = false; + if(vertices==4){ // or else it cannot be a rectangle rectangle + int vertex_count=0; + /* Get the ends of the LAST line segment. + Find minimum rotation to align rectangle with X,Y axes. (Very degenerate if it is rotated 45 degrees.) */ + *angle = 10.0; /* must be > than the actual angle in radians. */ + for(Geom::Path::const_iterator cit = pR.begin(); cit != pR.end_open(); ++cit){ + P1_trail = cit->initialPoint(); + P1 = cit->finalPoint(); + v1 = unit_vector(P1 - P1_trail); + if(v1[Geom::X] > 0){ // only check the 1 or 2 points on vectors aimed the same direction as unit X + double ang = asin(v1[Geom::Y]); // because component is rotation by ang of {1,0| vector + if(fabs(ang) < fabs(*angle))*angle = -ang; // y increases down, flips sign on angle + } + } + + for(Geom::Path::const_iterator cit = pR.begin(); cit != pR.end_open();++cit) { + P1_lead = cit->finalPoint(); + v1 = unit_vector(P1 - P1_trail); + v2 = unit_vector(P1_lead - P1 ); + if(!Geom::are_near(dot(v1,v2),0.0))break; // P1 is center of a turn that is not 90 degrees + P1_trail = P1; + P1 = P1_lead; + vertex_count++; + } + if(vertex_count == 4){ + *is_rect=true; + } + } + return(pR); +} + +/* Compare a vector with a rectangle's orientation (angle needed to rotate side(s) + closest to horizontal to exactly horizontal) and return: + 0 none of the following + 1 parallel to horizontal + 2 parallel to vertical + 3 antiparallel to horizontal + 4 antiparallel to vertical +*/ +int PrintEmf::vector_rect_alignment(double angle, Geom::Point vtest){ + int stat = 0; + Geom::Point v1 = Geom::unit_vector(vtest); // unit vector to test alignment + Geom::Point v2 = Geom::Point(1,0) * Geom::Rotate(-angle); // unit horizontal side (sign change because Y increases DOWN) + if( Geom::are_near(dot(v1,v2), 1.0)){ stat = 1; } + else if(Geom::are_near(dot(v1,v2),-1.0)){ stat = 2; } + if(!stat){ + v2 = Geom::Point(0,1) * Geom::Rotate(-angle); // unit vertical side + if( Geom::are_near(dot(v1,v2), 1.0)){ stat = 3; } + else if(Geom::are_near(dot(v1,v2),-1.0)){ stat = 4; } + } + return(stat); +} + +/* retrieve the point at the indicated corner: + 0 UL (and default) + 1 UR + 2 LR + 3 LL + Needed because the start can be any point, and the direction could run either + clockwise or counterclockwise. This should work even if the corners of the rectangle + are slightly displaced. +*/ +Geom::Point PrintEmf::get_pathrect_corner(Geom::Path pathRect, double angle, int corner){ + Geom::Point v1 = Geom::Point(1,0) * Geom::Rotate(-angle); // unit horizontal side (sign change because Y increases DOWN) + Geom::Point v2 = Geom::Point(0,1) * Geom::Rotate(-angle); // unit vertical side (sign change because Y increases DOWN) + Geom::Point center, P1; + int LR; // 1 if Left, 0 if Right + int UL; // 1 if Lower, 0 if Upper (as viewed on screen, y coordinates increase downwards) + center = Geom::Point(0,0); + Geom::Path::const_iterator cit = pathRect.begin(); + for(; cit != pathRect.end_open();++cit) { + center += cit->initialPoint()/4.0; + } + + switch(corner){ + case 1: //UR + LR = 0; + UL = 0; + break; + case 2: //LR + LR = 0; + UL = 1; + break; + case 3: //LL + LR = 1; + UL = 1; + break; + default: //UL + LR = 1; + UL = 0; + break; + } + cit = pathRect.begin(); + for(int i; cit != pathRect.end_open();++cit,i++) { + P1 = cit->initialPoint(); + if((LR == (dot(P1 - center,v1)> 0 ? 0 : 1)) && + (UL == (dot(P1 - center,v2)> 0 ? 1 : 0)))break; + } + return(P1); +} + +U_TRIVERTEX PrintEmf::make_trivertex(Geom::Point Pt, U_COLORREF uc){ + U_TRIVERTEX tv; + using Geom::X; + using Geom::Y; + tv.x = (int32_t) round(Pt[X]); + tv.y = (int32_t) round(Pt[Y]); + tv.Red = uc.Red << 8; + tv.Green = uc.Green << 8; + tv.Blue = uc.Blue << 8; + tv.Alpha = uc.Reserved << 8; // EMF will ignore this + return(tv); +} unsigned int PrintEmf::fill( Inkscape::Extension::Print * /*mod*/, @@ -795,8 +976,27 @@ unsigned int PrintEmf::fill( use_stroke = false; fill_transform = tf; + + int brush_stat = create_brush(style, NULL); + + /* native linear gradients are only used if the object is a rectangle AND the gradient is parallel to the sides of the object */ + bool is_Rect = false; + double angle; + int rectDir=0; + Geom::Path pathRect; + if(FixPPTLinGrad && brush_stat && gv.mode == DRAW_LINEAR_GRADIENT){ + pathRect = pathv_to_rect(pathv, &is_Rect, &angle); + if(is_Rect){ + /* Gradientfill records can only be used if the gradient is parallel to the sides of the rectangle. + That must be checked here so that we can fall back to another form of gradient fill if it is not + the case. */ + rectDir = vector_rect_alignment(angle, gv.p2 - gv.p1); + if(!rectDir)is_Rect = false; + } + if(!is_Rect && !FixPPTGrad2Polys)brush_stat=0; // fall all the way back to a solid fill + } - if (create_brush(style, NULL)) { // only happens if the style is a gradient + if (brush_stat) { // only happens if the style is a gradient /* Handle gradients. Uses modified livarot as 2geom boolops is currently broken. Can handle gradients with multiple stops. @@ -819,10 +1019,10 @@ unsigned int PrintEmf::fill( SPRadialGradient *tg = (SPRadialGradient *)(gv.grad); // linear/radial are the same here nstops = tg->vector.stops.size(); sp_color_get_rgb_floatv(&tg->vector.stops[0].color, rgb); - opa = tg->vector.stops[0].opacity; + opa = tg->vector.stops[0].opacity; // first stop c1 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa); sp_color_get_rgb_floatv(&tg->vector.stops[nstops - 1].color, rgb); - opa = tg->vector.stops[nstops - 1].opacity; + opa = tg->vector.stops[nstops - 1].opacity; // last stop c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa); doff = 0.0; @@ -868,9 +1068,10 @@ unsigned int PrintEmf::fill( pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); print_pathv(pathvr, fill_transform); // show the intersection - if (doff >= doff_range - doff_base) { + if (doff >= doff_range) { istop++; if (istop >= nstops) { + istop = nstops - 1; continue; // could happen on a rounding error } doff_base = doff_range; @@ -882,56 +1083,145 @@ unsigned int PrintEmf::fill( } } } else if (gv.mode == DRAW_LINEAR_GRADIENT) { - Geom::Point uv = Geom::unit_vector(gv.p2 - gv.p1); // unit vector - Geom::Point puv = uv.cw(); // perp. to unit vector - double range = Geom::distance(gv.p1, gv.p2); // length along the gradient - double step = range / divisions; // adequate approximation for gradient - double overlap = step / 4.0; // overlap slices slightly - double start; - double stop; - Geom::PathVector pathvc, pathvr; - - /* before lower end of gradient, overlap first slice position */ - wc = weight_opacity(c1); - (void) create_brush(style, &wc); - pathvc = rect_cutter(gv.p1, uv * (overlap), uv * (-50000.0), puv * 50000.0); - pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); - print_pathv(pathvr, fill_transform); - - /* after high end of gradient, overlap last slice poosition */ - wc = weight_opacity(c2); - (void) create_brush(style, &wc); - pathvc = rect_cutter(gv.p2, uv * (-overlap), uv * (50000.0), puv * 50000.0); - pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); - print_pathv(pathvr, fill_transform); + if(is_Rect){ + char *rec; + int gMode; + Geom::Point ul, ur, lr; + Geom::Point outUL, outLR; // UL,LR corners of a stop rectangle, in OUTPUT coordinates + U_TRIVERTEX ut[2]; + U_GRADIENT4 ug4; + U_RECTL rcb; + Geom::Affine tf2; + U_XFORM tmpTransform; + double wRect, hRect; + + /* coordinates, w,h and transform for the ENTIRE retangle */ + ul = get_pathrect_corner(pathRect, angle, 0) * fill_transform * PX2WORLD; + ur = get_pathrect_corner(pathRect, angle, 1) * fill_transform * PX2WORLD; + lr = get_pathrect_corner(pathRect, angle, 2) * fill_transform * PX2WORLD; + wRect = Geom::distance(ul,ur); + hRect = Geom::distance(ur,lr); + + /* The basic rectangle for all of these is placed with its UL corner at 0,0 with a size wRect,hRect. + Apply a world transform to place/scale it into the appropriate position on the drawing. + Actual gradientfill records are either this entire rectangle or slices of it as defined by the stops. + */ + + tf2 = Geom::Rotate(-angle); + tmpTransform.eM11 = tf2[0]; + tmpTransform.eM12 = tf2[1]; + tmpTransform.eM21 = tf2[2]; + tmpTransform.eM22 = tf2[3]; + tmpTransform.eDx = (ul)[Geom::X]; + tmpTransform.eDy = (ul)[Geom::Y]; + + rec = U_EMRSAVEDC_set(); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { + g_error("Fatal programming error in PrintEmf::image at U_EMRSAVEDC_set"); + } - sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); - opa = tg->vector.stops[istop].opacity; - c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa); + rec = U_EMRMODIFYWORLDTRANSFORM_set(tmpTransform, U_MWT_LEFTMULTIPLY); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { + g_error("Fatal programming error in PrintEmf::image at EMRMODIFYWORLDTRANSFORM"); + } + + for(;istop<nstops;istop++){ + doff_range = tg->vector.stops[istop].offset; // next or last stop + if(rectDir == 1 || rectDir == 2){ + outUL = Geom::Point(doff_base *wRect, 0 ); + outLR = Geom::Point(doff_range*wRect, hRect); + gMode = U_GRADIENT_FILL_RECT_H; + } + else { + outUL = Geom::Point(0, doff_base *hRect); + outLR = Geom::Point(wRect,doff_range*hRect); + gMode = U_GRADIENT_FILL_RECT_V; + } + doff_base = doff_range; + rcb.left = outUL[X]; + rcb.top = outUL[Y]; + rcb.right = outLR[X]; + rcb.bottom = outLR[Y]; + sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); + opa = tg->vector.stops[istop].opacity; + c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa); + + if(rectDir == 2 || rectDir == 4){ // gradient is reversed, so swap colors + ut[0] = make_trivertex(outUL, c2); + ut[1] = make_trivertex(outLR, c1); + } + else { + ut[0] = make_trivertex(outUL, c1); + ut[1] = make_trivertex(outLR, c2); + } + c1 = c2; // for next stop + ug4.UpperLeft = 0; + ug4.LowerRight= 1; + /* NEED to push world transform here for rotations */ + rec = U_EMRGRADIENTFILL_set(rcb, 2, 1, gMode, ut, (uint32_t *) &ug4 ); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { + g_error("Fatal programming error in PrintEmf::fill at U_EMRGRADIENTFILL_set"); + } + } - for (start = 0.0; start < range; start += step, doff += 1. / divisions) { - stop = start + step + overlap; - if (stop > range) { - stop = range; + rec = U_EMRRESTOREDC_set(-1); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { + g_error("Fatal programming error in PrintEmf::fill at U_EMRRESTOREDC_set"); } - pathvc = rect_cutter(gv.p1, uv * start, uv * stop, puv * 50000.0); + } + else { + Geom::Point uv = Geom::unit_vector(gv.p2 - gv.p1); // unit vector + Geom::Point puv = uv.cw(); // perp. to unit vector + double range = Geom::distance(gv.p1, gv.p2); // length along the gradient + double step = range / divisions; // adequate approximation for gradient + double overlap = step / 4.0; // overlap slices slightly + double start; + double stop; + Geom::PathVector pathvc, pathvr; + + /* before lower end of gradient, overlap first slice position */ + wc = weight_opacity(c1); + (void) create_brush(style, &wc); + pathvc = rect_cutter(gv.p1, uv * (overlap), uv * (-50000.0), puv * 50000.0); + pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); + print_pathv(pathvr, fill_transform); - wc = weight_colors(c1, c2, (doff - doff_base) / (doff_range - doff_base)); + /* after high end of gradient, overlap last slice position */ + wc = weight_opacity(c2); (void) create_brush(style, &wc); - Geom::PathVector pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); - print_pathv(pathvr, fill_transform); // show the intersection + pathvc = rect_cutter(gv.p2, uv * (-overlap), uv * (50000.0), puv * 50000.0); + pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); + print_pathv(pathvr, fill_transform); - if (doff >= doff_range - doff_base) { - istop++; - if (istop >= nstops) { - continue; // could happen on a rounding error + sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); + opa = tg->vector.stops[istop].opacity; + c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa); + + for (start = 0.0; start < range; start += step, doff += 1. / divisions) { + stop = start + step + overlap; + if (stop > range) { + stop = range; + } + pathvc = rect_cutter(gv.p1, uv * start, uv * stop, puv * 50000.0); + + wc = weight_colors(c1, c2, (doff - doff_base) / (doff_range - doff_base)); + (void) create_brush(style, &wc); + Geom::PathVector pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); + print_pathv(pathvr, fill_transform); // show the intersection + + if (doff >= doff_range) { + istop++; + if (istop >= nstops) { + istop = nstops - 1; + continue; // could happen on a rounding error + } + doff_base = doff_range; + doff_range = tg->vector.stops[istop].offset; // next or last stop + c1 = c2; + sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); + opa = tg->vector.stops[istop].opacity; + c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa); } - doff_base = doff_range; - doff_range = tg->vector.stops[istop].offset; // next or last stop - c1 = c2; - sp_color_get_rgb_floatv(&tg->vector.stops[istop].color, rgb); - opa = tg->vector.stops[istop].opacity; - c2 = U_RGBA(255 * rgb[0], 255 * rgb[1], 255 * rgb[2], 255 * opa); } } } else { @@ -1301,6 +1591,10 @@ unsigned int PrintEmf::image( U_POINTL cDest = pointl_set(round(dw * PX2WORLD), round(dh * PX2WORLD)); U_POINTL Src = pointl_set(0, 0); U_POINTL cSrc = pointl_set(w, h); + /* map the integer Dest coordinates back into pLL2, so that the rounded part does not destabilize the transform offset below */ + pLL2[Geom::X] = Dest.x; + pLL2[Geom::Y] = Dest.y; + pLL2 /= PX2WORLD; if (!FixImageRot) { /* Rotate images - some programs cannot read them in correctly if they are rotated */ tf[4] = tf[5] = 0.0; // get rid of the offset in the transform Geom::Point pLL2prime = pLL2 * tf; @@ -1309,7 +1603,7 @@ unsigned int PrintEmf::image( tmpTransform.eM12 = tf[1]; tmpTransform.eM21 = tf[2]; tmpTransform.eM22 = tf[3]; - tmpTransform.eDx = (pLL2[Geom::X] - pLL2prime[Geom::X]) * PX2WORLD; //map pLL2 (now in EMF coordinates) back onto itself after the rotation + tmpTransform.eDx = (pLL2[Geom::X] - pLL2prime[Geom::X]) * PX2WORLD; tmpTransform.eDy = (pLL2[Geom::Y] - pLL2prime[Geom::Y]) * PX2WORLD; rec = U_EMRSAVEDC_set(); @@ -1734,6 +2028,7 @@ void PrintEmf::init(void) "<param name=\"FixPPTCharPos\" type=\"boolean\">false</param>\n" "<param name=\"FixPPTDashLine\" type=\"boolean\">false</param>\n" "<param name=\"FixPPTGrad2Polys\" type=\"boolean\">false</param>\n" + "<param name=\"FixPPTLinGrad\" type=\"boolean\">false</param>\n" "<param name=\"FixPPTPatternAsHatch\" type=\"boolean\">false</param>\n" "<param name=\"FixImageRot\" type=\"boolean\">false</param>\n" "<print/>\n" diff --git a/src/extension/internal/emf-print.h b/src/extension/internal/emf-print.h index 1546fcaea..8fc9908e3 100644 --- a/src/extension/internal/emf-print.h +++ b/src/extension/internal/emf-print.h @@ -68,6 +68,11 @@ public: protected: static void smuggle_adxkyrtl_out(const char *string, uint32_t **adx, double *ky, int *rtl, int *ndx, float scale); + Geom::Path pathv_to_simple_polygon(Geom::PathVector const &pathv, int *vertices); + Geom::Path pathv_to_rect(Geom::PathVector const &pathv, bool *is_rect, double *angle); + Geom::Point get_pathrect_corner(Geom::Path pathRect, double angle, int corner); + U_TRIVERTEX make_trivertex(Geom::Point Pt, U_COLORREF uc); + int vector_rect_alignment(double angle, Geom::Point vtest); int create_brush(SPStyle const *style, PU_COLORREF fcolor); void destroy_brush(); int create_pen(SPStyle const *style, const Geom::Affine &transform); diff --git a/src/extension/internal/metafile-inout.cpp b/src/extension/internal/metafile-inout.cpp new file mode 100644 index 000000000..c7ae53370 --- /dev/null +++ b/src/extension/internal/metafile-inout.cpp @@ -0,0 +1,210 @@ +/** @file + * @brief Metafile input - common routines + *//* + * Authors: + * David Mathog + * + * Copyright (C) 2013 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <cstring> +#include <fstream> +#include <glib.h> +#include <glibmm/miscutils.h> + +#include "extension/internal/metafile-inout.h" // picks up PNG +#include "extension/print.h" +#include "path-prefix.h" +#include "sp-gradient.h" +#include "sp-image.h" +#include "sp-linear-gradient.h" +#include "sp-pattern.h" +#include "sp-radial-gradient.h" +#include "style.h" + +namespace Inkscape { +namespace Extension { +namespace Internal { + +Metafile::~Metafile() +{ + return; +} + +/** Construct a PNG in memory from an RGB from the EMF file + +from: +http://www.lemoda.net/c/write-png/ + +which was based on: +http://stackoverflow.com/questions/1821806/how-to-encode-png-to-buffer-using-libpng + +gcc -Wall -o testpng testpng.c -lpng + +Originally here, but moved up + +#include <png.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +*/ + + +/* Given "bitmap", this returns the pixel of bitmap at the point + ("x", "y"). */ + +pixel_t * Metafile::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 +Metafile::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 Metafile::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 (uint8_t) * bitmap->width * pixel_size); + row_pointers[bitmap->height - y - 1] = row; // Row order in EMF 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 EMF RGB(A) color to 0RGB +inverse of gethexcolor() in emf-print.cpp +*/ +uint32_t Metafile::sethexcolor(U_COLORREF color){ + + uint32_t out; + out = (U_RGBAGetR(color) << 16) + + (U_RGBAGetG(color) << 8 ) + + (U_RGBAGetB(color) ); + return(out); +} + +/* Return the base64 encoded png which is shown for all bad images. +Currently a random 3x4 blotch. +Caller must free. +*/ +gchar *Metafile::bad_image_png(void){ + gchar *gstring = g_strdup("iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII="); + return(gstring); +} + + + +} // namespace Internal +} // namespace Extension +} // namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/extension/internal/metafile-inout.h b/src/extension/internal/metafile-inout.h new file mode 100644 index 000000000..968773a3a --- /dev/null +++ b/src/extension/internal/metafile-inout.h @@ -0,0 +1,93 @@ +/** @file + * @brief Metafile input - common functions + *//* + * Authors: + * David Mathog + * + * Copyright (C) 2013 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_EXTENSION_INTERNAL_METAFILE_INOUT_H +#define SEEN_INKSCAPE_EXTENSION_INTERNAL_METAFILE_INOUT_H + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#define PNG_SKIP_SETJMP_CHECK // else any further png.h include blows up in the compiler +#include <png.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <map> +#include <stack> +#include <glibmm/ustring.h> +#include <libuemf/uemf.h> +#include <2geom/affine.h> +#include <2geom/pathvector.h> + +#include "extension/implementation/implementation.h" + +class SPObject; + +namespace Inkscape { +class Pixbuf; + +namespace Extension { +namespace Internal { + +/* A coloured pixel. */ +typedef struct { + uint8_t red; + uint8_t green; + uint8_t blue; + uint8_t 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; + +class Metafile + : public Inkscape::Extension::Implementation::Implementation +{ +public: + Metafile() {} + ~Metafile(); + +protected: + static uint32_t sethexcolor(U_COLORREF color); + static pixel_t *pixel_at (bitmap_t * bitmap, int x, int y); + static void my_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length); + static void toPNG(PMEMPNG accum, int width, int height, const char *px); + static gchar *bad_image_png(void); + + +private: +}; + +} // namespace Internal +} // namespace Extension +} // namespace Inkscape + +#endif // SEEN_INKSCAPE_EXTENSION_INTERNAL_METAFILE_INOUT_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ diff --git a/src/extension/internal/metafile-print.cpp b/src/extension/internal/metafile-print.cpp index 1e7735410..73d63f27d 100644 --- a/src/extension/internal/metafile-print.cpp +++ b/src/extension/internal/metafile-print.cpp @@ -187,7 +187,6 @@ U_COLORREF PrintMetafile::avg_stop_color(SPGradient *gr) return cr; } -#define clrweight(a,b,t) ((1-t)*((double) a) + (t)*((double) b)) U_COLORREF PrintMetafile::weight_opacity(U_COLORREF c1) { float opa = c1.Reserved / 255.0; @@ -199,9 +198,12 @@ U_COLORREF PrintMetafile::weight_opacity(U_COLORREF c1) return result; } +/* t between 0 and 1, values outside that range use the nearest limit */ U_COLORREF PrintMetafile::weight_colors(U_COLORREF c1, U_COLORREF c2, double t) { +#define clrweight(a,b,t) ((1-t)*((double) a) + (t)*((double) b)) U_COLORREF result; + t = ( t > 1.0 ? 1.0 : ( t < 0.0 ? 0.0 : t)); result.Red = clrweight(c1.Red, c2.Red, t); result.Green = clrweight(c1.Green, c2.Green, t); result.Blue = clrweight(c1.Blue, c2.Blue, t); diff --git a/src/extension/internal/wmf-inout.cpp b/src/extension/internal/wmf-inout.cpp index 870e4061c..a72c16a88 100644 --- a/src/extension/internal/wmf-inout.cpp +++ b/src/extension/internal/wmf-inout.cpp @@ -26,7 +26,7 @@ # include "config.h" #endif -#include <png.h> //This must precede text_reassemble.h or it blows up in pngconf.h when compiling +//#include <png.h> //This must precede text_reassemble.h or it blows up in pngconf.h when compiling #include <stdio.h> #include <stdlib.h> #include <stdint.h> @@ -70,154 +70,6 @@ static U_RECT16 rc_old; static bool clipset = false; static uint32_t BLTmode=0; -/** Construct a PNG in memory from an RGB from the WMF file - -from: -http://www.lemoda.net/c/write-png/ - -which was based on: -http://stackoverflow.com/questions/1821806/how-to-encode-png-to-buffer-using-libpng - -gcc -Wall -o testpng testpng.c -lpng - -Originally here, but moved up - -#include <png.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -*/ - - -/* 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 (uint8_t) * 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 -*/ -uint32_t Wmf::sethexcolor(U_COLORREF color){ - - uint32_t out; - out = (U_RGBAGetR(color) << 16) + - (U_RGBAGetG(color) << 8 ) + - (U_RGBAGetB(color) ); - return(out); -} - - Wmf::Wmf (void) // The null constructor { return; diff --git a/src/extension/internal/wmf-inout.h b/src/extension/internal/wmf-inout.h index 90f424c46..3d23ca749 100644 --- a/src/extension/internal/wmf-inout.h +++ b/src/extension/internal/wmf-inout.h @@ -11,9 +11,8 @@ #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 <png.h> #include <libuemf/uwmf.h> +#include "extension/internal/metafile-inout.h" // picks up PNG #include "extension/implementation/implementation.h" #include "style.h" #include "text_reassemble.h" @@ -69,35 +68,6 @@ typedef struct wmf_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 { - uint8_t red; - uint8_t green; - uint8_t blue; - uint8_t 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 { @@ -138,7 +108,8 @@ typedef struct { PWMF_OBJECT wmf_obj; } WMF_CALLBACK_DATA, *PWMF_CALLBACK_DATA; -class Wmf : Inkscape::Extension::Implementation::Implementation { //This is a derived class +class Wmf : public Metafile +{ public: Wmf(); // Empty constructor @@ -158,10 +129,6 @@ public: private: protected: - static pixel_t *pixel_at (bitmap_t * bitmap, int x, int y); - static void my_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length); - static void toPNG(PMEMPNG accum, int width, int height, const char *px); - static uint32_t sethexcolor(U_COLORREF color); static void print_document_to_file(SPDocument *doc, const gchar *filename); static double current_scale(PWMF_CALLBACK_DATA d); static std::string current_matrix(PWMF_CALLBACK_DATA d, double x, double y, int useoffset); diff --git a/src/extension/internal/wmf-print.cpp b/src/extension/internal/wmf-print.cpp index d60b2adf7..1c7b42c82 100644 --- a/src/extension/internal/wmf-print.cpp +++ b/src/extension/internal/wmf-print.cpp @@ -76,7 +76,7 @@ namespace Internal { /* globals */ -static double PX2WORLD = 1200.0 / 90.0; // inkscape is 90 dpi, WMF file is 1200 +static double PX2WORLD; // value set in begin() static bool FixPPTCharPos, FixPPTDashLine, FixPPTGrad2Polys, FixPPTPatternAsHatch; static WMFTRACK *wt = NULL; static WMFHANDLES *wht = NULL; @@ -128,6 +128,8 @@ unsigned int PrintWmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc) char *rec; gchar const *utf8_fn = mod->get_param_string("destination"); + // Typically PX2WORLD is 1200/90, using inkscape's default dpi + PX2WORLD = 1200.0 / Inkscape::Util::Quantity::convert(1.0, "in", "px"); FixPPTCharPos = mod->get_param_bool("FixPPTCharPos"); FixPPTDashLine = mod->get_param_bool("FixPPTDashLine"); FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys"); @@ -188,39 +190,39 @@ unsigned int PrintWmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc) int dwPxY = round(d.height() * 1200.0); #endif - PU_PAIRF ps = U_PAIRF_set(dwInchesX, dwInchesY); + U_PAIRF *ps = U_PAIRF_set(dwInchesX, dwInchesY); rec = U_WMRHEADER_set(ps, 1200); // Example: drawing is A4 horizontal, 1200 dpi if (!rec) { g_error("Fatal programming error in PrintWmf::begin at WMRSETMAPMODE"); } - (void) wmf_header_append((PU_METARECORD)rec, wt, 1); + (void) wmf_header_append((U_METARECORD *)rec, wt, 1); free(ps); rec = U_WMRSETWINDOWEXT_set(point16_set(dwPxX, dwPxY)); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at WMRSETWINDOWEXT"); } rec = U_WMRSETWINDOWORG_set(point16_set(0, 0)); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at WMRSETWINDOWORG"); } rec = U_WMRSETMAPMODE_set(U_MM_ANISOTROPIC); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at WMRSETMAPMODE"); } /* set some parameters, else the program that reads the WMF may default to other values */ rec = U_WMRSETBKMODE_set(U_TRANSPARENT); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at U_WMRSETBKMODE"); } hpolyfillmode = U_WINDING; rec = U_WMRSETPOLYFILLMODE_set(U_WINDING); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at U_WMRSETPOLYFILLMODE"); } @@ -229,24 +231,24 @@ unsigned int PrintWmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc) // actually starts, and already takes into account the text object's alignment; // - for this reason, the WMF text alignment must always be TA_BASELINE|TA_LEFT. rec = U_WMRSETTEXTALIGN_set(U_TA_BASELINE | U_TA_LEFT); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at U_WMRSETTEXTALIGN_set"); } htextcolor_rgb[0] = htextcolor_rgb[1] = htextcolor_rgb[2] = 0.0; rec = U_WMRSETTEXTCOLOR_set(U_RGB(0, 0, 0)); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at U_WMRSETTEXTCOLOR_set"); } rec = U_WMRSETROP2_set(U_R2_COPYPEN); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at U_WMRSETROP2"); } hmiterlimit = 5; rec = wmiterlimit_set(5); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at wmiterlimit_set"); } @@ -255,14 +257,14 @@ unsigned int PrintWmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc) U_PEN up = U_PEN_set(U_PS_SOLID, 1, colorref_set(0, 0, 0)); uint32_t Pen; rec = wcreatepenindirect_set(&Pen, wht, up); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at wcreatepenindirect_set"); } // create a null pen. If no specific pen is set, this is used up = U_PEN_set(U_PS_NULL, 1, colorref_set(0, 0, 0)); rec = wcreatepenindirect_set(&hpen_null, wht, up); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at wcreatepenindirect_set"); } destroy_pen(); // make this pen active @@ -270,7 +272,7 @@ unsigned int PrintWmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc) // create a null brush. If no specific brush is set, this is used U_WLOGBRUSH lb = U_WLOGBRUSH_set(U_BS_NULL, U_RGB(0, 0, 0), U_HS_HORIZONTAL); rec = wcreatebrushindirect_set(&hbrush_null, wht, lb); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::begin at wcreatebrushindirect_set"); } destroy_brush(); // make this brush active @@ -288,25 +290,25 @@ unsigned int PrintWmf::finish(Inkscape::Extension::Print * /*mod*/) // get rid of null brush rec = wdeleteobject_set(&hbrush_null, wht); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::finish at wdeleteobject_set null brush"); } // get rid of null pen rec = wdeleteobject_set(&hpen_null, wht); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::finish at wdeleteobject_set null pen"); } // get rid of object 0, which was a pen that was used to shift the other object indices to >=1. hpen = 0; rec = wdeleteobject_set(&hpen, wht); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::finish at wdeleteobject_set filler object"); } rec = U_WMREOF_set(); // generate the EOF record - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::finish"); } (void) wmf_finish(wt); // Finalize and write out the WMF @@ -330,7 +332,7 @@ unsigned int PrintWmf::comment(Inkscape::Extension::Print * /*module*/, const ch // fcolor is defined when gradients are being expanded, it is the color of one stripe or ring. -int PrintWmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) +int PrintWmf::create_brush(SPStyle const *style, U_COLORREF *fcolor) { float rgb[3]; char *rec; @@ -442,17 +444,17 @@ int PrintWmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) // SVG text has no background attribute, so OPAQUE mode ALWAYS cancels after the next draw, otherwise it would mess up future text output. if (usebk) { rec = U_WMRSETBKCOLOR_set(bkColor); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::create_brush at U_WMRSETBKCOLOR_set"); } rec = U_WMRSETBKMODE_set(U_OPAQUE); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::create_brush at U_WMRSETBKMODE_set"); } } lb = U_WLOGBRUSH_set(brushStyle, hatchColor, hatchType); rec = wcreatebrushindirect_set(&brush, wht, lb); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::create_brush at createbrushindirect_set"); } break; @@ -461,10 +463,10 @@ int PrintWmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) char *rgba_px; uint32_t cbPx; uint32_t colortype; - PU_RGBQUAD ct; + U_RGBQUAD *ct; int numCt; U_BITMAPINFOHEADER Bmih; - PU_BITMAPINFO Bmi; + U_BITMAPINFO *Bmi; rgba_px = (char *) pixbuf->pixels(); // Do NOT free this!!! colortype = U_BCBM_COLOR32; (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width * 4, colortype, 0, 1); @@ -474,7 +476,7 @@ int PrintWmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0); Bmi = bitmapinfo_set(Bmih, ct); rec = wcreatedibpatternbrush_srcdib_set(&brush, wht, U_DIB_RGB_COLORS, Bmi, cbPx, px); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::create_brush at createdibpatternbrushpt_set"); } free(px); @@ -484,14 +486,14 @@ int PrintWmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) hbrush = brush; // need this later for destroy_brush rec = wselectobject_set(brush, wht); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::create_brush at wselectobject_set"); } if (fmode != hpolyfillmode) { hpolyfillmode = fmode; rec = U_WMRSETPOLYFILLMODE_set(fmode); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::create_brush at U_WMRSETPOLYFILLMODE_set"); } } @@ -506,7 +508,7 @@ void PrintWmf::destroy_brush() // WMF lets any object be deleted whenever, and the chips fall where they may... if (hbrush) { rec = wdeleteobject_set(&hbrush, wht); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::destroy_brush"); } hbrush = 0; @@ -515,7 +517,7 @@ void PrintWmf::destroy_brush() // (re)select the null brush rec = wselectobject_set(hbrush_null, wht); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::destroy_brush"); } } @@ -583,7 +585,7 @@ int PrintWmf::create_pen(SPStyle const *style, const Geom::Affine &transform) if ((uint32_t)miterlimit != hmiterlimit) { hmiterlimit = (uint32_t)miterlimit; rec = wmiterlimit_set((uint32_t) miterlimit); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::create_pen at wmiterlimit_set"); } } @@ -605,12 +607,12 @@ int PrintWmf::create_pen(SPStyle const *style, const Geom::Affine &transform) up = U_PEN_set(penstyle | modstyle, linewidth, penColor); rec = wcreatepenindirect_set(&pen, wht, up); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::create_pen at wcreatepenindirect_set"); } rec = wselectobject_set(pen, wht); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::create_pen at wselectobject_set"); } hpen = pen; // need this later for destroy_pen @@ -625,7 +627,7 @@ void PrintWmf::destroy_pen() // WMF lets any object be deleted whenever, and the chips fall where they may... if (hpen) { rec = wdeleteobject_set(&hpen, wht); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::destroy_pen"); } hpen = 0; @@ -634,7 +636,7 @@ void PrintWmf::destroy_pen() // (re)select the null pen rec = wselectobject_set(hpen_null, wht); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::destroy_pen"); } } @@ -757,7 +759,7 @@ unsigned int PrintWmf::fill( pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_nonZero, frb); print_pathv(pathvr, fill_transform); - /* after high end of gradient, overlap last slice poosition */ + /* after high end of gradient, overlap last slice position */ wc = weight_opacity(c2); (void) create_brush(style, &wc); pathvc = rect_cutter(gv.p2, uv * (-overlap), uv * (50000.0), puv * 50000.0); @@ -898,7 +900,7 @@ unsigned int PrintWmf::stroke( if (usebk) { // OPAQUE was set, revert to TRANSPARENT usebk = false; rec = U_WMRSETBKMODE_set(U_TRANSPARENT); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::stroke at U_WMRSETBKMODE_set"); } } @@ -1066,7 +1068,7 @@ bool PrintWmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff }); rec = U_WMRELLIPSE_set(rcl); } - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::print_simple_shape at retangle/ellipse/polygon"); } @@ -1109,7 +1111,7 @@ unsigned int PrintWmf::image( Geom::Affine tf = m_tr_stack.top(); rec = U_WMRSETSTRETCHBLTMODE_set(U_COLORONCOLOR); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::image at EMRHEADER"); } @@ -1126,10 +1128,10 @@ unsigned int PrintWmf::image( char *px; uint32_t cbPx; uint32_t colortype; - PU_RGBQUAD ct; + U_RGBQUAD *ct; int numCt; U_BITMAPINFOHEADER Bmih; - PU_BITMAPINFO Bmi; + U_BITMAPINFO *Bmi; colortype = U_BCBM_COLOR32; (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, (char *) rgba_px, w, h, w * 4, colortype, 0, 1); Bmih = bitmapinfoheader_set(w, h, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0); @@ -1150,7 +1152,7 @@ unsigned int PrintWmf::image( h * rs, //! size in bytes of px px //! (Optional) bitmapbuffer (U_BITMAPINFO section) ); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::image at U_WMRSTRETCHDIB_set"); } free(px); @@ -1165,7 +1167,7 @@ unsigned int PrintWmf::image( unsigned int PrintWmf::print_pathv(Geom::PathVector const &pathv, const Geom::Affine &transform) { char *rec = NULL; - PU_POINT16 pt16hold, pt16ptr; + U_POINT16 *pt16hold, *pt16ptr; uint16_t *n16hold; uint16_t *n16ptr; @@ -1199,7 +1201,7 @@ unsigned int PrintWmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af } if (nPolys > 1) { // a single polypolygon, a single polygon falls through to the else - pt16hold = pt16ptr = (PU_POINT16) malloc(totPoints * sizeof(U_POINT16)); + pt16hold = pt16ptr = (U_POINT16 *) malloc(totPoints * sizeof(U_POINT16)); if (!pt16ptr) { return(false); } @@ -1235,7 +1237,7 @@ unsigned int PrintWmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af } rec = U_WMRPOLYPOLYGON_set(nPolys, n16hold, pt16hold); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRPOLYPOLYGON_set"); } free(pt16hold); @@ -1256,7 +1258,7 @@ unsigned int PrintWmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af */ int nPoints = 1 + pit->size_default(); - pt16hold = pt16ptr = (PU_POINT16) malloc(nPoints * sizeof(U_POINT16)); + pt16hold = pt16ptr = (U_POINT16 *) malloc(nPoints * sizeof(U_POINT16)); if (!pt16ptr) { break; } @@ -1280,21 +1282,21 @@ unsigned int PrintWmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af if (pit->end_default() == pit->end_closed()) { rec = U_WMRPOLYGON_set(nPoints, pt16hold); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRPOLYGON_set"); } } else if (nPoints > 2) { rec = U_WMRPOLYLINE_set(nPoints, pt16hold); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::print_pathv at U_POLYLINE_set"); } } else if (nPoints == 2) { rec = U_WMRMOVETO_set(pt16hold[0]); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRMOVETO_set"); } rec = U_WMRLINETO_set(pt16hold[1]); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRLINETO_set"); } } @@ -1348,7 +1350,7 @@ unsigned int PrintWmf::text(Inkscape::Extension::Print * /*mod*/, char const *te if (textalignment != htextalignment) { htextalignment = textalignment; rec = U_WMRSETTEXTALIGN_set(textalignment); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::text at U_WMRSETTEXTALIGN_set"); } } @@ -1420,7 +1422,7 @@ unsigned int PrintWmf::text(Inkscape::Extension::Print * /*mod*/, char const *te // it was streteched asymmetrically.) Few applications support text from WMF which is scaled // differently by height/width, so leave lfWidth alone. - PU_FONT puf = U_FONT_set( + U_FONT *puf = U_FONT_set( textheight, 0, round(rot), @@ -1438,14 +1440,14 @@ unsigned int PrintWmf::text(Inkscape::Extension::Print * /*mod*/, char const *te free(facename); rec = wcreatefontindirect_set(&hfont, wht, puf); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::text at wcreatefontindirect_set"); } free(puf); } rec = wselectobject_set(hfont, wht); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::text at wselectobject_set"); } @@ -1455,7 +1457,7 @@ unsigned int PrintWmf::text(Inkscape::Extension::Print * /*mod*/, char const *te if (memcmp(htextcolor_rgb, rgb, 3 * sizeof(float))) { memcpy(htextcolor_rgb, rgb, 3 * sizeof(float)); rec = U_WMRSETTEXTCOLOR_set(U_RGB(255 * rgb[0], 255 * rgb[1], 255 * rgb[2])); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::text at U_WMRSETTEXTCOLOR_set"); } } @@ -1522,12 +1524,12 @@ unsigned int PrintWmf::text(Inkscape::Extension::Print * /*mod*/, char const *te } free(latin1_text); free(adx); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::text at U_WMREXTTEXTOUTW_set"); } rec = wdeleteobject_set(&hfont, wht); - if (!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)) { + if (!rec || wmf_append((U_METARECORD *)rec, wt, U_REC_FREE)) { g_error("Fatal programming error in PrintWmf::text at wdeleteobject_set"); } |
