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