diff options
| author | Jabier Arraiza Cenoz <jabier.arraiza@marker.es> | 2014-04-01 17:00:00 +0000 |
|---|---|---|
| committer | Jabiertxof <jtx@jtx.marker.es> | 2014-04-01 17:00:00 +0000 |
| commit | 208ccdf9782984702f79b8ba416e67dd1e2c2dfa (patch) | |
| tree | 79d15123aa526c49c6386db6245fbfc6b7a63eaf /src/extension | |
| parent | update to trunk (diff) | |
| parent | partial 2geom update: (diff) | |
| download | inkscape-208ccdf9782984702f79b8ba416e67dd1e2c2dfa.tar.gz inkscape-208ccdf9782984702f79b8ba416e67dd1e2c2dfa.zip | |
update to trunk
(bzr r12588.1.32)
Diffstat (limited to 'src/extension')
34 files changed, 1594 insertions, 1119 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/dbus/doc/spec-to-docbook.xsl b/src/extension/dbus/doc/spec-to-docbook.xsl index e200a05e0..a4e792df0 100644 --- a/src/extension/dbus/doc/spec-to-docbook.xsl +++ b/src/extension/dbus/doc/spec-to-docbook.xsl @@ -491,7 +491,7 @@ See also: <xsl:template name="pad-spaces"> <xsl:param name="width"/> - <xsl:variable name="spaces" xml:space="preserve"> </xsl:variable> + <xsl:variable name="spaces" select="' '" ></xsl:variable> <xsl:value-of select="substring($spaces,1,$width)"/> </xsl:template> diff --git a/src/extension/error-file.cpp b/src/extension/error-file.cpp index 5a8bede70..f60af870f 100644 --- a/src/extension/error-file.cpp +++ b/src/extension/error-file.cpp @@ -39,7 +39,7 @@ namespace Extension { probably good to check anyway). */ ErrorFileNotice::ErrorFileNotice (void) : - Gtk::MessageDialog::MessageDialog( + Gtk::MessageDialog( "", /* message */ false, /* use markup */ Gtk::MESSAGE_WARNING, /* dialog type */ diff --git a/src/extension/execution-env.h b/src/extension/execution-env.h index 92f496b90..795f5a65a 100644 --- a/src/extension/execution-env.h +++ b/src/extension/execution-env.h @@ -17,8 +17,6 @@ #include <gtkmm/dialog.h> -#include "extension.h" - namespace Inkscape { namespace UI { diff --git a/src/extension/implementation/xslt.cpp b/src/extension/implementation/xslt.cpp index 9dd9c83ee..bcea06cb5 100644 --- a/src/extension/implementation/xslt.cpp +++ b/src/extension/implementation/xslt.cpp @@ -177,7 +177,7 @@ XSLT::open(Inkscape::Extension::Input */*module*/, gchar const *filename) } g_free(s); - SPDocument * doc = SPDocument::createDoc(rdoc, filename, base, name, true); + SPDocument * doc = SPDocument::createDoc(rdoc, filename, base, name, true, NULL); g_free(base); g_free(name); 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..c09b8e9c8 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -72,8 +72,8 @@ #include <cairo-ft.h> #endif #ifdef CAIRO_HAS_WIN32_FONT -#include <cairo-win32.h> #include <pango/pangowin32.h> +#include <cairo-win32.h> #endif #include <pango/pangofc-fontmap.h> @@ -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()); @@ -1301,10 +1297,14 @@ CairoRenderContext::_setStrokeStyle(SPStyle const *style, Geom::OptRect const &p } } - if (style->stroke_dash.n_dash && - style->stroke_dash.dash ) + if (!style->stroke_dasharray.values.empty()) { - cairo_set_dash(_cr, style->stroke_dash.dash, style->stroke_dash.n_dash, style->stroke_dash.offset); + size_t ndashes = style->stroke_dasharray.values.size(); + double* dashes =(double*)malloc(ndashes*sizeof(double)); + for( unsigned i = 0; i < ndashes; ++i ) { + dashes[i] = style->stroke_dasharray.values[i]; + } + cairo_set_dash(_cr, dashes, ndashes, style->stroke_dashoffset.value); } else { cairo_set_dash(_cr, NULL, 0, 0.0); // disable dashing } @@ -1437,7 +1437,7 @@ CairoRenderContext::renderPathVector(Geom::PathVector const & pathv, SPStyle con } bool CairoRenderContext::renderImage(Inkscape::Pixbuf *pb, - Geom::Affine const &image_transform, SPStyle const * /*style*/) + Geom::Affine const &image_transform, SPStyle const *style) { g_assert( _is_valid ); @@ -1472,6 +1472,27 @@ bool CairoRenderContext::renderImage(Inkscape::Pixbuf *pb, cairo_rectangle(_cr, 0, 0, w, h); cairo_clip(_cr); } + + // Cairo filter method will be mapped to PS/PDF 'interpolate' true/false). + // See cairo-pdf-surface.c + if (style) { + // See: http://www.w3.org/TR/SVG/painting.html#ImageRenderingProperty + // http://www.w3.org/TR/css4-images/#the-image-rendering + // style.h/style.cpp + switch (style->image_rendering.computed) { + case SP_CSS_COLOR_RENDERING_AUTO: + // Do nothing + break; + case SP_CSS_COLOR_RENDERING_OPTIMIZEQUALITY: + cairo_pattern_set_filter(cairo_get_source(_cr), CAIRO_FILTER_BEST ); + break; + case SP_CSS_COLOR_RENDERING_OPTIMIZESPEED: + default: + cairo_pattern_set_filter(cairo_get_source(_cr), CAIRO_FILTER_NEAREST ); + break; + } + } + cairo_paint_with_alpha(_cr, opacity); cairo_restore(_cr); 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..eae3bfb5a 100644 --- a/src/extension/internal/emf-inout.cpp +++ b/src/extension/internal/emf-inout.cpp @@ -4,6 +4,7 @@ /* Authors: * Ulf Erikson <ulferikson@users.sf.net> * Jon A. Cruz <jon@joncruz.org> + * David Mathog * Abhishek Sharma * * Copyright (C) 2006-2008 Authors @@ -26,7 +27,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 +70,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; @@ -270,7 +123,7 @@ Emf::print_document_to_file(SPDocument *doc, const gchar *filename) throw Inkscape::Extension::Output::save_failed(); } mod->base->invoke_print(&context); - ret = mod->finish(); + (void) mod->finish(); /* Release arena */ mod->base->invoke_hide(mod->dkey); mod->base = NULL; @@ -298,6 +151,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 +165,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 +470,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 +482,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; @@ -713,6 +554,7 @@ uint32_t Emf::add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint else { *(d->defs) += " xlink:href=\"data:image/png;base64,"; } *(d->defs) += base64String; *(d->defs) += "\"\n"; + *(d->defs) += " preserveAspectRatio=\"none\"\n"; *(d->defs) += " />\n"; @@ -732,7 +574,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 +614,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 +822,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 +879,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( @@ -962,14 +915,14 @@ Emf::output_style(PEMF_CALLBACK_DATA d, int iType) tmp_style << "stroke-miterlimit:" << MAX( 2.0, d->dc[d->level].style.stroke_miterlimit.value ) << ";"; - if (d->dc[d->level].style.stroke_dasharray_set && - d->dc[d->level].style.stroke_dash.n_dash && d->dc[d->level].style.stroke_dash.dash) + if (d->dc[d->level].style.stroke_dasharray.set && + !d->dc[d->level].style.stroke_dasharray.values.empty() ) { tmp_style << "stroke-dasharray:"; - for (int i=0; i<d->dc[d->level].style.stroke_dash.n_dash; i++) { + for (unsigned i=0; i<d->dc[d->level].style.stroke_dasharray.values.size(); i++) { if (i) tmp_style << ","; - tmp_style << d->dc[d->level].style.stroke_dash.dash[i]; + tmp_style << d->dc[d->level].style.stroke_dasharray.values[i]; } tmp_style << ";"; tmp_style << "stroke-dashoffset:0;"; @@ -1063,34 +1016,30 @@ Emf::select_pen(PEMF_CALLBACK_DATA d, int index) case U_PS_DASHDOT: case U_PS_DASHDOTDOT: { - int i = 0; int penstyle = (pEmr->lopn.lopnStyle & U_PS_STYLE_MASK); - d->dc[d->level].style.stroke_dash.n_dash = - penstyle == U_PS_DASHDOTDOT ? 6 : penstyle == U_PS_DASHDOT ? 4 : 2; - if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash))) - delete[] d->dc[d->level].style.stroke_dash.dash; - d->dc[d->level].style.stroke_dash.dash = new double[d->dc[d->level].style.stroke_dash.n_dash]; + if (!d->dc[d->level].style.stroke_dasharray.values.empty() && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dasharray.values!=d->dc[d->level-1].style.stroke_dasharray.values))) + d->dc[d->level].style.stroke_dasharray.values.clear(); if (penstyle==U_PS_DASH || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dash.dash[i++] = 3; - d->dc[d->level].style.stroke_dash.dash[i++] = 1; + d->dc[d->level].style.stroke_dasharray.values.push_back( 3 ); + d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); } if (penstyle==U_PS_DOT || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dash.dash[i++] = 1; - d->dc[d->level].style.stroke_dash.dash[i++] = 1; + d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); + d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); } if (penstyle==U_PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dash.dash[i++] = 1; - d->dc[d->level].style.stroke_dash.dash[i++] = 1; + d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); + d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); } - d->dc[d->level].style.stroke_dasharray_set = 1; + d->dc[d->level].style.stroke_dasharray.set = 1; break; } case U_PS_SOLID: default: { - d->dc[d->level].style.stroke_dasharray_set = 0; + d->dc[d->level].style.stroke_dasharray.set = 0; break; } } @@ -1152,10 +1101,8 @@ Emf::select_extpen(PEMF_CALLBACK_DATA d, int index) case U_PS_USERSTYLE: { if (pEmr->elp.elpNumEntries) { - d->dc[d->level].style.stroke_dash.n_dash = pEmr->elp.elpNumEntries; - if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash))) - delete[] d->dc[d->level].style.stroke_dash.dash; - d->dc[d->level].style.stroke_dash.dash = new double[pEmr->elp.elpNumEntries]; + if (!d->dc[d->level].style.stroke_dasharray.values.empty() && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dasharray.values!=d->dc[d->level-1].style.stroke_dasharray.values))) + d->dc[d->level].style.stroke_dasharray.values.clear(); for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) { int cur_level = d->level; d->level = d->emf_obj[index].level; @@ -1164,11 +1111,11 @@ Emf::select_extpen(PEMF_CALLBACK_DATA d, int index) // double dash_length = pix_to_abs_size( d, pEmr->elp.elpStyleEntry[i] ); double dash_length = pEmr->elp.elpStyleEntry[i]; d->level = cur_level; - d->dc[d->level].style.stroke_dash.dash[i] = dash_length; + d->dc[d->level].style.stroke_dasharray.values[i] = dash_length; } - d->dc[d->level].style.stroke_dasharray_set = 1; + d->dc[d->level].style.stroke_dasharray.set = 1; } else { - d->dc[d->level].style.stroke_dasharray_set = 0; + d->dc[d->level].style.stroke_dasharray.set = 0; } break; } @@ -1178,27 +1125,23 @@ Emf::select_extpen(PEMF_CALLBACK_DATA d, int index) case U_PS_DASHDOT: case U_PS_DASHDOTDOT: { - int i = 0; int penstyle = (pEmr->elp.elpPenStyle & U_PS_STYLE_MASK); - d->dc[d->level].style.stroke_dash.n_dash = - penstyle == U_PS_DASHDOTDOT ? 6 : penstyle == U_PS_DASHDOT ? 4 : 2; - if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash))) - delete[] d->dc[d->level].style.stroke_dash.dash; - d->dc[d->level].style.stroke_dash.dash = new double[d->dc[d->level].style.stroke_dash.n_dash]; + if (!d->dc[d->level].style.stroke_dasharray.values.empty() && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dasharray.values!=d->dc[d->level-1].style.stroke_dasharray.values))) + d->dc[d->level].style.stroke_dasharray.values.clear(); if (penstyle==U_PS_DASH || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dash.dash[i++] = 3; - d->dc[d->level].style.stroke_dash.dash[i++] = 2; + d->dc[d->level].style.stroke_dasharray.values.push_back( 3 ); + d->dc[d->level].style.stroke_dasharray.values.push_back( 2 ); } if (penstyle==U_PS_DOT || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dash.dash[i++] = 1; - d->dc[d->level].style.stroke_dash.dash[i++] = 2; + d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); + d->dc[d->level].style.stroke_dasharray.values.push_back( 2 ); } if (penstyle==U_PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dash.dash[i++] = 1; - d->dc[d->level].style.stroke_dash.dash[i++] = 2; + d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); + d->dc[d->level].style.stroke_dasharray.values.push_back( 2 ); } - d->dc[d->level].style.stroke_dasharray_set = 1; + d->dc[d->level].style.stroke_dasharray.set = 1; break; } case U_PS_SOLID: @@ -1210,7 +1153,7 @@ Emf::select_extpen(PEMF_CALLBACK_DATA d, int index) */ default: { - d->dc[d->level].style.stroke_dasharray_set = 0; + d->dc[d->level].style.stroke_dasharray.set = 0; break; } } @@ -1343,7 +1286,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 +1445,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 +1457,75 @@ 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 << " preserveAspectRatio=\"none\"\n"; + tmp_image << "/> \n"; - *(d->outsvg) += "/> \n"; + *(d->outsvg) += tmp_image.str().c_str(); *(d->path) = ""; } @@ -1631,6 +1556,7 @@ int Emf::myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DA tsp.vadvance = 0.0; /* meaningful only when a complex contains two or more lines */ tsp.taln = ALILEFT + ALIBASE; tsp.ldir = LDIR_LR; + tsp.spaces = 0; // this field is only used for debugging tsp.color.Red = 0; /* RGB Black */ tsp.color.Green = 0; /* RGB Black */ tsp.color.Blue = 0; /* RGB Black */ @@ -1664,7 +1590,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 +1637,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 +1652,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 +1663,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) = ""; @@ -2237,9 +2163,9 @@ std::cout << "BEFORE DRAW" tmp_rectangle << "\n x=\"" << dx << "\" "; tmp_rectangle << "\n y=\"" << dy << "\" "; tmp_rectangle << "\n width=\"" << dw << "\" "; - tmp_rectangle << "\n height=\"" << dh << "\" />"; + tmp_rectangle << "\n height=\"" << dh << "\" "; tmp_rectangle << "\n transform=" << current_matrix(d, dx, dy, 1); // calculate appropriate offset - tmp_rectangle << "\n</clipPath>"; + tmp_rectangle << "/>\n</clipPath>"; *(d->outdef) += tmp_rectangle.str().c_str(); *(d->path) = ""; @@ -2273,8 +2199,8 @@ std::cout << "BEFORE DRAW" d->level = d->level + pEmr->iRelative; } while (old_level > d->level) { - if (d->dc[old_level].style.stroke_dash.dash && (old_level==0 || (old_level>0 && d->dc[old_level].style.stroke_dash.dash!=d->dc[old_level-1].style.stroke_dash.dash))){ - delete[] d->dc[old_level].style.stroke_dash.dash; + if (!d->dc[old_level].style.stroke_dasharray.values.empty() && (old_level==0 || (old_level>0 && d->dc[old_level].style.stroke_dasharray.values!=d->dc[old_level-1].style.stroke_dasharray.values))){ + d->dc[old_level].style.stroke_dasharray.values.clear(); } if(d->dc[old_level].font_name){ free(d->dc[old_level].font_name); // else memory leak @@ -2451,7 +2377,7 @@ std::cout << "BEFORE DRAW" case U_WHITE_PEN: { float val = index == U_BLACK_PEN ? 0 : 1; - d->dc[d->level].style.stroke_dasharray_set = 0; + d->dc[d->level].style.stroke_dasharray.set = 0; d->dc[d->level].style.stroke_width.value = 1.0; d->dc[d->level].style.stroke.value.color.set( val, val, val ); @@ -2625,7 +2551,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 +2572,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 +2595,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 +2636,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 +3258,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 +3331,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 +3390,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 +3433,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; @@ -3486,8 +3442,7 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) delete[] d.emf_obj; } - if (d.dc[0].style.stroke_dash.dash) - delete[] d.dc[0].style.stroke_dash.dash; + d.dc[0].style.stroke_dasharray.values.clear(); for(int i=0; i<=d.level;i++){ if(d.dc[i].font_name)free(d.dc[i].font_name); @@ -3516,7 +3471,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 +3518,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..a97cb0a54 100644 --- a/src/extension/internal/emf-inout.h +++ b/src/extension/internal/emf-inout.h @@ -3,6 +3,7 @@ */ /* Authors: * Ulf Erikson <ulferikson@users.sf.net> + * David Mathog * * Copyright (C) 2006-2008 Authors * @@ -11,9 +12,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 +67,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 +98,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 +106,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 +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(PEMF_CALLBACK_DATA d); static std::string current_matrix(PEMF_CALLBACK_DATA d, double x, double y, int useoffset); @@ -171,6 +140,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..f4f7f08cb 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"); + // 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"); + 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; @@ -361,11 +366,13 @@ int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) if (!fcolor && style) { if (style->fill.isColor()) { fill_mode = DRAW_PAINT; +#if 0 +// opacity not supported by EMF float opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value); if (opacity <= 0.0) { opacity = 0.0; // basically the same as no fill } - +#endif sp_color_get_rgb_floatv(&style->fill.value.color, rgb); hatchColor = U_RGB(255 * rgb[0], 255 * rgb[1], 255 * rgb[2]); @@ -420,7 +427,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); @@ -678,25 +685,24 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform) linejoin = U_PS_JOIN_BEVEL; } - if (style->stroke_dash.n_dash && - style->stroke_dash.dash) { + if (!style->stroke_dasharray.values.empty()) { if (FixPPTDashLine) { // will break up line into many smaller lines. Override gradient if that was set, cannot do both. brushStyle = U_BS_SOLID; hatchType = U_HS_HORIZONTAL; } else { - int i = 0; - while ((linestyle != U_PS_USERSTYLE) && (i < style->stroke_dash.n_dash)) { - if (style->stroke_dash.dash[i] > 0.00000001) { + unsigned i = 0; + while ((linestyle != U_PS_USERSTYLE) && (i < style->stroke_dasharray.values.size())) { + if (style->stroke_dasharray.values[i] > 0.00000001) { linestyle = U_PS_USERSTYLE; } i++; } if (linestyle == U_PS_USERSTYLE) { - n_dash = style->stroke_dash.n_dash; + n_dash = style->stroke_dasharray.values.size(); 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]); + for (i = 0; i < n_dash; i++) { + dash[i] = (uint32_t)(Inkscape::Util::Quantity::convert(1, "mm", "px") * style->stroke_dasharray.values[i]); } } } @@ -780,6 +786,187 @@ 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, 1e-5))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, 1e-5)){ // 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 + 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 increased numerical stability, snap the angle to the nearest 1/100th of a degree. */ + double convert = 36000.0/ (2.0 * M_PI); + *angle = round(*angle * convert)/convert; + + 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 ); + // P1 is center of a turn that is not 90 degrees. Limit comes from cos(89.9) = .001745 + if(!Geom::are_near(dot(v1,v2), 0.0, 2e-3))break; + 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, 1e-5)){ stat = 1; } + else if(Geom::are_near(dot(v1,v2),-1.0, 1e-5)){ stat = 2; } + if(!stat){ + v2 = Geom::Point(0,1) * Geom::Rotate(-angle); // unit vertical side + if( Geom::are_near(dot(v1,v2), 1.0, 1e-5)){ stat = 3; } + else if(Geom::are_near(dot(v1,v2),-1.0, 1e-5)){ 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 center(0,0); + for(Geom::Path::const_iterator cit = pathRect.begin(); cit != pathRect.end_open(); ++cit) { + center += cit->initialPoint()/4.0; + } + + int LR; // 1 if Left, 0 if Right + int UL; // 1 if Lower, 0 if Upper (as viewed on screen, y coordinates increase downwards) + 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; + } + + 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 P1; + for(Geom::Path::const_iterator cit = pathRect.begin(); cit != pathRect.end_open(); ++cit) { + 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 +982,28 @@ 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){ + Geom::PathVector pvr = pathv * fill_transform; + pathRect = pathv_to_rect(pvr, &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) * fill_transform); + 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 +1026,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 +1075,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 +1090,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; + U_XFORM tmpTransform; + double wRect, hRect; + + /* coordinates: upper left, upper right, and lower right corners of the rectangle. + inkscape transform already applied, but needs to be scaled to EMF coordinates. */ + ul = get_pathrect_corner(pathRect, angle, 0) * PX2WORLD; + ur = get_pathrect_corner(pathRect, angle, 1) * PX2WORLD; + lr = get_pathrect_corner(pathRect, angle, 2) * 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. + This rectangle has already been transformed by tf (whatever rotation/scale) Inkscape had applied to it. + */ + + Geom::Affine tf2 = Geom::Rotate(-angle); // the rectangle may be drawn skewed to the coordinate system + tmpTransform.eM11 = tf2[0]; + tmpTransform.eM12 = tf2[1]; + tmpTransform.eM21 = tf2[2]; + tmpTransform.eM22 = tf2[3]; + tmpTransform.eDx = round((ul)[Geom::X]); // use explicit round for better stability + tmpTransform.eDy = round((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 = round(outUL[X]); // use explicit round for better stability + rcb.top = round(outUL[Y]); + rcb.right = round(outLR[X]); + rcb.bottom = round(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; + 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 { @@ -963,7 +1260,7 @@ unsigned int PrintEmf::fill( } if ( (style->stroke.isNone() || style->stroke.noneSet || style->stroke_width.computed == 0.0) || - (style->stroke_dash.n_dash && style->stroke_dash.dash && FixPPTDashLine) || + (!style->stroke_dasharray.values.empty() && FixPPTDashLine) || !all_closed ) { print_pathv(pathv, fill_transform); // do any fills. side effect: clears fill_pathv @@ -991,13 +1288,13 @@ unsigned int PrintEmf::stroke( return 0; } - if (style->stroke_dash.n_dash && style->stroke_dash.dash && FixPPTDashLine) { + if (!style->stroke_dasharray.values.empty() && FixPPTDashLine) { // convert the path, gets its complete length, and then make a new path with parameter length instead of t Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw; // pathv-> sbasis Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw2; // sbasis using arc length parameter Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw3; // new (discontinuous) path, composed of dots/dashes Geom::Piecewise<Geom::D2<Geom::SBasis> > first_frag; // first fragment, will be appended at end - int n_dash = style->stroke_dash.n_dash; + int n_dash = style->stroke_dasharray.values.size(); int i = 0; //dash index double tlength; // length of tmp_pathpw double slength = 0.0; // start of gragment @@ -1010,7 +1307,7 @@ unsigned int PrintEmf::stroke( // go around the dash array repeatedly until the entire path is consumed (but not beyond). while (slength < tlength) { - elength = slength + style->stroke_dash.dash[i++]; + elength = slength + style->stroke_dasharray.values[i++]; if (elength > tlength) { elength = tlength; } @@ -1021,7 +1318,7 @@ unsigned int PrintEmf::stroke( first_frag = fragment; } slength = elength; - slength += style->stroke_dash.dash[i++]; // the gap + slength += style->stroke_dasharray.values[i++]; // the gap if (i >= n_dash) { i = 0; } @@ -1266,8 +1563,8 @@ unsigned int PrintEmf::image( unsigned int w, /** width of bitmap */ unsigned int h, /** height of bitmap */ unsigned int rs, /** row stride (normally w*4) */ - Geom::Affine const &/*tf_ignore*/, /** WRONG affine transform, use the one from m_tr_stack */ - SPStyle const *style) /** provides indirect link to image object */ + Geom::Affine const &tf_rect, /** affine transform only used for defining location and size of rect, for all other tranforms, use the one from m_tr_stack */ + SPStyle const * /*style*/) /** provides indirect link to image object */ { double x1, y1, dw, dh; char *rec = NULL; @@ -1278,10 +1575,10 @@ unsigned int PrintEmf::image( g_error("Fatal programming error in PrintEmf::image at EMRHEADER"); } - x1 = atof(style->object->getAttribute("x")); - y1 = atof(style->object->getAttribute("y")); - dw = atof(style->object->getAttribute("width")); - dh = atof(style->object->getAttribute("height")); + x1 = tf_rect[4]; + y1 = tf_rect[5]; + dw = ((double) w) * tf_rect[0]; + dh = ((double) h) * tf_rect[3]; Geom::Point pLL(x1, y1); Geom::Point pLL2 = pLL * tf; //location of LL corner in Inkscape coordinates @@ -1301,6 +1598,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 +1610,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 +2035,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..1e4970a46 100644 --- a/src/extension/internal/emf-print.h +++ b/src/extension/internal/emf-print.h @@ -1,8 +1,9 @@ /** @file * @brief Enhanced Metafile printing - implementation */ -/* Author: +/* Authors: * Ulf Erikson <ulferikson@users.sf.net> + * David Mathog * * Copyright (C) 2006-2008 Authors * @@ -68,6 +69,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/filter/color.h b/src/extension/internal/filter/color.h index 7059ad29b..19af6e969 100644 --- a/src/extension/internal/filter/color.h +++ b/src/extension/internal/filter/color.h @@ -941,7 +941,7 @@ Invert::get_filter_text (Inkscape::Extension::Extension * ext) std::ostringstream transparency; std::ostringstream hue; - if (ext->get_param_bool("hue") xor ext->get_param_bool("lightness")) { + if (ext->get_param_bool("hue") ^ ext->get_param_bool("lightness")) { hue << "<feColorMatrix type=\"hueRotate\" values=\"180\" result=\"color1\" />\n"; } else { hue << ""; diff --git a/src/extension/internal/gdkpixbuf-input.cpp b/src/extension/internal/gdkpixbuf-input.cpp index d7d692091..a384c7bde 100644 --- a/src/extension/internal/gdkpixbuf-input.cpp +++ b/src/extension/internal/gdkpixbuf-input.cpp @@ -30,22 +30,31 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri) Inkscape::Preferences *prefs = Inkscape::Preferences::get(); bool ask = prefs->getBool("/dialogs/import/ask"); Glib::ustring link = prefs->getString("/dialogs/import/link"); + bool forcexdpi = prefs->getBool("/dialogs/import/forcexdpi"); Glib::ustring scale = prefs->getString("/dialogs/import/scale"); // std::cout << "GkdpixbufInput::open: " // << " ask: " << ask // << ", link: " << link + // << ", forcexdpi: " << forcexdpi // << ", scale: " << scale << std::endl; // std::cout << " in preferences: " // << " ask: " << !mod->get_param_bool("do_not_ask") // << ", link: " << mod->get_param_optiongroup("link") + // << ", mod_dpi: " << mod->get_param_optiongroup("dpi") // << ", scale: " << mod->get_param_optiongroup("scale") << std::endl; if( ask ) { Glib::ustring mod_link = mod->get_param_optiongroup("link"); + Glib::ustring mod_dpi = mod->get_param_optiongroup("dpi"); + bool mod_forcexdpi = ( mod_dpi.compare( "from_default" ) == 0 ); Glib::ustring mod_scale = mod->get_param_optiongroup("scale"); if( link.compare( mod_link ) != 0 ) { link = mod_link; } prefs->setString("/dialogs/import/link", link ); + if( forcexdpi != mod_forcexdpi ) { + forcexdpi = mod_forcexdpi; + } + prefs->setBool("/dialogs/import/forcexdpi", forcexdpi ); if( scale.compare( mod_scale ) != 0 ) { scale = mod_scale; } @@ -68,7 +77,7 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri) double width = pb->width(); double height = pb->height(); double defaultxdpi = prefs->getDouble("/dialogs/import/defaultxdpi/value", Inkscape::Util::Quantity::convert(1, "in", "px")); - bool forcexdpi = prefs->getBool("/dialogs/import/forcexdpi"); + //bool forcexdpi = prefs->getBool("/dialogs/import/forcexdpi"); ImageResolution *ir = 0; double xscale = 1; double yscale = 1; @@ -95,6 +104,11 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri) Inkscape::XML::Node *image_node = xml_doc->createElement("svg:image"); sp_repr_set_svg_double(image_node, "width", width); sp_repr_set_svg_double(image_node, "height", height); + + // Added 11 Feb 2014 as we now honor "preserveAspectRatio" and this is + // what Inkscaper's expect. + image_node->setAttribute("preserveAspectRatio", "none"); + if( scale.compare( "auto" ) != 0 ) { SPCSSAttr *css = sp_repr_css_attr_new(); sp_repr_css_set_property(css, "image-rendering", scale.c_str()); @@ -122,6 +136,7 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri) // Set viewBox if it doesn't exist if (!doc->getRoot()->viewBox_set) { + std::cout << "Viewbox not set, setting" << std::endl; doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDefaultUnit()), doc->getHeight().value(doc->getDefaultUnit()))); } @@ -173,18 +188,21 @@ GdkpixbufInput::init(void) "<name>%s</name>\n" "<id>org.inkscape.input.gdkpixbuf.%s</id>\n" - "<param name='link' type='optiongroup' appearance='full' _gui-text='" N_("Link or embed image:") "' >\n" + "<param name='link' type='optiongroup' appearance='full' _gui-text='" N_("Image Import Type:") "' _gui-description='" N_("Embed results in stand-alone, larger SVG files. Link references a file outside this SVG document and all files must be moved together.") "' >\n" "<_option value='embed' >" N_("Embed") "</_option>\n" "<_option value='link' >" N_("Link") "</_option>\n" "</param>\n" - "<_param name='help' type='description'>" N_("Embed results in stand-alone, larger SVG files. Link references a file outside this SVG document and all files must be moved together.") "</_param>\n" - "<param name='scale' type='optiongroup' appearance='full' _gui-text='" N_("Scale image preference (image-rendering):") "' >\n" + "<param name='dpi' type='optiongroup' appearance='full' _gui-text='" N_("Image DPI:") "' _gui-description='" N_("Take information from file or use default bitmap import resolution as defined in the preferences.") "' >\n" + "<_option value='from_file' >" N_("From file") "</_option>\n" + "<_option value='from_default' >" N_("Default import resolution") "</_option>\n" + "</param>\n" + + "<param name='scale' type='optiongroup' appearance='full' _gui-text='" N_("Image Rendering Mode:") "' _gui-description='" N_("When an image is upscaled, apply smoothing or keep blocky (pixelated). (Will not work in all browsers.)") "' >\n" "<_option value='auto' >" N_("None (auto)") "</_option>\n" "<_option value='optimizeQuality' >" N_("Smooth (optimizeQuality)") "</_option>\n" "<_option value='optimizeSpeed' >" N_("Blocky (optimizeSpeed)") "</_option>\n" "</param>\n" - "<_param name='help' type='description'>" N_("When an image is upscaled, apply smoothing or keep blocky (pixelated). (Will not work in all browsers.)") "</_param>\n" "<param name=\"do_not_ask\" _gui-description='" N_("Hide the dialog next time and always apply the same actions.") "' gui-text=\"" N_("Don't ask again") "\" type=\"boolean\" >false</param>\n" "<input>\n" diff --git a/src/extension/internal/grid.cpp b/src/extension/internal/grid.cpp index 2f9d0ff25..0059bbec2 100644 --- a/src/extension/internal/grid.cpp +++ b/src/extension/internal/grid.cpp @@ -29,6 +29,7 @@ #include "selection.h" #include "sp-object.h" #include "util/glib-list-iterators.h" +#include "2geom/geom.h" #include "svg/path-string.h" @@ -58,31 +59,31 @@ Grid::load (Inkscape::Extension::Extension */*module*/) namespace { Glib::ustring build_lines(Geom::Rect bounding_area, - float offset[], float spacing[]) + Geom::Point const &offset, Geom::Point const &spacing) { Geom::Point point_offset(0.0, 0.0); SVG::PathString path_data; - for ( int axis = 0 ; axis < 2 ; ++axis ) { + for ( int axis = Geom::X ; axis <= Geom::Y ; ++axis ) { point_offset[axis] = offset[axis]; for (Geom::Point start_point = bounding_area.min(); - start_point[axis] + offset[axis] <= (bounding_area.max())[axis]; - start_point[axis] += spacing[axis]) { + start_point[axis] + offset[axis] <= (bounding_area.max())[axis]; + start_point[axis] += spacing[axis]) { Geom::Point end_point = start_point; end_point[1-axis] = (bounding_area.max())[1-axis]; path_data.moveTo(start_point + point_offset) - .lineTo(end_point + point_offset); + .lineTo(end_point + point_offset); } } - // std::cout << "Path data:" << path_data.c_str() << std::endl; - return path_data; - } - + // std::cout << "Path data:" << path_data.c_str() << std::endl; + return path_data; } +} // namespace + /** \brief This actually draws the grid. \param module The effect that was called (unused) @@ -112,16 +113,17 @@ Grid::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View *doc bounding_area = temprec; } - float spacings[2] = { module->get_param_float("xspacing"), - module->get_param_float("yspacing") }; - float line_width = module->get_param_float("lineWidth"); - float offsets[2] = { module->get_param_float("xoffset"), - module->get_param_float("yoffset") }; + gdouble scale = Inkscape::Util::Quantity::convert(1, "px", (document->doc())->getDefaultUnit()); + bounding_area *= Geom::Scale(scale); + Geom::Point spacings( scale * module->get_param_float("xspacing"), + scale * module->get_param_float("yspacing") ); + gdouble line_width = scale * module->get_param_float("lineWidth"); + Geom::Point offsets( scale * module->get_param_float("xoffset"), + scale * module->get_param_float("yoffset") ); Glib::ustring path_data(""); - path_data = build_lines(bounding_area, - offsets, spacings); + path_data = build_lines(bounding_area, offsets, spacings); Inkscape::XML::Document * xml_doc = document->doc()->getReprDoc(); //XML Tree being used directly here while it shouldn't be. @@ -141,9 +143,7 @@ Grid::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View *doc path->setAttribute("style", style.c_str()); current_layer->appendChild(path); - Inkscape::GC::release(path); - - return; + Inkscape::GC::release(path); } /** \brief A class to make an adjustment that uses Extension params */ diff --git a/src/extension/internal/image-resolution.cpp b/src/extension/internal/image-resolution.cpp index aee46aaba..18eb97f80 100644 --- a/src/extension/internal/image-resolution.cpp +++ b/src/extension/internal/image-resolution.cpp @@ -322,6 +322,12 @@ void ImageResolution::readjfif(char const *fn) { y_ = cinfo.Y_density * 2.54; ok_ = true; } + /* According to http://www.jpeg.org/public/jfif.pdf (page 7): + * "Xdensity and Ydensity should always be non-zero". + * but in some cases, they are (see LP bug #1275443) */ + if (x_ == 0 or y_ == 0) { + ok_ = false; + } } jpeg_destroy_decompress(&cinfo); fclose(ifd); diff --git a/src/extension/internal/javafx-out.cpp b/src/extension/internal/javafx-out.cpp index 035a6f0aa..19946022c 100644 --- a/src/extension/internal/javafx-out.cpp +++ b/src/extension/internal/javafx-out.cpp @@ -396,12 +396,14 @@ bool JavaFXOutput::doStyle(SPStyle *style) } else if (fill.isPaintserver()){ if (fill.value.href && fill.value.href->getURI() ){ - String uri = fill.value.href->getURI()->toString(); + gchar *str = fill.value.href->getURI()->toString(); + String uri = (str ? str : ""); /* trim the anchor '#' from the front */ if (uri.size() > 0 && uri[0]=='#') { uri = uri.substr(1); } out(" fill: %s()\n", sanatize(uri).c_str()); + g_free(str); } } @@ -416,10 +418,8 @@ bool JavaFXOutput::doStyle(SPStyle *style) * SPIEnum stroke_linecap; * SPIEnum stroke_linejoin; * SPIFloat stroke_miterlimit; - * NRVpathDash stroke_dash; - * unsigned stroke_dasharray_set : 1; - * unsigned stroke_dasharray_inherit : 1; - * unsigned stroke_dashoffset_set : 1; + * SPIDashArray stroke_dasharray; + * SPILength stroke_dashoffset; * SPIScale24 stroke_opacity; */ if (style->stroke_opacity.value > 0) @@ -434,16 +434,16 @@ bool JavaFXOutput::doStyle(SPStyle *style) out(" strokeLineCap: %s\n", getStrokeLineCap(linecap).c_str()); out(" strokeLineJoin: %s\n", getStrokeLineJoin(linejoin).c_str()); out(" strokeMiterLimit: %s\n", DSTR(style->stroke_miterlimit.value)); - if (style->stroke_dasharray_set) { - if (style->stroke_dashoffset_set) { - out(" strokeDashOffset: %s\n", DSTR(style->stroke_dash.offset)); + if (style->stroke_dasharray.set) { + if (style->stroke_dashoffset.set) { + out(" strokeDashOffset: %s\n", DSTR(style->stroke_dashoffset.value)); } out(" strokeDashArray: [ "); - for(int i = 0; i < style->stroke_dash.n_dash; i++ ) { + for(unsigned i = 0; i < style->stroke_dasharray.values.size(); i++ ) { if (i > 0) { - out(", %.2lf", style->stroke_dash.dash[i]); + out(", %.2lf", style->stroke_dasharray.values[i]); }else { - out(" %.2lf", style->stroke_dash.dash[i]); + out(" %.2lf", style->stroke_dasharray.values[i]); } } out(" ]\n"); diff --git a/src/extension/internal/latex-pstricks.cpp b/src/extension/internal/latex-pstricks.cpp index c8e8e2f2e..6aaa1bca4 100644 --- a/src/extension/internal/latex-pstricks.cpp +++ b/src/extension/internal/latex-pstricks.cpp @@ -239,16 +239,13 @@ unsigned int PrintLatex::stroke(Inkscape::Extension::Print * /*mod*/, os<<",strokeopacity="<<stroke_opacity; } - if (style->stroke_dasharray_set && - style->stroke_dash.n_dash && - style->stroke_dash.dash) { - int i; + if (style->stroke_dasharray.set && !style->stroke_dasharray.values.empty()) { os << ",linestyle=dashed,dash="; - for (i = 0; i < style->stroke_dash.n_dash; i++) { + for (unsigned i = 0; i < style->stroke_dasharray.values.size(); i++) { if ((i)) { os << " "; } - os << style->stroke_dash.dash[i]; + os << style->stroke_dasharray.values[i]; } } diff --git a/src/extension/internal/metafile-inout.cpp b/src/extension/internal/metafile-inout.cpp new file mode 100644 index 000000000..1d419a6a0 --- /dev/null +++ b/src/extension/internal/metafile-inout.cpp @@ -0,0 +1,211 @@ +/** @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 "display/curve.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/odf.cpp b/src/extension/internal/odf.cpp index fcabcc4b2..52fabcf3c 100644 --- a/src/extension/internal/odf.cpp +++ b/src/extension/internal/odf.cpp @@ -77,12 +77,7 @@ #include "text-editing.h" #include "util/units.h" - -//# DOM-specific includes -#include "dom/dom.h" -#include "dom/util/ziptool.h" -//#include "dom/io/domstream.h" - +#include "uri.h" #include "inkscape-version.h" #include "document.h" @@ -90,6 +85,7 @@ #include "io/inkscapestream.h" #include "io/bufferstream.h" +#include <util/ziptool.h> #include <iomanip> namespace Inkscape { @@ -98,7 +94,6 @@ namespace Extension namespace Internal { //# Shorthand notation -typedef org::w3c::dom::DOMString DOMString; typedef Inkscape::IO::BufferOutputStream BufferOutputStream; typedef Inkscape::IO::OutputStreamWriter OutputStreamWriter; typedef Inkscape::IO::StringOutputStream StringOutputStream; @@ -1026,6 +1021,7 @@ static void gatherText(Inkscape::XML::Node *node, Glib::ustring &buf) } + /** * FIRST PASS. * Method descends into the repr tree, converting image, style, and gradient info @@ -1086,10 +1082,9 @@ void OdfOutput::preprocess(ZipFile &zf, Inkscape::XML::Node *node) imageTable[oldName] = newName; Glib::ustring comment = "old name was: "; comment.append(oldName); - URI oldUri(oldName); + Inkscape::URI oldUri(oldName.c_str()); //# if relative to the documentURI, get proper path - URI resUri = documentUri.resolve(oldUri); - DOMString pathName = resUri.getNativePath(); + std::string pathName = documentUri.getFullPath(oldUri.getFullPath("")); ZipEntry *ze = zf.addFile(pathName, comment); if (ze) { @@ -2105,9 +2100,7 @@ void OdfOutput::save(Inkscape::Extension::Output */*mod*/, SPDocument *doc, gcha { reset(); - documentUri = URI(filename); - /* fixme: It looks like we really are using documentUri as a URI, so we ought to call - * g_filename_to_uri for the URI constructor. */ + documentUri = Inkscape::URI(filename); ZipFile zf; preprocess(zf, doc->rroot); diff --git a/src/extension/internal/odf.h b/src/extension/internal/odf.h index 6b915e347..f8712d5eb 100644 --- a/src/extension/internal/odf.h +++ b/src/extension/internal/odf.h @@ -23,18 +23,16 @@ #ifndef EXTENSION_INTERNAL_ODG_OUT_H #define EXTENSION_INTERNAL_ODG_OUT_H -#include <dom/dom.h> #include <io/stringstream.h> -#include <dom/uri.h> +#include <util/ziptool.h> #include "extension/implementation/implementation.h" #include <xml/repr.h> - #include <string> #include <map> -#include <dom/util/ziptool.h> +#include "uri.h" #include "sp-item.h" #include <glibmm/ustring.h> @@ -46,7 +44,6 @@ namespace Extension namespace Internal { -typedef org::w3c::dom::URI URI; typedef Inkscape::IO::Writer Writer; class StyleInfo @@ -279,7 +276,7 @@ public: private: - URI documentUri; + Inkscape::URI documentUri; void reset(); diff --git a/src/extension/internal/pdfinput/pdf-parser.cpp b/src/extension/internal/pdfinput/pdf-parser.cpp index 7edb758fd..b398486e6 100644 --- a/src/extension/internal/pdfinput/pdf-parser.cpp +++ b/src/extension/internal/pdfinput/pdf-parser.cpp @@ -76,10 +76,6 @@ extern "C" { // Operator table //------------------------------------------------------------------------ -#ifdef WIN32 // this works around a bug in the VC7 compiler -# pragma optimize("",off) -#endif - PdfOperator PdfParser::opTab[] = { {"\"", 3, {tchkNum, tchkNum, tchkString}, &PdfParser::opMoveSetShowText}, @@ -249,10 +245,6 @@ PdfOperator PdfParser::opTab[] = { &PdfParser::opCurveTo2} }; -#ifdef WIN32 // this works around a bug in the VC7 compiler -# pragma optimize("",on) -#endif - #define numOps (sizeof(opTab) / sizeof(PdfOperator)) //------------------------------------------------------------------------ @@ -718,10 +710,7 @@ void PdfParser::opSetMiterLimit(Object args[], int /*numArgs*/) // TODO not good that numArgs is ignored but args[] is used: void PdfParser::opSetLineWidth(Object args[], int /*numArgs*/) { - if (args[0].getNum() > 0.0) - state->setLineWidth(args[0].getNum()); - else - state->setLineWidth(1.0); // default + state->setLineWidth(args[0].getNum()); builder->updateStyle(state); } diff --git a/src/extension/internal/pdfinput/svg-builder.cpp b/src/extension/internal/pdfinput/svg-builder.cpp index b3f15bbff..71e6dc6ae 100644 --- a/src/extension/internal/pdfinput/svg-builder.cpp +++ b/src/extension/internal/pdfinput/svg-builder.cpp @@ -56,9 +56,6 @@ namespace Internal { #define TRACE(_args) IFTRACE(g_print _args) -static double ttm[6] = {1, 0, 0, 1, 0, 0}; // temporary transform matrix -static bool ttm_is_set = false; // flag to forbid setting ttm - /** * \struct SvgTransparencyGroup * \brief Holds information about a PDF transparency group @@ -94,6 +91,9 @@ SvgBuilder::SvgBuilder(SPDocument *document, gchar *docname, XRef *xref) _preferences = _xml_doc->createElement("svgbuilder:prefs"); _preferences->setAttribute("embedImages", "1"); _preferences->setAttribute("localFonts", "1"); + + _ttm[0] = 1; _ttm[1] = 0; _ttm[2] = 0; _ttm[3] = 1; _ttm[4] = 0; _ttm[5] = 0; + _ttm_is_set = false; } SvgBuilder::SvgBuilder(SvgBuilder *parent, Inkscape::XML::Node *root) { @@ -216,9 +216,9 @@ Inkscape::XML::Node *SvgBuilder::pushGroup() { } } if (_container->parent()->attribute("inkscape:groupmode") != NULL) { - ttm[0] = ttm[3] = 1.0; // clear ttm if parent is a layer - ttm[1] = ttm[2] = ttm[4] = ttm[5] = 0.0; - ttm_is_set = false; + _ttm[0] = _ttm[3] = 1.0; // clear ttm if parent is a layer + _ttm[1] = _ttm[2] = _ttm[4] = _ttm[5] = 0.0; + _ttm_is_set = false; } return _container; } @@ -298,14 +298,6 @@ static gchar *svgInterpretPath(GfxPath *path) { * Uses the given SPCSSAttr for storing the style properties */ void SvgBuilder::_setStrokeStyle(SPCSSAttr *css, GfxState *state) { - - // Check line width - if ( state->getLineWidth() <= 0.0 ) { - // Ignore stroke - sp_repr_css_set_property(css, "stroke", "none"); - return; - } - // Stroke color/pattern if ( state->getStrokeColorSpace()->getMode() == csPattern ) { gchar *urltext = _createPattern(state->getStrokePattern(), state, true); @@ -326,7 +318,14 @@ void SvgBuilder::_setStrokeStyle(SPCSSAttr *css, GfxState *state) { // Line width Inkscape::CSSOStringStream os_width; - os_width << state->getLineWidth(); + double lw = state->getLineWidth(); + if (lw > 0.0) { + os_width << lw; + } else { + // emit a stroke which is 1px in toplevel user units + double pxw = Inkscape::Util::Quantity::convert(1.0, "pt", "px"); + os_width << 1.0 / state->transformWidth(pxw); + } sp_repr_css_set_property(css, "stroke-width", os_width.str().c_str()); // Line cap @@ -570,14 +569,14 @@ bool SvgBuilder::getTransform(double *transform) { void SvgBuilder::setTransform(double c0, double c1, double c2, double c3, double c4, double c5) { // do not remember the group which is a layer - if ((_container->attribute("inkscape:groupmode") == NULL) && !ttm_is_set) { - ttm[0] = c0; - ttm[1] = c1; - ttm[2] = c2; - ttm[3] = c3; - ttm[4] = c4; - ttm[5] = c5; - ttm_is_set = true; + if ((_container->attribute("inkscape:groupmode") == NULL) && !_ttm_is_set) { + _ttm[0] = c0; + _ttm[1] = c1; + _ttm[2] = c2; + _ttm[3] = c3; + _ttm[4] = c4; + _ttm[5] = c5; + _ttm_is_set = true; } // Avoid transforming a group with an already set clip-path @@ -633,15 +632,15 @@ gchar *SvgBuilder::_createPattern(GfxPattern *pattern, GfxState *state, bool is_ // construct a (pattern space) -> (current space) transform matrix ptm = shading_pattern->getMatrix(); - det = ttm[0] * ttm[3] - ttm[1] * ttm[2]; + det = _ttm[0] * _ttm[3] - _ttm[1] * _ttm[2]; if (det) { double ittm[6]; // invert ttm - ittm[0] = ttm[3] / det; - ittm[1] = -ttm[1] / det; - ittm[2] = -ttm[2] / det; - ittm[3] = ttm[0] / det; - ittm[4] = (ttm[2] * ttm[5] - ttm[3] * ttm[4]) / det; - ittm[5] = (ttm[1] * ttm[4] - ttm[0] * ttm[5]) / det; + ittm[0] = _ttm[3] / det; + ittm[1] = -_ttm[1] / det; + ittm[2] = -_ttm[2] / det; + ittm[3] = _ttm[0] / det; + ittm[4] = (_ttm[2] * _ttm[5] - _ttm[3] * _ttm[4]) / det; + ittm[5] = (_ttm[1] * _ttm[4] - _ttm[0] * _ttm[5]) / det; m[0] = ptm[0] * ittm[0] + ptm[1] * ittm[2]; m[1] = ptm[0] * ittm[1] + ptm[1] * ittm[3]; m[2] = ptm[2] * ittm[0] + ptm[3] * ittm[2]; @@ -676,15 +675,15 @@ gchar *SvgBuilder::_createTilingPattern(GfxTilingPattern *tiling_pattern, double *p2u = tiling_pattern->getMatrix(); double m[6] = {1, 0, 0, 1, 0, 0}; double det; - det = ttm[0] * ttm[3] - ttm[1] * ttm[2]; // see LP Bug 1168908 + det = _ttm[0] * _ttm[3] - _ttm[1] * _ttm[2]; // see LP Bug 1168908 if (det) { double ittm[6]; // invert ttm - ittm[0] = ttm[3] / det; - ittm[1] = -ttm[1] / det; - ittm[2] = -ttm[2] / det; - ittm[3] = ttm[0] / det; - ittm[4] = (ttm[2] * ttm[5] - ttm[3] * ttm[4]) / det; - ittm[5] = (ttm[1] * ttm[4] - ttm[0] * ttm[5]) / det; + ittm[0] = _ttm[3] / det; + ittm[1] = -_ttm[1] / det; + ittm[2] = -_ttm[2] / det; + ittm[3] = _ttm[0] / det; + ittm[4] = (_ttm[2] * _ttm[5] - _ttm[3] * _ttm[4]) / det; + ittm[5] = (_ttm[1] * _ttm[4] - _ttm[0] * _ttm[5]) / det; m[0] = p2u[0] * ittm[0] + p2u[1] * ittm[2]; m[1] = p2u[0] * ittm[1] + p2u[1] * ittm[3]; m[2] = p2u[2] * ittm[0] + p2u[3] * ittm[2]; @@ -1657,6 +1656,10 @@ Inkscape::XML::Node *SvgBuilder::_createImage(Stream *str, int width, int height Inkscape::XML::Node *image_node = _xml_doc->createElement("svg:image"); sp_repr_set_svg_double(image_node, "width", 1); sp_repr_set_svg_double(image_node, "height", 1); + + // PS/PDF images are placed via a transformation matrix, no preserveAspectRatio used + image_node->setAttribute("preserveAspectRatio", "none"); + // Set transformation svgSetTransform(image_node, 1.0, 0.0, 0.0, -1.0, 0.0, 1.0); diff --git a/src/extension/internal/pdfinput/svg-builder.h b/src/extension/internal/pdfinput/svg-builder.h index 610822959..f1ce02cf0 100644 --- a/src/extension/internal/pdfinput/svg-builder.h +++ b/src/extension/internal/pdfinput/svg-builder.h @@ -223,6 +223,8 @@ private: Inkscape::XML::Node *_preferences; // Preferences container node double _width; // Document size in px double _height; // Document size in px + double _ttm[6]; ///< temporary transform matrix + bool _ttm_is_set; }; diff --git a/src/extension/internal/text_reassemble.c b/src/extension/internal/text_reassemble.c index cd84910fc..810e3f8cc 100644 --- a/src/extension/internal/text_reassemble.c +++ b/src/extension/internal/text_reassemble.c @@ -67,11 +67,11 @@ Optional compiler switches for development: File: text_reassemble.c -Version: 0.0.10 -Date: 06-MAY-2013 +Version: 0.0.14 +Date: 25-MAR-2014 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2013 David Mathog and California Institute of Technology (Caltech) +Copyright: 2014 David Mathog and California Institute of Technology (Caltech) */ #ifdef __cplusplus @@ -601,10 +601,13 @@ FT_INFO *ftinfo_init(void){ */ int ftinfo_make_insertable(FT_INFO *fti){ int status=0; + FNT_SPECS *tmp; if(!fti)return(2); if(fti->used >= fti->space){ fti->space += ALLOCINFO_CHUNK; - if((fti->fonts = (FNT_SPECS *) realloc(fti->fonts, fti->space * sizeof(FNT_SPECS) ))){ + tmp = (FNT_SPECS *) realloc(fti->fonts, fti->space * sizeof(FNT_SPECS) ); + if(tmp){ + fti->fonts = tmp; memset(&fti->fonts[fti->used],0,(fti->space - fti->used)*sizeof(FNT_SPECS)); } else { @@ -665,7 +668,7 @@ FT_INFO *ftinfo_clear(FT_INFO *fti){ free(fsp->file); /* release memory holding copies of paths */ free(fsp->fontspec); /* release memory holding copies of font names */ FcPatternDestroy(fsp->fpat); /* release memory for FontConfig fpats */ - FcFontSetDestroy(fti->fonts[i].fontset); + FcFontSetDestroy(fsp->fontset); if(fsp->alts){ free(fsp->alts); } } free(fti->fonts); @@ -726,9 +729,10 @@ int ftinfo_find_loaded_by_src(const FT_INFO *fti, const uint8_t *filename){ */ int ftinfo_load_fontname(FT_INFO *fti, const char *fontspec){ - FcPattern *pattern, *fpat; - FcFontSet *fontset; - FcResult result = FcResultMatch; + FcPattern *pattern = NULL; + FcPattern *fpat = NULL; + FcFontSet *fontset = NULL; + FcResult result = FcResultMatch; char *filename; double fd; FNT_SPECS *fsp; @@ -738,38 +742,45 @@ int ftinfo_load_fontname(FT_INFO *fti, const char *fontspec){ if(!fti)return(-1); /* If it is already loaded, do not load it again */ - if((status = ftinfo_find_loaded_by_spec(fti, (uint8_t *) fontspec))>=0){ - return(status); - } + status = ftinfo_find_loaded_by_spec(fti, (uint8_t *) fontspec); + if(status >= 0){ return(status); } + status = 0; /* was -1, reset to 0 */ ftinfo_make_insertable(fti); fi_idx = fti->used; - if(!(pattern = FcNameParse((const FcChar8 *)fontspec)) )return(2); - if(!FcConfigSubstitute(NULL, pattern, FcMatchPattern) )return(3); - FcDefaultSubstitute(pattern); - /* get a fontset, trimmed to only those with new glyphs as needed, so that missing glyph's may be handled */ - if(!(fontset = FcFontSort (NULL,pattern, FcTrue, NULL, &result)) - || result != FcResultMatch)return(4); - if(!(fpat = FcFontRenderPrepare(NULL, pattern, fontset->fonts[0])) )return(405); - if(FcPatternGetString( fpat, FC_FILE, 0, (FcChar8 **)&filename) != FcResultMatch)return(5); - if(FcPatternGetDouble( fpat, FC_SIZE, 0, &fd) != FcResultMatch)return(6); - - /* copy these into memory for external use */ - fsp = &(fti->fonts[fti->used]); - fsp->fontset = fontset; - fsp->alts = NULL; /* Initially no links to alternate fonts */ - fsp->space = 0; - fsp->file = (uint8_t *) U_strdup((char *) filename); - fsp->fontspec = (uint8_t *) U_strdup((char *) fontspec); - fsp->fpat = fpat; - fsp->fsize = fd; - + pattern = FcNameParse((const FcChar8 *)fontspec); + while(1) { /* this is NOT a loop, it uses breaks to avoid gotos and deep nesting */ + if(!(pattern)){ status = -2; break; } + if(!FcConfigSubstitute(NULL, pattern, FcMatchPattern)){ status = -3; break; }; + FcDefaultSubstitute(pattern); + /* get a fontset, trimmed to only those with new glyphs as needed, so that missing glyph's may be handled */ + if(!(fontset = FcFontSort (NULL,pattern, FcTrue, NULL, &result)) || (result != FcResultMatch)){ status = -4; break; } + if(!(fpat = FcFontRenderPrepare(NULL, pattern, fontset->fonts[0]))){ status = -405; break; } + if(FcPatternGetString( fpat, FC_FILE, 0, (FcChar8 **)&filename) != FcResultMatch){ status = -5; break; } + if(FcPatternGetDouble( fpat, FC_SIZE, 0, &fd) != FcResultMatch){ status = -6; break; } + + /* copy these into memory for external use */ + fsp = &(fti->fonts[fti->used]); + fsp->fontset = fontset; + fsp->alts = NULL; /* Initially no links to alternate fonts */ + fsp->space = 0; + fsp->file = (uint8_t *) U_strdup((char *) filename); + fsp->fontspec = (uint8_t *) U_strdup((char *) fontspec); + fsp->fpat = fpat; + fsp->fsize = fd; + break; + } /* release FC's own memory related to this call that does not need to be kept around so that face will work */ - FcPatternDestroy(pattern); + if(pattern)FcPatternDestroy(pattern); /* done with this memory */ + if(status<0){ + if(fontset)FcFontSetDestroy(fontset); + if(fpat)FcPatternDestroy(fpat); + return(status); + } /* get the current face */ - if(FT_New_Face( fti->library, (const char *) fsp->file, 0, &(fsp->face) )){ return(8); } + if(FT_New_Face( fti->library, (const char *) fsp->file, 0, &(fsp->face) )){ return(-8); } if(FT_Set_Char_Size( fsp->face, /* handle to face object */ @@ -777,12 +788,12 @@ int ftinfo_load_fontname(FT_INFO *fti, const char *fontspec){ fd*64, /* char_height in 1/64th of points */ 72, /* horizontal device resolution, DPI */ 72) /* vebrical device resolution, DPI */ - ){ return(9); } + ){ return(-9); } /* The space advance is needed in various places. Get it now, and get it in the font units, so that it can be scaled later with the text size */ status = TR_getadvance(fti, fsp,' ',0,FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP, FT_KERNING_UNSCALED, NULL, NULL); - if(status < 0)return(7); + if(status < 0)return(-7); fsp->spcadv = ((double) status)/(64.0); fti->used++; @@ -836,10 +847,13 @@ void ftinfo_dump(const FT_INFO *fti){ */ int fsp_alts_make_insertable(FNT_SPECS *fsp){ int status=0; + ALT_SPECS *tmp; if(!fsp)return(2); if(fsp->used >= fsp->space){ fsp->space += ALLOCINFO_CHUNK; - if((fsp->alts = (ALT_SPECS *) realloc(fsp->alts, fsp->space * sizeof(ALT_SPECS) ))){ + tmp = (ALT_SPECS *) realloc(fsp->alts, fsp->space * sizeof(ALT_SPECS) ); + if(tmp){ + fsp->alts = tmp; memset(&fsp->alts[fsp->used],0,(fsp->space - fsp->used)*sizeof(ALT_SPECS)); } else { @@ -904,10 +918,13 @@ int fsp_alts_weight(FNT_SPECS *fsp, uint32_t a_idx){ */ int csp_make_insertable(CHILD_SPECS *csp){ int status=0; + int *tmp; if(!csp)return(2); if(csp->used >= csp->space){ csp->space += ALLOCINFO_CHUNK; - if((csp->members = (int *) realloc(csp->members, csp->space * sizeof(int) ))){ + tmp = (int *) realloc(csp->members, csp->space * sizeof(int) ); + if(tmp){ + csp->members = tmp; memset(&csp->members[csp->used],0,(csp->space - csp->used)*sizeof(int)); } else { @@ -999,9 +1016,12 @@ CX_INFO *cxinfo_init(void){ */ int cxinfo_make_insertable(CX_INFO *cxi){ int status=0; + CX_SPECS *tmp; if(cxi->used >= cxi->space){ cxi->space += ALLOCINFO_CHUNK; - if((cxi->cx = (CX_SPECS *) realloc(cxi->cx, cxi->space * sizeof(CX_SPECS) ))){ + tmp = (CX_SPECS *) realloc(cxi->cx, cxi->space * sizeof(CX_SPECS) ); + if(tmp){ + cxi->cx = tmp; memset(&cxi->cx[cxi->used],0,(cxi->space - cxi->used)*sizeof(CX_SPECS)); } else { @@ -1170,9 +1190,12 @@ TP_INFO *tpinfo_init(void){ */ int tpinfo_make_insertable(TP_INFO *tpi){ int status=0; + TCHUNK_SPECS *tmp; if(tpi->used >= tpi->space){ tpi->space += ALLOCINFO_CHUNK; - if((tpi->chunks = (TCHUNK_SPECS *) realloc(tpi->chunks, tpi->space * sizeof(TCHUNK_SPECS) ))){ + tmp = (TCHUNK_SPECS *) realloc(tpi->chunks, tpi->space * sizeof(TCHUNK_SPECS) ); + if(tmp){ + tpi->chunks = tmp; memset(&tpi->chunks[tpi->used],0,(tpi->space - tpi->used)*sizeof(TCHUNK_SPECS)); } else { @@ -1243,10 +1266,13 @@ BR_INFO *brinfo_init(void){ */ int brinfo_make_insertable(BR_INFO *bri){ int status=0; + BRECT_SPECS *tmp; if(!bri)return(2); if(bri->used >= bri->space){ bri->space += ALLOCINFO_CHUNK; - if(!(bri->rects = (BRECT_SPECS *) realloc(bri->rects, bri->space * sizeof(BRECT_SPECS) ))){ status = 1; } + tmp = (BRECT_SPECS *) realloc(bri->rects, bri->space * sizeof(BRECT_SPECS) ); + if(tmp){ bri->rects = tmp; } + else { status = 1;} } return(status); } @@ -1380,7 +1406,7 @@ printf("Overlap rprect (LL,UR) dst:(%lf,%lf),(%lf,%lf) src:(%lf,%lf),(%lf,%lf)\n } /** - \brief Check for a text element upstream from the start element and in the reversed direction. + \brief Check for various sorts of invalid text elements upstream (language dir changes, draw order backwards from language direction) \returns 0 on success (not upstream), 1 if upstream, anything else is an error. \param bri pointer to the BR_INFO structure \param dst index of the destination bounding rectangle. @@ -1405,6 +1431,12 @@ int brinfo_upstream(BR_INFO *bri, int dst, int src, int ddir, int sdir){ else if( ddir == LDIR_LR && sdir == LDIR_RL){ if((br_src->xll + br_src->xur)/2.0 <= br_dst->xll ){ status = 1; } } + else if( ddir == LDIR_RL && sdir == LDIR_RL){ + if(br_dst->xur <= (br_src->xll + br_src->xur)/2.0){ status = 1; } + } + else if( ddir == LDIR_LR && sdir == LDIR_LR){ + if((br_src->xll + br_src->xur)/2.0 <= br_dst->xll ){ status = 1; } + } return(status); } @@ -1490,13 +1522,19 @@ TR_INFO *trinfo_init(TR_INFO *tri){ !(tri->bri = brinfo_init()) || !(tri->cxi = cxinfo_init()) ){ tri = trinfo_release(tri); } + tri->out = NULL; /* This will allocate as needed, it might not ever be needed. */ + tri->qe = 0.0; + tri->esc = 0.0; + tri->x = DBL_MAX; + tri->y = DBL_MAX; + tri->dirty = 0; tri->use_kern = 1; - tri->usebk = BKCLR_NONE; tri->load_flags = FT_LOAD_NO_SCALE; tri->kern_mode = FT_KERNING_UNSCALED; - tri->out = NULL; /* This will allocate as needed, it might not ever be needed. */ tri->outspace = 0; tri->outused = 0; + tri->usebk = BKCLR_NONE; + memset(&(tri->bkcolor),0,sizeof(TRCOLORREF)); return(tri); } @@ -1552,9 +1590,6 @@ TR_INFO *trinfo_release_except_FC(TR_INFO *tri){ */ TR_INFO *trinfo_clear(TR_INFO *tri){ if(tri){ - tri->dirty = 0; /* set these back to their defaults */ - tri->esc = 0.0; - /* Do NOT modify use_kern, usebk, load_flags, or kern_mode */ if(tri->bri)tri->bri=brinfo_release(tri->bri); if(tri->tpi)tri->tpi=tpinfo_release(tri->tpi); @@ -1565,6 +1600,11 @@ TR_INFO *trinfo_clear(TR_INFO *tri){ tri->outused = 0; tri->outspace = 0; }; + /* Do NOT modify: qe, use_kern, usebk, load_flags, kern_mode, or bkcolor. Set the rest back to their defaults */ + tri->esc = 0.0; + tri->x = DBL_MAX; + tri->y = DBL_MAX; + tri->dirty = 0; if(!(tri->tpi = tpinfo_init()) || /* re-init the pieces just released */ !(tri->bri = brinfo_init()) || !(tri->cxi = cxinfo_init()) @@ -1658,11 +1698,14 @@ int trinfo_load_ft_opts(TR_INFO *tri, int use_kern, int load_flags, int kern_mod */ int trinfo_append_out(TR_INFO *tri, const char *src){ size_t slen; + uint8_t *tmp; if(!src)return(-1); slen = strlen(src); if(tri->outused + (int) slen + 1 >= tri->outspace){ tri->outspace += TEREMAX(ALLOCOUT_CHUNK,slen+1); - if(!(tri->out = realloc(tri->out, tri->outspace )))return(-1); + tmp = realloc(tri->out, tri->outspace * sizeof(uint8_t) ); + if(tmp){ tri->out = tmp; } + else { return(-1); } } memcpy(tri->out + tri->outused, src, slen+1); /* copy the terminator */ tri->outused += slen; /* do not count the terminator in the length */ @@ -1958,7 +2001,7 @@ void TR_layout_2_svg(TR_INFO *tri){ cutat=strcspn((char *)fti->fonts[tsp->fi_idx].fontspec,":"); sprintf(obuf,"font-family:%.*s;",cutat,fti->fonts[tsp->fi_idx].fontspec); TRPRINT(tri, obuf); - sprintf(obuf,"\n\">%s</text>\n",tsp->string); + sprintf(obuf,"\n\">%s</text>\n",&tsp->string[tsp->spaces]); TRPRINT(tri, obuf); #endif /* DBG_TR_INPUT debugging code, original text objects */ } @@ -2033,7 +2076,6 @@ void TR_layout_2_svg(TR_INFO *tri){ } - tsp = tpi->chunks; /* over all complex members from phase2. Paragraphs == TR_PARA_* */ for(i=cxi->phase1; i<cxi->used;i++){ csp = &(cxi->cx[i]); @@ -2278,7 +2320,10 @@ int TR_layout_analyze(TR_INFO *tri){ next logical piece of text is "upstream" positionally of its logical predecessor. The meaning of such a construct is at best ambiguous. The test is only applied with respect to the first text chunk. This sort of construct may appear when a valid initial construct like [1->English][2<-Hebrew][3->English] is edited - and the leading chunk of text removed. + and the leading chunk of text removed. + + Also reject reversed order text as in (English) <A><B><C> (draw order) arranged as <C><B><A>. This happens + if the language direction field is incorrect, perhaps due to a corrupt or malformed input file. */ if(brinfo_upstream(bri, dst_rt, /* index into bri for dst */ @@ -2422,10 +2467,28 @@ int TR_layout_analyze(TR_INFO *tri){ } } - /* if x or y kern is less than the quantization error it is probably noise, set it to zero */ - if(fabs(tspj->xkern)<tri->qe)tspj->xkern = 0.0; - if(fabs(tspj->ykern)<tri->qe)tspj->ykern = 0.0; - + /* if x or y kern is less than twice the quantization error it is probably noise, set it to zero */ + if(fabs(tspj->xkern) <= 2.0*tri->qe)tspj->xkern = 0.0; + if(fabs(tspj->ykern) <= 2.0*tri->qe)tspj->ykern = 0.0; + + /* reintroduce spaces on the leading edge of text "j" if the kerning can be in part or in whole replaced + with 1 or 2 spaces */ + if(tspj->ykern == 0.0){ + double spaces = tspj->xkern/spcadv; /* negative on RL language, positive on LR */ + if((ldir == LDIR_RL && (spaces <= -0.9 && spaces >= -2.1)) || + (ldir == LDIR_LR && (spaces >= 0.9 && spaces <= 2.1)) ){ + int ispaces = lround(spaces); + tspj->xkern -= ((double)ispaces*spcadv); + if(ispaces<0)ispaces=-ispaces; + size_t slen = strlen((char *)tspj->string); + uint8_t *newstring = malloc(1 + ispaces + slen); + sprintf((char *)newstring," "); /* start with two spaces, possibly overwrite one in the next line */ + memcpy(newstring+ispaces,tspj->string,slen+1); /* copy existing string to proper position */ + free(tspj->string); + tspj->string = newstring; + tspj->spaces = ispaces; // only needed to fix optional debugging SVG output later + } + } tspi = tspj; lastldir = ldir; @@ -2699,7 +2762,7 @@ int main(int argc, char *argv[]){ tsp.weight = 80; tsp.condensed = 100; tsp.decoration = 0; /* none */ - tsp.co = 0; + tsp.spaces = 0; /* none */ tsp.fi_idx = -1; /* set to an invalid */ tsp.rt_tidx = -1; /* set to an invalid */ tsp.xkern = tsp.ykern = 0.0; diff --git a/src/extension/internal/text_reassemble.h b/src/extension/internal/text_reassemble.h index d85b233be..6c1acafe5 100644 --- a/src/extension/internal/text_reassemble.h +++ b/src/extension/internal/text_reassemble.h @@ -4,11 +4,11 @@ See text_reassemble.c for notes File: text_reassemble.h -Version: 0.0.12 -Date: 14-MAY-2013 +Version: 0.0.13 +Date: 06-FEB-2014 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2013 David Mathog and California Institute of Technology (Caltech) +Copyright: 2014 David Mathog and California Institute of Technology (Caltech) */ #ifndef _TEXT_REASSEMBLE_ @@ -189,6 +189,7 @@ typedef struct { int weight; /**< weight, as in FontConfig */ int condensed; /**< condensed, as in FontConfig */ int decoration; /**< text decorations, ignored during assembly, used during output */ + int spaces; /**< count of spaces converted from wide kerning (1 or 2) */ TRCOLORREF decColor; /**< text decoration color, ignored during assembly, used during output */ int co; /**< condensed override, if set Font name included narrow */ int rt_tidx; /**< index of rectangle that contains it */ diff --git a/src/extension/internal/wmf-inout.cpp b/src/extension/internal/wmf-inout.cpp index 870e4061c..ef95dbe45 100644 --- a/src/extension/internal/wmf-inout.cpp +++ b/src/extension/internal/wmf-inout.cpp @@ -4,6 +4,7 @@ /* Authors: * Ulf Erikson <ulferikson@users.sf.net> * Jon A. Cruz <jon@joncruz.org> + * David Mathog * Abhishek Sharma * * Copyright (C) 2006-2008 Authors @@ -26,7 +27,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 +71,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; @@ -592,9 +445,9 @@ int Wmf::in_images(PWMF_CALLBACK_DATA d, char *test){ uint32_t Wmf::add_dib_image(PWMF_CALLBACK_DATA d, const char *dib, uint32_t iUsage){ uint32_t idx; - char imagename[64]; // big enough - char xywh[64]; // big enough - int dibparams; + char imagename[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; @@ -602,58 +455,46 @@ uint32_t Wmf::add_dib_image(PWMF_CALLBACK_DATA d, const char *dib, uint32_t iUsa char *rgba_px = NULL; // RGBA pixels const char *px = NULL; // DIB pixels const U_RGBQUAD *ct = NULL; // DIB color table - int32_t width, height, colortype, numCt, invert; - if((iUsage != U_DIB_RGB_COLORS) || - !(dibparams = wget_DIB_params( // this returns pointers and values, but allocates no memory - dib, - &px, - &ct, - &numCt, - &width, - &height, - &colortype, - &invert - )) - ){ - - if(!DIB_to_RGBA( - px, // DIB pixel array - ct, // DIB color table - numCt, // DIB color table number of entries - &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free. - width, // Width of pixel array in record - height, // Height of pixel array in record - colortype, // DIB BitCount Enumeration - numCt, // Color table used if not 0 - invert // If DIB rows are in opposite order from RGBA rows - ) && - rgba_px - ){ - toPNG( // Get the image from the RGBA px into mempng - &mempng, - width, height, // of the SRC bitmap - rgba_px - ); - free(rgba_px); + int32_t width, height, colortype, numCt, invert; // if needed these values will be set by wget_DIB_params + if(iUsage == U_DIB_RGB_COLORS){ + // next call returns pointers and values, but allocates no memory + dibparams = wget_DIB_params(dib, &px, &ct, &numCt, &width, &height, &colortype, &invert); + if(dibparams == U_BI_RGB){ + 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 { // 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; @@ -672,6 +513,7 @@ uint32_t Wmf::add_dib_image(PWMF_CALLBACK_DATA d, const char *dib, uint32_t iUsa else { *(d->defs) += " xlink:href=\"data:image/png;base64,"; } *(d->defs) += base64String; *(d->defs) += "\"\n"; + *(d->defs) += " preserveAspectRatio=\"none\"\n"; *(d->defs) += " />\n"; @@ -691,7 +533,7 @@ uint32_t Wmf::add_dib_image(PWMF_CALLBACK_DATA d, const char *dib, uint32_t iUsa *(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 return(idx-1); } @@ -709,16 +551,16 @@ uint32_t Wmf::add_bm16_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char * mempng.buffer = NULL; char *rgba_px = NULL; // RGBA pixels - const U_RGBQUAD *ct = NULL; // color table, always NULL here + const U_RGBQUAD *ct = NULL; // color table, always NULL here int32_t width, height, colortype, numCt, invert; numCt = 0; width = Bm16.Width; // bitmap width in pixels. height = Bm16.Height; // bitmap height in scan lines. colortype = Bm16.BitsPixel; // seems to be BitCount Enumeration invert = 0; - if(colortype < 16)return(0xFFFFFFFF); // these would need a colortable if they were a dib, no idea what bm16 is supposed to do instead. + if(colortype < 16)return(U_WMR_INVALID); // these would need a colortable if they were a dib, no idea what bm16 is supposed to do instead. - if(!DIB_to_RGBA(// This is not really a dib, but close enough... + if(!DIB_to_RGBA(// This is not really a dib, but close enough so that it still works. px, // DIB pixel array ct, // DIB color table (always NULL here) numCt, // DIB color table number of entries (always 0) @@ -728,8 +570,7 @@ uint32_t Wmf::add_bm16_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char * 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 @@ -737,17 +578,18 @@ uint32_t Wmf::add_bm16_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char * ); free(rgba_px); } - gchar *base64String; - if(mempng.buffer){ + + gchar *base64String=NULL; + if(mempng.buffer){ // image was Bm16 in source file, converted to png in this routine base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size ); free(mempng.buffer); } - else { - // insert a random 3x4 blotch otherwise + else { // failed conversion, insert the common bad image picture width = 3; height = 4; - base64String = g_strdup("iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII="); + 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); } @@ -766,6 +608,7 @@ uint32_t Wmf::add_bm16_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char * *(d->defs) += " xlink:href=\"data:image/png;base64,"; *(d->defs) += base64String; *(d->defs) += "\"\n"; + *(d->defs) += " preserveAspectRatio=\"none\"\n"; *(d->defs) += " />\n"; @@ -784,7 +627,7 @@ uint32_t Wmf::add_bm16_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char * *(d->defs) += "\" />\n"; *(d->defs) += " </pattern>\n"; } - g_free(base64String); + g_free(base64String); //wait until this point to free because it might be a duplicate image return(idx-1); } @@ -978,14 +821,14 @@ Wmf::output_style(PWMF_CALLBACK_DATA d) tmp_style << "stroke-miterlimit:" << MAX( 2.0, d->dc[d->level].style.stroke_miterlimit.value ) << ";"; - if (d->dc[d->level].style.stroke_dasharray_set && - d->dc[d->level].style.stroke_dash.n_dash && d->dc[d->level].style.stroke_dash.dash) + if (d->dc[d->level].style.stroke_dasharray.set && + !d->dc[d->level].style.stroke_dasharray.values.empty()) { tmp_style << "stroke-dasharray:"; - for (int i=0; i<d->dc[d->level].style.stroke_dash.n_dash; i++) { + for (unsigned i=0; i<d->dc[d->level].style.stroke_dasharray.values.size(); i++) { if (i) tmp_style << ","; - tmp_style << d->dc[d->level].style.stroke_dash.dash[i]; + tmp_style << d->dc[d->level].style.stroke_dasharray.values[i]; } tmp_style << ";"; tmp_style << "stroke-dashoffset:0;"; @@ -1028,16 +871,13 @@ double Wmf::pix_to_x_point(PWMF_CALLBACK_DATA d, double px, double /*py*/) { double x = _pix_x_to_point(d, px); - return x; } double Wmf::pix_to_y_point(PWMF_CALLBACK_DATA d, double /*px*/, double py) { - double y = _pix_y_to_point(d, py); - return y; } @@ -1081,34 +921,30 @@ Wmf::select_pen(PWMF_CALLBACK_DATA d, int index) case U_PS_DASHDOT: case U_PS_DASHDOTDOT: { - int i = 0; int penstyle = (up.Style & U_PS_STYLE_MASK); - d->dc[d->level].style.stroke_dash.n_dash = - penstyle == U_PS_DASHDOTDOT ? 6 : penstyle == U_PS_DASHDOT ? 4 : 2; - if (d->dc[d->level].style.stroke_dash.dash && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dash.dash!=d->dc[d->level-1].style.stroke_dash.dash))) - delete[] d->dc[d->level].style.stroke_dash.dash; - d->dc[d->level].style.stroke_dash.dash = new double[d->dc[d->level].style.stroke_dash.n_dash]; + if (!d->dc[d->level].style.stroke_dasharray.values.empty() && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dasharray.values!=d->dc[d->level-1].style.stroke_dasharray.values))) + d->dc[d->level].style.stroke_dasharray.values.clear(); if (penstyle==U_PS_DASH || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dash.dash[i++] = 3; - d->dc[d->level].style.stroke_dash.dash[i++] = 1; + d->dc[d->level].style.stroke_dasharray.values.push_back( 3 ); + d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); } if (penstyle==U_PS_DOT || penstyle==U_PS_DASHDOT || penstyle==U_PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dash.dash[i++] = 1; - d->dc[d->level].style.stroke_dash.dash[i++] = 1; + d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); + d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); } if (penstyle==U_PS_DASHDOTDOT) { - d->dc[d->level].style.stroke_dash.dash[i++] = 1; - d->dc[d->level].style.stroke_dash.dash[i++] = 1; + d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); + d->dc[d->level].style.stroke_dasharray.values.push_back( 1 ); } - d->dc[d->level].style.stroke_dasharray_set = 1; + d->dc[d->level].style.stroke_dasharray.set = 1; break; } case U_PS_SOLID: default: { - d->dc[d->level].style.stroke_dasharray_set = 0; + d->dc[d->level].style.stroke_dasharray.set = 0; break; } } @@ -1199,7 +1035,6 @@ Wmf::select_brush(PWMF_CALLBACK_DATA d, int index) const char *Bm16h; // Pointer to Bitmap16 header (px follows) const char *dib; // Pointer to DIB (void) U_WMRDIBCREATEPATTERNBRUSH_get(record, &Style, &cUsage, &Bm16h, &dib); - // Bm16 not handled yet if(dib || Bm16h){ if(dib){ tidx = add_dib_image(d, dib, cUsage); } else if(Bm16h){ @@ -1209,7 +1044,7 @@ Wmf::select_brush(PWMF_CALLBACK_DATA d, int index) px = Bm16h + U_SIZE_BITMAP16; tidx = add_bm16_image(d, Bm16, px); } - if(tidx == 0xFFFFFFFF){ // Problem with the image, for instance, an unsupported bitmap16 type + if(tidx == U_WMR_INVALID){ // Problem with the image, for instance, an unsupported bitmap16 type 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)); @@ -1227,6 +1062,28 @@ Wmf::select_brush(PWMF_CALLBACK_DATA d, int index) g_message("Please send WMF file to developers - select_brush U_WMR_DIBCREATEPATTERNBRUSH not bm16 or dib, not handled"); } } + else if(iType == U_WMR_CREATEPATTERNBRUSH){ + uint32_t tidx; + int cbPx; + U_BITMAP16 Bm16h; + const char *px; + if(U_WMRCREATEPATTERNBRUSH_get(record, &Bm16h, &cbPx, &px)){ + tidx = add_bm16_image(d, Bm16h, px); + if(tidx == 0xFFFFFFFF){ // Problem with the image, for instance, an unsupported bitmap16 type + double r, g, b; + r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor)); + g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor)); + b = SP_COLOR_U_TO_F( U_RGBAGetB(d->dc[d->level].textColor)); + d->dc[d->level].style.fill.value.color.set( r, g, b ); + d->dc[d->level].fill_mode = DRAW_PAINT; + } + else { + d->dc[d->level].fill_idx = tidx; + d->dc[d->level].fill_mode = DRAW_IMAGE; + } + d->dc[d->level].fill_set = true; + } + } } @@ -1314,7 +1171,7 @@ Wmf::delete_object(PWMF_CALLBACK_DATA d, int index) // If the active object is deleted set default draw values if(index == d->dc[d->level].active_pen){ // Use default pen: solid, black, 1 pixel wide d->dc[d->level].active_pen = -1; - d->dc[d->level].style.stroke_dasharray_set = 0; + d->dc[d->level].style.stroke_dasharray.set = 0; d->dc[d->level].style.stroke_linecap.computed = 2; // U_PS_ENDCAP_SQUARE d->dc[d->level].style.stroke_linejoin.computed = 0; // U_PS_JOIN_MITER; d->dc[d->level].stroke_set = true; @@ -1392,12 +1249,11 @@ void Wmf::common_dib_to_image(PWMF_CALLBACK_DATA d, const char *dib, double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh, uint32_t iUsage){ 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; @@ -1405,87 +1261,72 @@ void Wmf::common_dib_to_image(PWMF_CALLBACK_DATA d, const char *dib, char *sub_px = NULL; // RGBA pixels, subarray const char *px = NULL; // DIB pixels const U_RGBQUAD *ct = NULL; // color table - int32_t width, height, colortype, numCt, invert; - if( (iUsage != U_DIB_RGB_COLORS) || - !(dibparams = wget_DIB_params( // this returns pointers and values, but allocates no memory - dib, - &px, - &ct, - &numCt, - &width, - &height, - &colortype, - &invert - )) - ){ - if(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 + int32_t width, height, colortype, numCt, invert; // if needed these values will be set in wget_DIB_params + if(iUsage == U_DIB_RGB_COLORS){ + // next call returns pointers and values, but allocates no memory + dibparams = wget_DIB_params(dib, &px, &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, 0.0, 0.0, 0); // returns an identity matrix, no offsets. - *(d->outsvg) += "\n\t <image\n"; - *(d->outsvg) += tmp_image.str().c_str(); + tmp_image << " preserveAspectRatio=\"none\"\n"; + tmp_image << "/> \n"; - *(d->outsvg) += "/> \n"; + *(d->outsvg) += tmp_image.str().c_str(); *(d->path) = ""; } @@ -1507,10 +1348,9 @@ void Wmf::common_bm16_to_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char SVGOStringStream tmp_image; + 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; @@ -1531,7 +1371,8 @@ void Wmf::common_bm16_to_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char } if(colortype < 16)return; // these would need a colortable if they were a dib, no idea what bm16 is supposed to do instead. - if(!DIB_to_RGBA( // This is not really a dib, but close enough... + + if(!DIB_to_RGBA(// This is not really a dib, but close enough so that it still works. px, // DIB pixel array ct, // DIB color table (always NULL here) numCt, // DIB color table number of entries (always 0) @@ -1541,15 +1382,13 @@ void Wmf::common_bm16_to_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char colortype, // DIB BitCount Enumeration numCt, // Color table used if not 0 invert // If DIB rows are in opposite order from RGBA rows - ) && - rgba_px - ){ - sub_px = RGBA_to_RGBA( - rgba_px, // full pixel array from DIB - width, // Width of pixel array - height, // Height of pixel array - sx,sy, // starting point in pixel array - &sw,&sh // columns/rows to extract from the pixel array (output array size) + )){ + 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; @@ -1560,26 +1399,26 @@ void Wmf::common_bm16_to_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char ); free(sub_px); } - if(mempng.buffer){ + + gchar *base64String=NULL; + if(mempng.buffer){ // image was Bm16 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, 0.0, 0.0, 0); // returns an identity matrix, no offsets. - *(d->outsvg) += "\n\t <image\n"; - *(d->outsvg) += tmp_image.str().c_str(); + tmp_image << " preserveAspectRatio=\"none\"\n"; + tmp_image << "/> \n"; - *(d->outsvg) += "/> \n"; + *(d->outsvg) += tmp_image.str().c_str(); *(d->path) = ""; } @@ -1636,6 +1475,7 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK tsp.vadvance = 0.0; /* meaningful only when a complex contains two or more lines */ tsp.taln = ALILEFT + ALIBASE; tsp.ldir = LDIR_LR; + tsp.spaces = 0; // this field is only used for debugging tsp.color.Red = 0; /* RGB Black */ tsp.color.Green = 0; /* RGB Black */ tsp.color.Blue = 0; /* RGB Black */ @@ -1646,6 +1486,7 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK tsp.condensed = 100; tsp.co = 0; tsp.fi_idx = -1; /* set to an invalid */ + tsp.rt_tidx = -1; /* set to an invalid */ SVGOStringStream dbg_str; @@ -1686,7 +1527,7 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK iType = *(uint8_t *)(contents + off + offsetof(U_METARECORD, iType ) ); if(iType == U_WMR_SETWINDOWEXT){ OK=0; - nSize = U_WMRSETWINDOWEXT_get(contents + off, &Dst); + (void) U_WMRSETWINDOWEXT_get(contents + off, &Dst); Placeable.Dst.right = Dst.x; Placeable.Dst.bottom = Dst.y; } @@ -1716,7 +1557,10 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK d->dc[d->level].sizeView.x = d->dc[d->level].sizeWnd.x = 0; d->dc[d->level].sizeView.y = d->dc[d->level].sizeWnd.y = 0; - // Upper left corner in device units, usually both 0, but not always + /* Upper left corner in device units, usually both 0, but not always. + If a placeable header is used, and later a windoworg/windowext are found, then + the placeable information will be ignored. + */ d->ulCornerInX = Placeable.Dst.left; d->ulCornerInY = Placeable.Dst.top; @@ -1787,7 +1631,7 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK // 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) || ((wmr_mask != 0xFFFFFFFF) && (wmr_mask & U_DRAW_TEXT) && d->tri->dirty)){ + if ((d->dc[d->level].dirty & DIRTY_TEXT) || ((wmr_mask != U_WMR_INVALID) && (wmr_mask & U_DRAW_TEXT) && d->tri->dirty)){ TR_layout_analyze(d->tri); TR_layout_2_svg(d->tri); SVGOStringStream ts; @@ -1830,7 +1674,7 @@ std::cout << "BEFORE DRAW" */ if( - (wmr_mask != 0xFFFFFFFF) && // next record is valid type + (wmr_mask != U_WMR_INVALID) && // next record is valid type (d->mask & U_DRAW_VISIBLE) && // This record is drawable ( (d->mask & U_DRAW_FORCE) || // This draw is forced by STROKE/FILL/STROKEANDFILL PATH @@ -1953,6 +1797,8 @@ std::cout << "BEFORE DRAW" { dbg_str << "<!-- U_WMR_SETWINDOWORG -->\n"; nSize = U_WMRSETWINDOWORG_get(contents, &d->dc[d->level].winorg); + d->ulCornerOutX = 0.0; // In the examples seen to date if this record is used with a placeable header, that header is ignored + d->ulCornerOutY = 0.0; break; } case U_WMR_SETWINDOWEXT: @@ -1968,6 +1814,20 @@ std::cout << "BEFORE DRAW" d->dc[d->level].sizeWnd.y = d->PixelsOutY; } } + else { + /* There are a lot WMF files in circulation with the x,y values in the setwindowext reversed. If this is detected, swap them. + There is a remote possibility that the strange scaling this implies was intended, and those will be rendered incorrectly */ + double Ox = d->PixelsOutX; + double Oy = d->PixelsOutY; + double Wx = d->dc[d->level].sizeWnd.x; + double Wy = d->dc[d->level].sizeWnd.y; + if(Wx != Wy && Geom::are_near(Ox/Wy, Oy/Wx, 1.01/MIN(Wx,Wy)) ){ + int tmp; + tmp = d->dc[d->level].sizeWnd.x; + d->dc[d->level].sizeWnd.x = d->dc[d->level].sizeWnd.y; + d->dc[d->level].sizeWnd.y = tmp; + } + } if (!d->dc[d->level].sizeView.x || !d->dc[d->level].sizeView.y) { /* Previously it used sizeWnd, but that always resulted in scale = 1 if no viewport ever appeared, and in most files, it did not */ @@ -2100,7 +1960,7 @@ std::cout << "BEFORE DRAW" int stat = wmr_arc_points(rc, ArcStart, ArcEnd,&f1, f2, ¢er, &start, &end, &size); if(!stat){ tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y); - tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ; + tmp_path << " 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 << " "; @@ -2152,7 +2012,7 @@ std::cout << "BEFORE DRAW" if(!wmr_arc_points(rc, ArcStart, ArcEnd, &f1, f2, ¢er, &start, &end, &size)){ tmp_path << "\n\tM " << pix_to_xy(d, center.x, center.y); tmp_path << "\n\tL " << pix_to_xy(d, start.x, start.y); - tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ; + tmp_path << " 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 << " "; @@ -2431,8 +2291,8 @@ std::cout << "BEFORE DRAW" d->level = d->level + DC; } while (old_level > d->level) { - if (d->dc[old_level].style.stroke_dash.dash && (old_level==0 || (old_level>0 && d->dc[old_level].style.stroke_dash.dash!=d->dc[old_level-1].style.stroke_dash.dash))){ - delete[] d->dc[old_level].style.stroke_dash.dash; + if (!d->dc[old_level].style.stroke_dasharray.values.empty() && (old_level==0 || (old_level>0 && d->dc[old_level].style.stroke_dasharray.values!=d->dc[old_level-1].style.stroke_dasharray.values))){ + d->dc[old_level].style.stroke_dasharray.values.clear(); } if(d->dc[old_level].font_name){ free(d->dc[old_level].font_name); // else memory leak @@ -2470,12 +2330,12 @@ std::cout << "BEFORE DRAW" break; case U_WMR_CREATEBRUSHINDIRECT: case U_WMR_DIBCREATEPATTERNBRUSH: + case U_WMR_CREATEPATTERNBRUSH: // <- this one did not display properly on XP, DIBCREATEPATTERNBRUSH works select_brush(d, index); break; case U_WMR_CREATEFONTINDIRECT: select_font(d, index); break; - case U_WMR_CREATEPATTERNBRUSH: // <- this one did not display properly on XP, DIBCREATEPATTERNBRUSH works case U_WMR_CREATEPALETTE: case U_WMR_CREATEBITMAPINDIRECT: case U_WMR_CREATEBITMAP: @@ -2524,6 +2384,7 @@ std::cout << "BEFORE DRAW" if(iType == U_WMR_TEXTOUT){ dbg_str << "<!-- U_WMR_TEXTOUT -->\n"; nSize = U_WMRTEXTOUT_get(contents, &Dst, &tlen, &text); + Opts=0; } else { dbg_str << "<!-- U_WMR_EXTTEXTOUT -->\n"; @@ -3096,7 +2957,7 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) d.dc[0].bkMode = U_TRANSPARENT; d.dc[0].dirty = 0; // Default pen, WMF files that do not specify a pen are unlikely to look very good! - d.dc[0].style.stroke_dasharray_set = 0; + d.dc[0].style.stroke_dasharray.set = 0; d.dc[0].style.stroke_linecap.computed = 2; // U_PS_ENDCAP_SQUARE; d.dc[0].style.stroke_linejoin.computed = 0; // U_PS_JOIN_MITER; d.dc[0].stroke_set = true; @@ -3171,8 +3032,7 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) delete[] d.wmf_obj; } - if (d.dc[0].style.stroke_dash.dash) - delete[] d.dc[0].style.stroke_dash.dash; + d.dc[0].style.stroke_dasharray.values.clear(); for(int i=0; i<=d.level;i++){ if(d.dc[i].font_name)free(d.dc[i].font_name); @@ -3201,7 +3061,14 @@ Wmf::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); 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..5a552ad83 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"); } } @@ -594,8 +596,7 @@ int PrintWmf::create_pen(SPStyle const *style, const Geom::Affine &transform) modstyle |= U_PS_JOIN_BEVEL; } - if (style->stroke_dash.n_dash && - style->stroke_dash.dash) { + if (!style->stroke_dasharray.values.empty()) { if (!FixPPTDashLine) { // if this is set code elsewhere will break dots/dashes into many smaller lines. penstyle = U_PS_DASH;// userstyle not supported apparently, for now map all Inkscape dot/dash to just dash } @@ -605,12 +606,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 +626,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 +635,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 +758,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); @@ -822,7 +823,7 @@ unsigned int PrintWmf::fill( } if ( (style->stroke.isNone() || style->stroke.noneSet || style->stroke_width.computed == 0.0) || - (style->stroke_dash.n_dash && style->stroke_dash.dash && FixPPTDashLine) || + (!style->stroke_dasharray.values.empty() && FixPPTDashLine) || !all_closed ) { print_pathv(pathv, fill_transform); // do any fills. side effect: clears fill_pathv @@ -850,13 +851,13 @@ unsigned int PrintWmf::stroke( return 0; } - if (style->stroke_dash.n_dash && style->stroke_dash.dash && FixPPTDashLine) { + if (!style->stroke_dasharray.values.empty() && FixPPTDashLine) { // convert the path, gets its complete length, and then make a new path with parameter length instead of t Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw; // pathv-> sbasis Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw2; // sbasis using arc length parameter Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw3; // new (discontinuous) path, composed of dots/dashes Geom::Piecewise<Geom::D2<Geom::SBasis> > first_frag; // first fragment, will be appended at end - int n_dash = style->stroke_dash.n_dash; + int n_dash = style->stroke_dasharray.values.size(); int i = 0; //dash index double tlength; // length of tmp_pathpw double slength = 0.0; // start of gragment @@ -869,7 +870,7 @@ unsigned int PrintWmf::stroke( // go around the dash array repeatedly until the entire path is consumed (but not beyond). while (slength < tlength) { - elength = slength + style->stroke_dash.dash[i++]; + elength = slength + style->stroke_dasharray.values[i++]; if (elength > tlength) { elength = tlength; } @@ -880,7 +881,7 @@ unsigned int PrintWmf::stroke( first_frag = fragment; } slength = elength; - slength += style->stroke_dash.dash[i++]; // the gap + slength += style->stroke_dasharray.values[i++]; // the gap if (i >= n_dash) { i = 0; } @@ -898,7 +899,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 +1067,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"); } @@ -1101,35 +1102,39 @@ unsigned int PrintWmf::image( unsigned int w, /** width of bitmap */ unsigned int h, /** height of bitmap */ unsigned int rs, /** row stride (normally w*4) */ - Geom::Affine const & /*tf_ignore*/, /** WRONG affine transform, use the one from m_tr_stack */ - SPStyle const *style) /** provides indirect link to image object */ + Geom::Affine const &tf_rect, /** affine transform only used for defining location and size of rect, for all other tranforms, use the one from m_tr_stack */ + SPStyle const * /*style*/) /** provides indirect link to image object */ { double x1, y1, dw, dh; char *rec = NULL; 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"); } - x1 = g_ascii_strtod(style->object->getAttribute("x"), NULL); - y1 = g_ascii_strtod(style->object->getAttribute("y"), NULL); - dw = g_ascii_strtod(style->object->getAttribute("width"), NULL); - dh = g_ascii_strtod(style->object->getAttribute("height"), NULL); + x1 = tf_rect[4]; + y1 = tf_rect[5]; + dw = ((double) w) * tf_rect[0]; + dh = ((double) h) * tf_rect[3]; Geom::Point pLL(x1, y1); Geom::Point pLL2 = pLL * tf; //location of LL corner in Inkscape coordinates + /* adjust scale of w and h. This works properly when there is no rotation. The values are + a bit strange when there is rotation, but since WMF cannot handle rotation in any case, all + answers are equally wrong. + */ Geom::Point pWH(dw, dh); - Geom::Point pWH2 = pWH * tf.withoutTranslation(); //adjust scale + Geom::Point pWH2 = pWH * tf.withoutTranslation(); 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 +1155,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 +1170,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 +1204,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 +1240,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 +1261,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 +1285,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 +1353,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 +1425,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 +1443,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 +1460,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 +1527,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"); } diff --git a/src/extension/prefdialog.cpp b/src/extension/prefdialog.cpp index f3c6508af..1b657f644 100644 --- a/src/extension/prefdialog.cpp +++ b/src/extension/prefdialog.cpp @@ -42,9 +42,9 @@ namespace Extension { */ PrefDialog::PrefDialog (Glib::ustring name, gchar const * help, Gtk::Widget * controls, Effect * effect) : #if WITH_GTKMM_3_0 - Gtk::Dialog::Dialog(_(name.c_str()), true), + Gtk::Dialog(_(name.c_str()), true), #else - Gtk::Dialog::Dialog(_(name.c_str()), true, true), + Gtk::Dialog(_(name.c_str()), true, true), #endif _help(help), _name(name), diff --git a/src/extension/system.cpp b/src/extension/system.cpp index 7a50826ca..c244d9c16 100644 --- a/src/extension/system.cpp +++ b/src/extension/system.cpp @@ -99,7 +99,7 @@ SPDocument *open(Extension *key, gchar const *filename) Inkscape::Preferences *prefs = Inkscape::Preferences::get(); bool ask = prefs->getBool("/dialogs/import/ask"); Glib::ustring id = Glib::ustring(imod->get_id(), 28); - if (!ask and id.compare( "org.inkscape.input.gdkpixbuf") == 0) { + if (!ask && id.compare( "org.inkscape.input.gdkpixbuf") == 0) { show = false; imod->set_gui(false); } |
