summaryrefslogtreecommitdiffstats
path: root/src/extension
diff options
context:
space:
mode:
authorJabier Arraiza Cenoz <jabier.arraiza@marker.es>2014-04-01 17:00:00 +0000
committerJabiertxof <jtx@jtx.marker.es>2014-04-01 17:00:00 +0000
commit208ccdf9782984702f79b8ba416e67dd1e2c2dfa (patch)
tree79d15123aa526c49c6386db6245fbfc6b7a63eaf /src/extension
parentupdate to trunk (diff)
parentpartial 2geom update: (diff)
downloadinkscape-208ccdf9782984702f79b8ba416e67dd1e2c2dfa.tar.gz
inkscape-208ccdf9782984702f79b8ba416e67dd1e2c2dfa.zip
update to trunk
(bzr r12588.1.32)
Diffstat (limited to 'src/extension')
-rw-r--r--src/extension/CMakeLists.txt1
-rw-r--r--src/extension/dbus/doc/spec-to-docbook.xsl2
-rw-r--r--src/extension/error-file.cpp2
-rw-r--r--src/extension/execution-env.h2
-rw-r--r--src/extension/implementation/xslt.cpp2
-rw-r--r--src/extension/internal/Makefile_insert2
-rw-r--r--src/extension/internal/cairo-ps-out.cpp4
-rw-r--r--src/extension/internal/cairo-render-context.cpp39
-rw-r--r--src/extension/internal/cairo-renderer.cpp6
-rw-r--r--src/extension/internal/emf-inout.cpp705
-rw-r--r--src/extension/internal/emf-inout.h44
-rw-r--r--src/extension/internal/emf-print.cpp462
-rw-r--r--src/extension/internal/emf-print.h8
-rw-r--r--src/extension/internal/filter/color.h2
-rw-r--r--src/extension/internal/gdkpixbuf-input.cpp28
-rw-r--r--src/extension/internal/grid.cpp38
-rw-r--r--src/extension/internal/image-resolution.cpp6
-rw-r--r--src/extension/internal/javafx-out.cpp22
-rw-r--r--src/extension/internal/latex-pstricks.cpp9
-rw-r--r--src/extension/internal/metafile-inout.cpp211
-rw-r--r--src/extension/internal/metafile-inout.h93
-rw-r--r--src/extension/internal/metafile-print.cpp4
-rw-r--r--src/extension/internal/odf.cpp19
-rw-r--r--src/extension/internal/odf.h9
-rw-r--r--src/extension/internal/pdfinput/pdf-parser.cpp13
-rw-r--r--src/extension/internal/pdfinput/svg-builder.cpp77
-rw-r--r--src/extension/internal/pdfinput/svg-builder.h2
-rw-r--r--src/extension/internal/text_reassemble.c173
-rw-r--r--src/extension/internal/text_reassemble.h7
-rw-r--r--src/extension/internal/wmf-inout.cpp529
-rw-r--r--src/extension/internal/wmf-inout.h39
-rw-r--r--src/extension/internal/wmf-print.cpp147
-rw-r--r--src/extension/prefdialog.cpp4
-rw-r--r--src/extension/system.cpp2
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, &center, &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, &center, &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, &center, &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, &center, &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, &center, &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, &center, &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);
}