summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Mathog <>2013-03-19 02:22:04 +0000
committer~suv <suv-sf@users.sourceforge.net>2013-03-19 02:22:04 +0000
commit2bddd4ed1da6759f2ee741f47261b9f431cba7f8 (patch)
tree706af9ac3dac7f5cb3fea3cda177e842d244000f /src
parentmerge from trunk (r12209) (diff)
downloadinkscape-2bddd4ed1da6759f2ee741f47261b9f431cba7f8.tar.gz
inkscape-2bddd4ed1da6759f2ee741f47261b9f431cba7f8.zip
changes_2013_03_18c.patch
This set of patches does the following: 1. Fixed a typo ( where "+ sizeof()" should have been "* sizeof()") which caused a memory problem for EMF/WMF files with very large numbers of hatches. 2. Added support for background mode, background color, and textcolor in hatches. EMF/WMF files change these parameters but the change may be silent until many records later. This has the odd effect that a stroke or fill may be defined (in SVG) and then it is ignored later and replaced with one with a different background color. 3. Fixed WMF output so that it wasn't adding +1 to the number of pixels for Width and Height. (Allows WMF files to go through several cycles of save as, open without changing sizes.) 4. Cleaned up indenting of [ew]mf-{print|inout}.* files, to make them compliant with the inkscape standard. All indents are (I hope) now 4*i deep. 5. Added underline/strikeout support for text read from EMF/WMF files. Inkscape itself cannot currently render this, but it makes it into the SVG, and it shows up correctly when that SVG is read by Opera. 6. Took out all the "throw" calls, replacing them with g_error(). If this comes up again in debugging a define can be used to remap the g_error to temporarily reintroduce the throw so that gdb can catch them. 7. Took out the "%6lf" format changes from patch 11724, retained the "127" length limit in the same sscanf. 8. Put the C type casts back in, reversing those changes from patch 11724. This is a style issue, and I could not find clear guidance for which way to go. (Nor a good rationale for keeping the lengthier C++ syntax.) So I reviewed a large swath of other inkscape code to see if there was a trend and found a very large number of other sections that were using C style casts instead of the more verbose C++ forms. So I kept it the way it has been. 9. The locale changes from 11724 were of course retained. (bzr r11668.1.59)
Diffstat (limited to 'src')
-rw-r--r--src/extension/internal/emf-inout.cpp2143
-rw-r--r--src/extension/internal/emf-inout.h66
-rw-r--r--src/extension/internal/emf-print.cpp1959
-rw-r--r--src/extension/internal/emf-print.h7
-rw-r--r--src/extension/internal/text_reassemble.c271
-rw-r--r--src/extension/internal/text_reassemble.h35
-rw-r--r--src/extension/internal/uwmf.c15
-rw-r--r--src/extension/internal/uwmf.h6
-rw-r--r--src/extension/internal/uwmf_print.c2
-rw-r--r--src/extension/internal/wmf-inout.cpp2349
-rw-r--r--src/extension/internal/wmf-inout.h14
-rw-r--r--src/extension/internal/wmf-print.cpp1805
-rw-r--r--src/extension/internal/wmf-print.h10
13 files changed, 4585 insertions, 4097 deletions
diff --git a/src/extension/internal/emf-inout.cpp b/src/extension/internal/emf-inout.cpp
index d1587a5b6..7a5757235 100644
--- a/src/extension/internal/emf-inout.cpp
+++ b/src/extension/internal/emf-inout.cpp
@@ -67,7 +67,7 @@ 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
+/** Construct a PNG in memory from an RGB from the EMF file
from:
http://www.lemoda.net/c/write-png/
@@ -84,10 +84,10 @@ Originally here, but moved up
#include <stdlib.h>
#include <stdint.h>
*/
-
-/* Given "bitmap", this returns the pixel of bitmap at the point
- ("x", "y"). */
+
+/* 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)
{
@@ -95,87 +95,86 @@ pixel_t * Emf::pixel_at (bitmap_t * bitmap, int x, int y)
}
-/* Write "bitmap" to a PNG file specified by "path"; returns 0 on
- success, non-zero on error. */
+/* 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;
+ 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, char *px){
- bitmap_t bmstore;
- bitmap_t *bitmap=&bmstore;
+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.
+ /* 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){
+ 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;
+ 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;
+ 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);
-
+ 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 *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) {
@@ -185,21 +184,21 @@ void Emf::toPNG(PMEMPNG accum, int width, int height, char *px){
*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);
-
+
}
@@ -209,7 +208,7 @@ inverse of gethexcolor() in emf-print.cpp
uint32_t Emf::sethexcolor(U_COLORREF color){
uint32_t out;
- out = (U_RGBAGetR(color) << 16) +
+ out = (U_RGBAGetR(color) << 16) +
(U_RGBAGetG(color) << 8 ) +
(U_RGBAGetB(color) );
return(out);
@@ -238,11 +237,11 @@ Emf::check (Inkscape::Extension::Extension * /*module*/)
void
-Emf::print_document_to_file(SPDocument *doc, gchar const *filename)
+Emf::print_document_to_file(SPDocument *doc, const gchar *filename)
{
Inkscape::Extension::Print *mod;
SPPrintContext context;
- gchar const *oldconst;
+ const gchar *oldconst;
gchar *oldoutput;
unsigned int ret;
@@ -301,10 +300,10 @@ Emf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filena
bool new_FixImageRot = mod->get_param_bool("FixImageRot"); // remove rotations on images
TableGen( //possibly regenerate the unicode-convert tables
- mod->get_param_bool("TnrToSymbol"),
- mod->get_param_bool("TnrToWingdings"),
- mod->get_param_bool("TnrToZapfDingbats"),
- mod->get_param_bool("UsePUA")
+ mod->get_param_bool("TnrToSymbol"),
+ mod->get_param_bool("TnrToWingdings"),
+ mod->get_param_bool("TnrToZapfDingbats"),
+ mod->get_param_bool("UsePUA")
);
ext->set_param_bool("FixPPTCharPos",new_FixPPTCharPos); // Remember to add any new ones to PrintEmf::init or a mysterious failure will result!
@@ -324,45 +323,46 @@ enum drawmode {DRAW_PAINT, DRAW_PATTERN, DRAW_IMAGE}; // apply to either fill o
-/* given the transformation matrix from worldTranform return the scale in the matrix part. Assumes that the
- matrix is not used to skew, invert, or make another distorting transformation. */
+/* given the transformation matrix from worldTranform return the scale in the matrix part. Assumes that the
+ matrix is not used to skew, invert, or make another distorting transformation. */
double Emf::current_scale(PEMF_CALLBACK_DATA d){
- double scale = d->dc[d->level].worldTransform.eM11 * d->dc[d->level].worldTransform.eM22 -
- d->dc[d->level].worldTransform.eM12 * d->dc[d->level].worldTransform.eM21;
- if(scale <= 0.0)scale=1.0; /* something is dreadfully wrong with the matrix, but do not crash over it */
- scale=sqrt(scale);
- return(scale);
+ double scale =
+ d->dc[d->level].worldTransform.eM11 * d->dc[d->level].worldTransform.eM22 -
+ d->dc[d->level].worldTransform.eM12 * d->dc[d->level].worldTransform.eM21;
+ if(scale <= 0.0)scale=1.0; /* something is dreadfully wrong with the matrix, but do not crash over it */
+ scale=sqrt(scale);
+ return(scale);
}
-/* given the transformation matrix from worldTranform and the current x,y position in inkscape coordinates,
- generate an SVG transform that gives the same amount of rotation, no scaling, and maps x,y back onto x,y. This is used for
- rotating objects when the location of at least one point in that object is known. Returns:
- "matrix(a,b,c,d,e,f)" (WITH the double quotes)
+/* given the transformation matrix from worldTranform and the current x,y position in inkscape coordinates,
+ generate an SVG transform that gives the same amount of rotation, no scaling, and maps x,y back onto x,y. This is used for
+ rotating objects when the location of at least one point in that object is known. Returns:
+ "matrix(a,b,c,d,e,f)" (WITH the double quotes)
*/
std::string Emf::current_matrix(PEMF_CALLBACK_DATA d, double x, double y, int useoffset){
- std::stringstream cxform;
- double scale = current_scale(d);
- cxform << "\"matrix(";
- cxform << d->dc[d->level].worldTransform.eM11/scale; cxform << ",";
- cxform << d->dc[d->level].worldTransform.eM12/scale; cxform << ",";
- cxform << d->dc[d->level].worldTransform.eM21/scale; cxform << ",";
- cxform << d->dc[d->level].worldTransform.eM22/scale; cxform << ",";
- if(useoffset){
- /* for the "new" coordinates drop the worldtransform translations, not used here */
- double newx = x * d->dc[d->level].worldTransform.eM11/scale + y * d->dc[d->level].worldTransform.eM21/scale;
- double newy = x * d->dc[d->level].worldTransform.eM12/scale + y * d->dc[d->level].worldTransform.eM22/scale;
- cxform << x - newx; cxform << ",";
- cxform << y - newy;
- }
- else {
- cxform << "0,0";
- }
- cxform << ")\"";
- return(cxform.str());
+ std::stringstream cxform;
+ double scale = current_scale(d);
+ cxform << "\"matrix(";
+ cxform << d->dc[d->level].worldTransform.eM11/scale; cxform << ",";
+ cxform << d->dc[d->level].worldTransform.eM12/scale; cxform << ",";
+ cxform << d->dc[d->level].worldTransform.eM21/scale; cxform << ",";
+ cxform << d->dc[d->level].worldTransform.eM22/scale; cxform << ",";
+ if(useoffset){
+ /* for the "new" coordinates drop the worldtransform translations, not used here */
+ double newx = x * d->dc[d->level].worldTransform.eM11/scale + y * d->dc[d->level].worldTransform.eM21/scale;
+ double newy = x * d->dc[d->level].worldTransform.eM12/scale + y * d->dc[d->level].worldTransform.eM22/scale;
+ cxform << x - newx; cxform << ",";
+ cxform << y - newy;
+ }
+ else {
+ cxform << "0,0";
+ }
+ cxform << ")\"";
+ return(cxform.str());
}
-/* given the transformation matrix from worldTranform return the rotation angle in radians.
- counter clocwise from the x axis. */
+/* given the transformation matrix from worldTranform return the rotation angle in radians.
+ counter clocwise from the x axis. */
double Emf::current_rotation(PEMF_CALLBACK_DATA d){
return -std::atan2(d->dc[d->level].worldTransform.eM12, d->dc[d->level].worldTransform.eM11);
}
@@ -370,350 +370,408 @@ double Emf::current_rotation(PEMF_CALLBACK_DATA d){
/* Add another 100 blank slots to the hatches array.
*/
void Emf::enlarge_hatches(PEMF_CALLBACK_DATA d){
- d->hatches.size += 100;
- d->hatches.strings = (char **) realloc(d->hatches.strings,d->hatches.size + sizeof(char *));
+ d->hatches.size += 100;
+ d->hatches.strings = (char **) realloc(d->hatches.strings,d->hatches.size * sizeof(char *));
}
/* See if the pattern name is already in the list. If it is return its position (1->n, not 1-n-1)
*/
int Emf::in_hatches(PEMF_CALLBACK_DATA d, char *test){
- int i;
- for(i=0; i<d->hatches.count; i++){
- if(strcmp(test,d->hatches.strings[i])==0)return(i+1);
- }
- return(0);
+ int i;
+ for(i=0; i<d->hatches.count; i++){
+ if(strcmp(test,d->hatches.strings[i])==0)return(i+1);
+ }
+ return(0);
}
/* (Conditionally) add a hatch. If a matching hatch already exists nothing happens. If one
- does not exist it is added to the hatches list and also entered into <defs>.
+ does not exist it is added to the hatches list and also entered into <defs>.
+ This is also used to add the path part of the hatches, which they reference with a xlink:href
*/
uint32_t Emf::add_hatch(PEMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hatchColor){
- char hatchname[64]; // big enough
- char hrotname[64]; // big enough
- char tmpcolor[8];
- uint32_t idx;
-
- if(hatchType==U_HS_DIAGCROSS){ // This is the only one with dependencies on others
- (void) add_hatch(d,U_HS_FDIAGONAL,hatchColor);
- (void) add_hatch(d,U_HS_BDIAGONAL,hatchColor);
- }
-
- sprintf(tmpcolor,"%6.6X",sethexcolor(hatchColor));
- switch(hatchType){
- case U_HS_SOLIDTEXTCLR:
- case U_HS_DITHEREDTEXTCLR:
- sprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].textColor));
- break;
- case U_HS_SOLIDBKCLR:
- case U_HS_DITHEREDBKCLR:
- sprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].bkColor));
- break;
- default:
- break;
- }
-
- // EMF can take solid colors from background or the default text color but on conversion to inkscape
- // these need to go to a defined color. Consequently the hatchType also has to go to a solid color, otherwise
- // on export the background/text might not match at the time this is written, and the colors will shift.
- if(hatchType > U_HS_SOLIDCLR)hatchType = U_HS_SOLIDCLR;
-
- // pattern defines hatch when there is no rotation. Load this one first.
- sprintf(hatchname,"EMFhatch%d_%s",hatchType,tmpcolor); /* name of pattern BEFORE rotation*/
- idx = in_hatches(d,hatchname);
- if(!idx){ // add it if not already present
- if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
- d->hatches.strings[d->hatches.count++]=strdup(hatchname);
-
- *(d->defs) += "\n";
- *(d->defs) += " <pattern id=\"";
- *(d->defs) += hatchname;
- *(d->defs) += "\"\n";
- switch(hatchType){
- case U_HS_HORIZONTAL:
- *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" >\n";
- *(d->defs) += " <path d=\"M 0 0 6 0\" style=\"fill:none;stroke:#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\" />\n";
+ char hatchname[64]; // big enough
+ char hpathname[64]; // big enough
+ char hbkname[64]; // big enough
+ char tmpcolor[8];
+ char bkcolor[8];
+ uint32_t idx;
+
+ switch(hatchType){
+ case U_HS_SOLIDTEXTCLR:
+ case U_HS_DITHEREDTEXTCLR:
+ sprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].textColor));
+ break;
+ case U_HS_SOLIDBKCLR:
+ case U_HS_DITHEREDBKCLR:
+ sprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].bkColor));
break;
- case U_HS_VERTICAL:
- *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" >\n";
- *(d->defs) += " <path d=\"M 0 0 0 6\" style=\"fill:none;stroke:#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\" />\n";
+ default:
+ sprintf(tmpcolor,"%6.6X",sethexcolor(hatchColor));
break;
- case U_HS_FDIAGONAL:
- *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" viewBox=\"0 0 6 6\" preserveAspectRatio=\"none\" >\n";
- *(d->defs) += " <line x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\" id=\"sub";
- *(d->defs) += hatchname;
- *(d->defs) += "\"/>\n";
- *(d->defs) += " <use xlink:href=\"#sub";
- *(d->defs) += hatchname;
- *(d->defs) += "\" transform=\"translate(6,0)\"/>\n";
- *(d->defs) += " <use xlink:href=\"#sub";
- *(d->defs) += hatchname;
- *(d->defs) += "\" transform=\"translate(-6,0)\"/>\n";
+ }
+
+ /* For both bkMode types set the PATH + FOREGROUND COLOR for the indicated standard hatch.
+ This will be used late to compose, or recompose the transparent or opaque final hatch.*/
+
+ std::string refpath; // used to reference later the path pieces which are about to be created
+ sprintf(hpathname,"EMFhpath%d_%s",hatchType,tmpcolor);
+ idx = in_hatches(d,hpathname);
+ if(!idx){ // add path/color if not already present
+ if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
+ d->hatches.strings[d->hatches.count++]=strdup(hpathname);
+
+ *(d->defs) += "\n";
+ switch(hatchType){
+ case U_HS_HORIZONTAL:
+ *(d->defs) += " <path id=\"";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" d=\"M 0 0 6 0\" style=\"fill:none;stroke:#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\" />\n";
+ break;
+ case U_HS_VERTICAL:
+ *(d->defs) += " <path id=\"";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" d=\"M 0 0 0 6\" style=\"fill:none;stroke:#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\" />\n";
+ break;
+ case U_HS_FDIAGONAL:
+ *(d->defs) += " <line id=\"sub";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\"/>\n";
+ break;
+ case U_HS_BDIAGONAL:
+ *(d->defs) += " <line id=\"sub";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\"/>\n";
+ break;
+ case U_HS_CROSS:
+ *(d->defs) += " <path id=\"";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" d=\"M 0 0 6 0 M 0 0 0 6\" style=\"fill:none;stroke:#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\" />\n";
+ break;
+ case U_HS_DIAGCROSS:
+ *(d->defs) += " <line id=\"subfd";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\"/>\n";
+ *(d->defs) += " <line id=\"subbd";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\"/>\n";
+ break;
+ case U_HS_SOLIDCLR:
+ case U_HS_DITHEREDCLR:
+ case U_HS_SOLIDTEXTCLR:
+ case U_HS_DITHEREDTEXTCLR:
+ case U_HS_SOLIDBKCLR:
+ case U_HS_DITHEREDBKCLR:
+ default:
+ *(d->defs) += " <path id=\"";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" d=\"M 0 0 6 0 6 6 0 6 z\" style=\"fill:#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += ";stroke:none";
+ *(d->defs) += "\" />\n";
+ break;
+ }
+ }
+
+ // References to paths possibly just created above. These will be used in the actual patterns.
+ switch(hatchType){
+ case U_HS_HORIZONTAL:
+ case U_HS_VERTICAL:
+ case U_HS_CROSS:
+ case U_HS_SOLIDCLR:
+ case U_HS_DITHEREDCLR:
+ case U_HS_SOLIDTEXTCLR:
+ case U_HS_DITHEREDTEXTCLR:
+ case U_HS_SOLIDBKCLR:
+ case U_HS_DITHEREDBKCLR:
+ default:
+ refpath += " <use xlink:href=\"#";
+ refpath += hpathname;
+ refpath += "\" />\n";
+ break;
+ case U_HS_FDIAGONAL:
+ case U_HS_BDIAGONAL:
+ refpath += " <use xlink:href=\"#sub";
+ refpath += hpathname;
+ refpath += "\" />\n";
+ refpath += " <use xlink:href=\"#sub";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(6,0)\" />\n";
+ refpath += " <use xlink:href=\"#sub";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(-6,0)\" />\n";
+ break;
+ case U_HS_DIAGCROSS:
+ refpath += " <use xlink:href=\"#subfd";
+ refpath += hpathname;
+ refpath += "\" />\n";
+ refpath += " <use xlink:href=\"#subfd";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(6,0)\"/>\n";
+ refpath += " <use xlink:href=\"#subfd";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(-6,0)\"/>\n";
+ refpath += " <use xlink:href=\"#subbd";
+ refpath += hpathname;
+ refpath += "\" />\n";
+ refpath += " <use xlink:href=\"#subbd";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(6,0)\"/>\n";
+ refpath += " <use xlink:href=\"#subbd";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(-6,0)\"/>\n";
break;
- case U_HS_BDIAGONAL:
- *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" viewBox=\"0 0 6 6\" preserveAspectRatio=\"none\" >\n";
- *(d->defs) += " <line x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\" id=\"sub";
- *(d->defs) += hatchname;
- *(d->defs) += "\"/>\n";
- *(d->defs) += " <use xlink:href=\"#sub";
- *(d->defs) += hatchname;
- *(d->defs) += "\" transform=\"translate(6,0)\"/>\n";
- *(d->defs) += " <use xlink:href=\"#sub";
+ }
+
+ if(d->dc[d->level].bkMode == U_TRANSPARENT || hatchType >= U_HS_SOLIDCLR){
+ sprintf(hatchname,"EMFhatch%d_%s",hatchType,tmpcolor);
+ sprintf(hpathname,"EMFhpath%d_%s",hatchType,tmpcolor);
+ idx = in_hatches(d,hatchname);
+ if(!idx){ // add it if not already present
+ if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
+ d->hatches.strings[d->hatches.count++]=strdup(hatchname);
+ *(d->defs) += "\n";
+ *(d->defs) += " <pattern id=\"";
*(d->defs) += hatchname;
- *(d->defs) += "\" transform=\"translate(-6,0)\"/>\n";
- break;
- case U_HS_CROSS:
- *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" >\n";
- *(d->defs) += " <path d=\"M 0 0 6 0 M 0 0 0 6\" style=\"fill:none;stroke:#";
- *(d->defs) += tmpcolor;
+ *(d->defs) += "\" xlink:href=\"#EMFhbasepattern\">\n";
+ *(d->defs) += refpath;
+ *(d->defs) += " </pattern>\n";
+ idx = d->hatches.count;
+ }
+ }
+ else { // bkMode==U_OPAQUE
+ /* Set up an object in the defs for this background, if there is not one already there */
+ sprintf(bkcolor,"%6.6X",sethexcolor(d->dc[d->level].bkColor));
+ sprintf(hbkname,"EMFhbkclr_%s",bkcolor);
+ idx = in_hatches(d,hbkname);
+ if(!idx){ // add path/color if not already present. Hatchtype is not needed in the name.
+ if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
+ d->hatches.strings[d->hatches.count++]=strdup(hbkname);
+
+ *(d->defs) += "\n";
+ *(d->defs) += " <rect id=\"";
+ *(d->defs) += hbkname;
+ *(d->defs) += "\" x=\"0\" y=\"0\" width=\"6\" height=\"6\" fill=\"#";
+ *(d->defs) += bkcolor;
*(d->defs) += "\" />\n";
- break;
- case U_HS_DIAGCROSS:
- *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" viewBox=\"0 0 6 6\" preserveAspectRatio=\"none\" >\n";
- *(d->defs) += " <use xlink:href=\"#sub";
- sprintf(hrotname,"EMFhatch%d_%6.6X",U_HS_FDIAGONAL,sethexcolor(hatchColor)); // keep hatchname intact for later, hrotname will overwrite this
- *(d->defs) += hrotname;
- *(d->defs) += "\" transform=\"translate(0,0)\"/>\n";
- *(d->defs) += " <use xlink:href=\"#sub";
- sprintf(hrotname,"EMFhatch%d_%6.6X",U_HS_BDIAGONAL,sethexcolor(hatchColor));
- *(d->defs) += hrotname;
- *(d->defs) += "\" transform=\"translate(0,0)\"/>\n";
- break;
- case U_HS_SOLIDCLR:
- case U_HS_DITHEREDCLR:
- case U_HS_SOLIDTEXTCLR:
- case U_HS_DITHEREDTEXTCLR:
- case U_HS_SOLIDBKCLR:
- case U_HS_DITHEREDBKCLR:
- default:
- *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" >\n";
- *(d->defs) += " <path d=\"M 0 0 6 0 6 6 0 6 z\" style=\"fill:#";
- *(d->defs) += tmpcolor;
- *(d->defs) += ";stroke:none";
+ }
+
+ // this is the pattern, its name will show up in Inkscape's pattern selector
+ sprintf(hatchname,"EMFhatch%d_%s_%s",hatchType,tmpcolor,bkcolor);
+ idx = in_hatches(d,hatchname);
+ if(!idx){ // add it if not already present
+ if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
+ d->hatches.strings[d->hatches.count++]=strdup(hatchname);
+ *(d->defs) += "\n";
+ *(d->defs) += " <pattern id=\"";
+ *(d->defs) += hatchname;
+ *(d->defs) += "\" xlink:href=\"#EMFhbasepattern\">\n";
+ *(d->defs) += " <use xlink:href=\"#";
+ *(d->defs) += hbkname;
*(d->defs) += "\" />\n";
- break;
- }
- *(d->defs) += " ";
- *(d->defs) += " </pattern>\n";
- idx = d->hatches.count;
- }
-
-
- // pattern allows the inner pattern to be rotated nicely, load this one second only if needed
- // hatchname retained from above
- sprintf(hrotname,"EMFrothatch%d_%s",hatchType,tmpcolor); /* name of pattern AFTER rotation*/
- if(current_rotation(d) >= 0.00001 || current_rotation(d) <= -0.00001){ /* some rotation, allow a little rounding error around 0 degrees */
- idx = in_hatches(d,hrotname);
- if(!idx){
- if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
- d->hatches.strings[d->hatches.count++]=strdup(hrotname);
-
- *(d->defs) += "\n";
- *(d->defs) += " <pattern\n";
- *(d->defs) += " id=\"";
- *(d->defs) += hrotname;
- *(d->defs) += "\"\n";
- *(d->defs) += " xlink:href=\"#";
- *(d->defs) += hatchname;
- *(d->defs) += "\"\n";
- *(d->defs) += " patternTransform=";
- *(d->defs) += current_matrix(d, 0.0, 0.0, 0); //j use offset 0,0
- *(d->defs) += " />\n";
- idx = d->hatches.count;
- }
- }
-
- return(idx-1);
+ *(d->defs) += refpath;
+ *(d->defs) += " </pattern>\n";
+ idx = d->hatches.count;
+ }
+ }
+ return(idx-1);
}
/* Add another 100 blank slots to the images array.
*/
void Emf::enlarge_images(PEMF_CALLBACK_DATA d){
- d->images.size += 100;
- d->images.strings = (char **) realloc(d->images.strings,d->images.size + sizeof(char *));
+ d->images.size += 100;
+ d->images.strings = (char **) realloc(d->images.strings,d->images.size * sizeof(char *));
}
/* See if the image string is already in the list. If it is return its position (1->n, not 1-n-1)
*/
int Emf::in_images(PEMF_CALLBACK_DATA d, char *test){
- int i;
- for(i=0; i<d->images.count; i++){
- if(strcmp(test,d->images.strings[i])==0)return(i+1);
- }
- return(0);
+ int i;
+ for(i=0; i<d->images.count; i++){
+ if(strcmp(test,d->images.strings[i])==0)return(i+1);
+ }
+ return(0);
}
/* (Conditionally) add an image. If a matching image already exists nothing happens. If one
- does not exist it is added to the images list and also entered into <defs>.
-
+ does not exist it is added to the images list and also entered into <defs>.
+
U_EMRCREATEMONOBRUSH records only work when the bitmap is monochrome. If we hit one that isn't
set idx to 2^32-1 and let the caller handle it.
*/
-uint32_t Emf::add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint32_t cbBmi,
- 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;
-
- MEMPNG mempng; // PNG in memory comes back in this
- mempng.buffer = NULL;
-
- char *rgba_px = NULL; // RGBA pixels
- const char *px = NULL; // DIB pixels
- const 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
- ))
- ){
-
- // 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);
- }
- }
- gchar *base64String;
- if(dibparams == U_BI_JPEG || dibparams==U_BI_PNG){
- base64String = g_base64_encode((guchar*) px, numCt );
- idx = in_images(d, (char *) base64String);
- }
- else if(mempng.buffer){
- base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
- free(mempng.buffer);
- idx = in_images(d, (char *) base64String);
- }
- else {
- // insert a random 3x4 blotch otherwise
- width = 3;
- height = 4;
- base64String = strdup("iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII=");
- idx = in_images(d, (char *) base64String);
- }
- if(!idx){ // add it if not already present - we looked at the actual data for comparison
- if(d->images.count == d->images.size){ enlarge_images(d); }
- idx = d->images.count;
- d->images.strings[d->images.count++]=strdup(base64String);
-
- sprintf(imagename,"EMFimage%d",idx++);
- sprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer
-
- *(d->defs) += "\n";
- *(d->defs) += " <image id=\"";
- *(d->defs) += imagename;
- *(d->defs) += "\"\n ";
- *(d->defs) += xywh;
- *(d->defs) += "\n";
- if(dibparams == U_BI_JPEG){ *(d->defs) += " xlink:href=\"data:image/jpeg;base64,"; }
- else { *(d->defs) += " xlink:href=\"data:image/png;base64,"; }
- *(d->defs) += base64String;
- *(d->defs) += "\"\n";
- *(d->defs) += " />\n";
-
-
- *(d->defs) += "\n";
- *(d->defs) += " <pattern id=\"";
- *(d->defs) += imagename;
- *(d->defs) += "_ref\"\n ";
- *(d->defs) += xywh;
- *(d->defs) += "\n patternUnits=\"userSpaceOnUse\"";
- *(d->defs) += " >\n";
- *(d->defs) += " <use id=\"";
- *(d->defs) += imagename;
- *(d->defs) += "_ign\" ";
- *(d->defs) += " xlink:href=\"#";
- *(d->defs) += imagename;
- *(d->defs) += "\" />\n";
- *(d->defs) += " ";
- *(d->defs) += " </pattern>\n";
- }
- g_free(base64String);
-
- /* image allows the inner image to be rotated nicely, load this one second only if needed
- imagename retained from above
- Here comes a dreadful hack. How do we determine if this rotation of the base image has already
- been loaded? The image names contain no identifying information, they are just numbered sequentially.
- So the rotated name is EMFrotimage###_XXXXXX, where ### is the number of the referred to image, and
- XXXX is the rotation in radians x 1000000 and truncated. That is then stored in BASE64 as the "image".
- The corresponding SVG generated though is not for an image, but a reference to an image.
- The name of the pattern MUST stil be EMFimage###_ref or output_style() will not be able to use it.
- */
- if(current_rotation(d) >= 0.00001 || current_rotation(d) <= -0.00001){ /* some rotation, allow a little rounding error around 0 degrees */
- int tangle = round(current_rotation(d)*1000000.0);
- sprintf(imrotname,"EMFrotimage%d_%d",idx-1,tangle);
- base64String = g_base64_encode((guchar*) imrotname, strlen(imrotname) );
- idx = in_images(d, (char *) base64String); // scan for this "image"
- if(!idx){
- if(d->images.count == d->images.size){ enlarge_images(d); }
- idx = d->images.count;
- d->images.strings[d->images.count++]=strdup(base64String);
- sprintf(imrotname,"EMFimage%d",idx++);
-
- *(d->defs) += "\n";
- *(d->defs) += " <pattern\n";
- *(d->defs) += " id=\"";
- *(d->defs) += imrotname;
- *(d->defs) += "_ref\"\n";
- *(d->defs) += " xlink:href=\"#";
- *(d->defs) += imagename;
- *(d->defs) += "_ref\"\n";
- *(d->defs) += " patternTransform=";
- *(d->defs) += current_matrix(d, 0.0, 0.0, 0); //j use offset 0,0
- *(d->defs) += " />\n";
- }
- g_free(base64String);
- }
-
- return(idx-1);
+uint32_t Emf::add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint32_t cbBmi,
+ 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;
+
+ MEMPNG mempng; // PNG in memory comes back in this
+ mempng.buffer = NULL;
+
+ char *rgba_px = NULL; // RGBA pixels
+ const char *px = NULL; // DIB pixels
+ const 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
+ ))
+ ){
+
+ // 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);
+ }
+ }
+ gchar *base64String;
+ if(dibparams == U_BI_JPEG || dibparams==U_BI_PNG){
+ base64String = g_base64_encode((guchar*) px, numCt );
+ idx = in_images(d, (char *) base64String);
+ }
+ else if(mempng.buffer){
+ base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
+ free(mempng.buffer);
+ idx = in_images(d, (char *) base64String);
+ }
+ else {
+ // insert a random 3x4 blotch otherwise
+ width = 3;
+ height = 4;
+ base64String = g_strdup("iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII=");
+ idx = in_images(d, (char *) base64String);
+ }
+ if(!idx){ // add it if not already present - we looked at the actual data for comparison
+ if(d->images.count == d->images.size){ enlarge_images(d); }
+ idx = d->images.count;
+ d->images.strings[d->images.count++]=strdup(base64String);
+
+ sprintf(imagename,"EMFimage%d",idx++);
+ sprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer
+
+ *(d->defs) += "\n";
+ *(d->defs) += " <image id=\"";
+ *(d->defs) += imagename;
+ *(d->defs) += "\"\n ";
+ *(d->defs) += xywh;
+ *(d->defs) += "\n";
+ if(dibparams == U_BI_JPEG){ *(d->defs) += " xlink:href=\"data:image/jpeg;base64,"; }
+ else { *(d->defs) += " xlink:href=\"data:image/png;base64,"; }
+ *(d->defs) += base64String;
+ *(d->defs) += "\"\n";
+ *(d->defs) += " />\n";
+
+
+ *(d->defs) += "\n";
+ *(d->defs) += " <pattern id=\"";
+ *(d->defs) += imagename;
+ *(d->defs) += "_ref\"\n ";
+ *(d->defs) += xywh;
+ *(d->defs) += "\n patternUnits=\"userSpaceOnUse\"";
+ *(d->defs) += " >\n";
+ *(d->defs) += " <use id=\"";
+ *(d->defs) += imagename;
+ *(d->defs) += "_ign\" ";
+ *(d->defs) += " xlink:href=\"#";
+ *(d->defs) += imagename;
+ *(d->defs) += "\" />\n";
+ *(d->defs) += " ";
+ *(d->defs) += " </pattern>\n";
+ }
+ g_free(base64String);
+
+ /* image allows the inner image to be rotated nicely, load this one second only if needed
+ imagename retained from above
+ Here comes a dreadful hack. How do we determine if this rotation of the base image has already
+ been loaded? The image names contain no identifying information, they are just numbered sequentially.
+ So the rotated name is EMFrotimage###_XXXXXX, where ### is the number of the referred to image, and
+ XXXX is the rotation in radians x 1000000 and truncated. That is then stored in BASE64 as the "image".
+ The corresponding SVG generated though is not for an image, but a reference to an image.
+ The name of the pattern MUST stil be EMFimage###_ref or output_style() will not be able to use it.
+ */
+ if(current_rotation(d) >= 0.00001 || current_rotation(d) <= -0.00001){ /* some rotation, allow a little rounding error around 0 degrees */
+ int tangle = round(current_rotation(d)*1000000.0);
+ sprintf(imrotname,"EMFrotimage%d_%d",idx-1,tangle);
+ base64String = g_base64_encode((guchar*) imrotname, strlen(imrotname) );
+ idx = in_images(d, (char *) base64String); // scan for this "image"
+ if(!idx){
+ if(d->images.count == d->images.size){ enlarge_images(d); }
+ idx = d->images.count;
+ d->images.strings[d->images.count++]=strdup(base64String);
+ sprintf(imrotname,"EMFimage%d",idx++);
+
+ *(d->defs) += "\n";
+ *(d->defs) += " <pattern\n";
+ *(d->defs) += " id=\"";
+ *(d->defs) += imrotname;
+ *(d->defs) += "_ref\"\n";
+ *(d->defs) += " xlink:href=\"#";
+ *(d->defs) += imagename;
+ *(d->defs) += "_ref\"\n";
+ *(d->defs) += " patternTransform=";
+ *(d->defs) += current_matrix(d, 0.0, 0.0, 0); //j use offset 0,0
+ *(d->defs) += " />\n";
+ }
+ g_free(base64String);
+ }
+
+ return(idx-1);
}
@@ -728,74 +786,74 @@ Emf::output_style(PEMF_CALLBACK_DATA d, int iType)
sp_color_get_rgb_floatv( &(d->dc[d->level].style.fill.value.color), fill_rgb );
float stroke_rgb[3];
sp_color_get_rgb_floatv(&(d->dc[d->level].style.stroke.value.color), stroke_rgb);
-
+
// for U_EMR_BITBLT with no image, try to approximate some of these operations/
// Assume src color is "white"
if(d->dwRop3){
- switch(d->dwRop3){
- case U_PATINVERT: // treat all of these as black
- case U_SRCINVERT:
- case U_DSTINVERT:
- case U_BLACKNESS:
- case U_SRCERASE:
- case U_NOTSRCCOPY:
- fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=0.0;
- break;
- case U_SRCCOPY: // treat all of these as white
- case U_NOTSRCERASE:
- case U_PATCOPY:
- case U_WHITENESS:
- fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=1.0;
- break;
- case U_SRCPAINT: // use the existing color
- case U_SRCAND:
- case U_MERGECOPY:
- case U_MERGEPAINT:
- case U_PATPAINT:
- default:
- break;
- }
- d->dwRop3 = 0; // might as well reset it here, it must be set for each BITBLT
+ switch(d->dwRop3){
+ case U_PATINVERT: // treat all of these as black
+ case U_SRCINVERT:
+ case U_DSTINVERT:
+ case U_BLACKNESS:
+ case U_SRCERASE:
+ case U_NOTSRCCOPY:
+ fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=0.0;
+ break;
+ case U_SRCCOPY: // treat all of these as white
+ case U_NOTSRCERASE:
+ case U_PATCOPY:
+ case U_WHITENESS:
+ fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=1.0;
+ break;
+ case U_SRCPAINT: // use the existing color
+ case U_SRCAND:
+ case U_MERGECOPY:
+ case U_MERGEPAINT:
+ case U_PATPAINT:
+ default:
+ break;
+ }
+ d->dwRop3 = 0; // might as well reset it here, it must be set for each BITBLT
}
// Implement some of these, the ones where the original screen color does not matter.
- // The options that merge screen and pen colors cannot be done correctly because we
+ // The options that merge screen and pen colors cannot be done correctly because we
// have no way of knowing what color is already on the screen. For those just pass the
- // pen color through.
+ // pen color through.
switch(d->dwRop2){
- case U_R2_BLACK:
- fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 0.0;
- stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 0.0;
- break;
- case U_R2_NOTMERGEPEN:
- case U_R2_MASKNOTPEN:
- break;
- case U_R2_NOTCOPYPEN:
- fill_rgb[0] = 1.0 - fill_rgb[0];
- fill_rgb[1] = 1.0 - fill_rgb[1];
- fill_rgb[2] = 1.0 - fill_rgb[2];
- stroke_rgb[0] = 1.0 - stroke_rgb[0];
- stroke_rgb[1] = 1.0 - stroke_rgb[1];
- stroke_rgb[2] = 1.0 - stroke_rgb[2];
- break;
- case U_R2_MASKPENNOT:
- case U_R2_NOT:
- case U_R2_XORPEN:
- case U_R2_NOTMASKPEN:
- case U_R2_NOTXORPEN:
- case U_R2_NOP:
- case U_R2_MERGENOTPEN:
- case U_R2_COPYPEN:
- case U_R2_MASKPEN:
- case U_R2_MERGEPENNOT:
- case U_R2_MERGEPEN:
- break;
- case U_R2_WHITE:
- fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 1.0;
- stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 1.0;
- break;
- default:
- break;
+ case U_R2_BLACK:
+ fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 0.0;
+ stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 0.0;
+ break;
+ case U_R2_NOTMERGEPEN:
+ case U_R2_MASKNOTPEN:
+ break;
+ case U_R2_NOTCOPYPEN:
+ fill_rgb[0] = 1.0 - fill_rgb[0];
+ fill_rgb[1] = 1.0 - fill_rgb[1];
+ fill_rgb[2] = 1.0 - fill_rgb[2];
+ stroke_rgb[0] = 1.0 - stroke_rgb[0];
+ stroke_rgb[1] = 1.0 - stroke_rgb[1];
+ stroke_rgb[2] = 1.0 - stroke_rgb[2];
+ break;
+ case U_R2_MASKPENNOT:
+ case U_R2_NOT:
+ case U_R2_XORPEN:
+ case U_R2_NOTMASKPEN:
+ case U_R2_NOTXORPEN:
+ case U_R2_NOP:
+ case U_R2_MERGENOTPEN:
+ case U_R2_COPYPEN:
+ case U_R2_MASKPEN:
+ case U_R2_MERGEPENNOT:
+ case U_R2_MERGEPEN:
+ break;
+ case U_R2_WHITE:
+ fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 1.0;
+ stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 1.0;
+ break;
+ default:
+ break;
}
@@ -808,32 +866,48 @@ Emf::output_style(PEMF_CALLBACK_DATA d, int iType)
switch(d->dc[d->level].fill_mode){
// both of these use the url(#) method
case DRAW_PATTERN:
- snprintf(tmp, 1023, "fill:url(#%s); ",d->hatches.strings[d->dc[d->level].fill_idx]);
- tmp_style << tmp;
- break;
+ snprintf(tmp, 1023, "fill:url(#%s); ",d->hatches.strings[d->dc[d->level].fill_idx]);
+ tmp_style << tmp;
+ break;
case DRAW_IMAGE:
- snprintf(tmp, 1023, "fill:url(#EMFimage%d_ref); ",d->dc[d->level].fill_idx);
- tmp_style << tmp;
- break;
+ snprintf(tmp, 1023, "fill:url(#EMFimage%d_ref); ",d->dc[d->level].fill_idx);
+ tmp_style << tmp;
+ break;
case DRAW_PAINT:
default: // <-- this should never happen, but just in case...
- snprintf(tmp, 1023,
- "fill:#%02x%02x%02x;",
- SP_COLOR_F_TO_U(fill_rgb[0]),
- SP_COLOR_F_TO_U(fill_rgb[1]),
- SP_COLOR_F_TO_U(fill_rgb[2]));
- tmp_style << tmp;
- break;
- }
- snprintf(tmp, 1023,
- "fill-rule:%s;",
- d->dc[d->level].style.fill_rule.value == 0 ? "evenodd" : "nonzero");
+ snprintf(
+ tmp, 1023,
+ "fill:#%02x%02x%02x;",
+ SP_COLOR_F_TO_U(fill_rgb[0]),
+ SP_COLOR_F_TO_U(fill_rgb[1]),
+ SP_COLOR_F_TO_U(fill_rgb[2])
+ );
+ tmp_style << tmp;
+ break;
+ }
+ snprintf(
+ tmp, 1023,
+ "fill-rule:%s;",
+ (d->dc[d->level].style.fill_rule.value == 0 ? "evenodd" : "nonzero")
+ );
tmp_style << tmp;
tmp_style << "fill-opacity:1;";
- if (d->dc[d->level].fill_set && d->dc[d->level].stroke_set && d->dc[d->level].style.stroke_width.value == 1 &&
- fill_rgb[0]==stroke_rgb[0] && fill_rgb[1]==stroke_rgb[1] && fill_rgb[2]==stroke_rgb[2])
- {
+ // if the stroke is the same as the fill, and the right size not to change the end size of the object, do not do it separately
+ if(
+ (d->dc[d->level].fill_set ) &&
+ (d->dc[d->level].stroke_set ) &&
+ (d->dc[d->level].style.stroke_width.value == 1 ) &&
+ (d->dc[d->level].fill_mode == d->dc[d->level].stroke_mode) &&
+ (
+ (d->dc[d->level].fill_mode != DRAW_PAINT) ||
+ (
+ (fill_rgb[0]==stroke_rgb[0]) &&
+ (fill_rgb[1]==stroke_rgb[1]) &&
+ (fill_rgb[2]==stroke_rgb[2])
+ )
+ )
+ ){
d->dc[d->level].stroke_set = false;
}
}
@@ -844,37 +918,43 @@ Emf::output_style(PEMF_CALLBACK_DATA d, int iType)
switch(d->dc[d->level].stroke_mode){
// both of these use the url(#) method
case DRAW_PATTERN:
- snprintf(tmp, 1023, "stroke:url(#%s); ",d->hatches.strings[d->dc[d->level].stroke_idx]);
- tmp_style << tmp;
- break;
+ snprintf(tmp, 1023, "stroke:url(#%s); ",d->hatches.strings[d->dc[d->level].stroke_idx]);
+ tmp_style << tmp;
+ break;
case DRAW_IMAGE:
- snprintf(tmp, 1023, "stroke:url(#EMFimage%d_ref); ",d->dc[d->level].stroke_idx);
- tmp_style << tmp;
- break;
+ snprintf(tmp, 1023, "stroke:url(#EMFimage%d_ref); ",d->dc[d->level].stroke_idx);
+ tmp_style << tmp;
+ break;
case DRAW_PAINT:
default: // <-- this should never happen, but just in case...
- snprintf(tmp, 1023,
- "stroke:#%02x%02x%02x;",
- SP_COLOR_F_TO_U(stroke_rgb[0]),
- SP_COLOR_F_TO_U(stroke_rgb[1]),
- SP_COLOR_F_TO_U(stroke_rgb[2]));
- tmp_style << tmp;
- break;
+ snprintf(
+ tmp, 1023,
+ "stroke:#%02x%02x%02x;",
+ SP_COLOR_F_TO_U(stroke_rgb[0]),
+ SP_COLOR_F_TO_U(stroke_rgb[1]),
+ SP_COLOR_F_TO_U(stroke_rgb[2])
+ );
+ tmp_style << tmp;
+ break;
}
tmp_style << "stroke-width:" <<
MAX( 0.001, d->dc[d->level].style.stroke_width.value ) << "px;";
tmp_style << "stroke-linecap:" <<
- (d->dc[d->level].style.stroke_linecap.computed == 0 ? "butt" :
- d->dc[d->level].style.stroke_linecap.computed == 1 ? "round" :
- d->dc[d->level].style.stroke_linecap.computed == 2 ? "square" :
- "unknown") << ";";
+ (
+ d->dc[d->level].style.stroke_linecap.computed == 0 ? "butt" :
+ d->dc[d->level].style.stroke_linecap.computed == 1 ? "round" :
+ d->dc[d->level].style.stroke_linecap.computed == 2 ? "square" :
+ "unknown"
+ ) << ";";
tmp_style << "stroke-linejoin:" <<
- (d->dc[d->level].style.stroke_linejoin.computed == 0 ? "miter" :
- d->dc[d->level].style.stroke_linejoin.computed == 1 ? "round" :
- d->dc[d->level].style.stroke_linejoin.computed == 2 ? "bevel" :
- "unknown") << ";";
+ (
+ d->dc[d->level].style.stroke_linejoin.computed == 0 ? "miter" :
+ d->dc[d->level].style.stroke_linejoin.computed == 1 ? "round" :
+ d->dc[d->level].style.stroke_linejoin.computed == 2 ? "bevel" :
+ "unknown"
+ ) << ";";
// Set miter limit if known, even if it is not needed immediately (not miter)
tmp_style << "stroke-miterlimit:" <<
@@ -941,7 +1021,7 @@ Emf::pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py)
double wpy = px * d->dc[d->level].worldTransform.eM12 + py * d->dc[d->level].worldTransform.eM22 + d->dc[d->level].worldTransform.eDy;
double y = _pix_y_to_point(d, wpy);
-
+
return y;
}
@@ -956,11 +1036,11 @@ Emf::pix_to_abs_size(PEMF_CALLBACK_DATA d, double px)
/* returns "x,y" (without the quotes) in inkscape coordinates for a pair of EMF x,y coordinates
*/
std::string Emf::pix_to_xy(PEMF_CALLBACK_DATA d, double x, double y){
- std::stringstream cxform;
- cxform << pix_to_x_point(d,x,y);
- cxform << ",";
- cxform << pix_to_y_point(d,x,y);
- return(cxform.str());
+ std::stringstream cxform;
+ cxform << pix_to_x_point(d,x,y);
+ cxform << ",";
+ cxform << pix_to_y_point(d,x,y);
+ return(cxform.str());
}
@@ -969,11 +1049,11 @@ Emf::select_pen(PEMF_CALLBACK_DATA d, int index)
{
PU_EMRCREATEPEN pEmr = NULL;
- if (index >= 0 && index < d->n_obj)
+ if (index >= 0 && index < d->n_obj){
pEmr = (PU_EMRCREATEPEN) d->emf_obj[index].lpEMFR;
+ }
- if (!pEmr)
- return;
+ if (!pEmr){ return; }
switch (pEmr->lopn.lopnStyle & U_PS_STYLE_MASK) {
case U_PS_DASH:
@@ -1000,11 +1080,11 @@ Emf::select_pen(PEMF_CALLBACK_DATA d, int index)
d->dc[d->level].style.stroke_dash.dash[i++] = 1;
d->dc[d->level].style.stroke_dash.dash[i++] = 1;
}
-
+
d->dc[d->level].style.stroke_dasharray_set = 1;
break;
}
-
+
case U_PS_SOLID:
default:
{
@@ -1014,41 +1094,17 @@ Emf::select_pen(PEMF_CALLBACK_DATA d, int index)
}
switch (pEmr->lopn.lopnStyle & U_PS_ENDCAP_MASK) {
- case U_PS_ENDCAP_ROUND:
- {
- d->dc[d->level].style.stroke_linecap.computed = 1;
- break;
- }
- case U_PS_ENDCAP_SQUARE:
- {
- d->dc[d->level].style.stroke_linecap.computed = 2;
- break;
- }
+ case U_PS_ENDCAP_ROUND: { d->dc[d->level].style.stroke_linecap.computed = 1; break; }
+ case U_PS_ENDCAP_SQUARE: { d->dc[d->level].style.stroke_linecap.computed = 2; break; }
case U_PS_ENDCAP_FLAT:
- default:
- {
- d->dc[d->level].style.stroke_linecap.computed = 0;
- break;
- }
+ default: { d->dc[d->level].style.stroke_linecap.computed = 0; break; }
}
switch (pEmr->lopn.lopnStyle & U_PS_JOIN_MASK) {
- case U_PS_JOIN_BEVEL:
- {
- d->dc[d->level].style.stroke_linejoin.computed = 2;
- break;
- }
- case U_PS_JOIN_MITER:
- {
- d->dc[d->level].style.stroke_linejoin.computed = 0;
- break;
- }
+ case U_PS_JOIN_BEVEL: { d->dc[d->level].style.stroke_linejoin.computed = 2; break; }
+ case U_PS_JOIN_MITER: { d->dc[d->level].style.stroke_linejoin.computed = 0; break; }
case U_PS_JOIN_ROUND:
- default:
- {
- d->dc[d->level].style.stroke_linejoin.computed = 1;
- break;
- }
+ default: { d->dc[d->level].style.stroke_linejoin.computed = 1; break; }
}
d->dc[d->level].stroke_set = true;
@@ -1139,7 +1195,7 @@ Emf::select_extpen(PEMF_CALLBACK_DATA d, int index)
d->dc[d->level].style.stroke_dash.dash[i++] = 1;
d->dc[d->level].style.stroke_dash.dash[i++] = 2;
}
-
+
d->dc[d->level].style.stroke_dasharray_set = 1;
break;
}
@@ -1208,49 +1264,50 @@ Emf::select_extpen(PEMF_CALLBACK_DATA d, int index)
d->dc[d->level].stroke_mode = DRAW_PAINT;
}
else {
- if (pEmr->elp.elpWidth) {
- int cur_level = d->level;
- d->level = d->emf_obj[index].level;
- double pen_width = pix_to_abs_size( d, pEmr->elp.elpWidth );
- d->level = cur_level;
- d->dc[d->level].style.stroke_width.value = pen_width;
- } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?)
- //d->dc[d->level].style.stroke_width.value = 1.0;
- int cur_level = d->level;
- d->level = d->emf_obj[index].level;
- double pen_width = pix_to_abs_size( d, 1 );
- d->level = cur_level;
- d->dc[d->level].style.stroke_width.value = pen_width;
- }
-
- if( pEmr->elp.elpBrushStyle == U_BS_SOLID){
- double r, g, b;
- r = SP_COLOR_U_TO_F( U_RGBAGetR(pEmr->elp.elpColor) );
- g = SP_COLOR_U_TO_F( U_RGBAGetG(pEmr->elp.elpColor) );
- b = SP_COLOR_U_TO_F( U_RGBAGetB(pEmr->elp.elpColor) );
- d->dc[d->level].style.stroke.value.color.set( r, g, b );
- d->dc[d->level].stroke_mode = DRAW_PAINT;
- d->dc[d->level].stroke_set = true;
- }
- else if(pEmr->elp.elpBrushStyle == U_BS_HATCHED){
- d->dc[d->level].stroke_idx = add_hatch(d, pEmr->elp.elpHatch, pEmr->elp.elpColor);
- d->dc[d->level].stroke_mode = DRAW_PATTERN;
- d->dc[d->level].stroke_set = true;
- }
- else if(pEmr->elp.elpBrushStyle == U_BS_DIBPATTERN || pEmr->elp.elpBrushStyle == U_BS_DIBPATTERNPT){
- d->dc[d->level].stroke_idx = add_image(d, pEmr, pEmr->cbBits, pEmr->cbBmi, *(uint32_t *) &(pEmr->elp.elpColor), pEmr->offBits, pEmr->offBmi);
- d->dc[d->level].stroke_mode = DRAW_IMAGE;
- d->dc[d->level].stroke_set = true;
- }
- else { // U_BS_PATTERN and anything strange that falls in, stroke is solid textColor
- double r, g, b;
- r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor));
- g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor));
- b = SP_COLOR_U_TO_F( U_RGBAGetB(d->dc[d->level].textColor));
- d->dc[d->level].style.stroke.value.color.set( r, g, b );
- d->dc[d->level].stroke_mode = DRAW_PAINT;
- d->dc[d->level].stroke_set = true;
- }
+ if (pEmr->elp.elpWidth) {
+ int cur_level = d->level;
+ d->level = d->emf_obj[index].level;
+ double pen_width = pix_to_abs_size( d, pEmr->elp.elpWidth );
+ d->level = cur_level;
+ d->dc[d->level].style.stroke_width.value = pen_width;
+ } else { // this stroke should always be rendered as 1 pixel wide, independent of zoom level (can that be done in SVG?)
+ //d->dc[d->level].style.stroke_width.value = 1.0;
+ int cur_level = d->level;
+ d->level = d->emf_obj[index].level;
+ double pen_width = pix_to_abs_size( d, 1 );
+ d->level = cur_level;
+ d->dc[d->level].style.stroke_width.value = pen_width;
+ }
+
+ if( pEmr->elp.elpBrushStyle == U_BS_SOLID){
+ double r, g, b;
+ r = SP_COLOR_U_TO_F( U_RGBAGetR(pEmr->elp.elpColor) );
+ g = SP_COLOR_U_TO_F( U_RGBAGetG(pEmr->elp.elpColor) );
+ b = SP_COLOR_U_TO_F( U_RGBAGetB(pEmr->elp.elpColor) );
+ d->dc[d->level].style.stroke.value.color.set( r, g, b );
+ d->dc[d->level].stroke_mode = DRAW_PAINT;
+ d->dc[d->level].stroke_set = true;
+ }
+ else if(pEmr->elp.elpBrushStyle == U_BS_HATCHED){
+ d->dc[d->level].stroke_idx = add_hatch(d, pEmr->elp.elpHatch, pEmr->elp.elpColor);
+ d->dc[d->level].stroke_recidx = index; // used if the hatch needs to be redone due to bkMode, textmode, etc. changes
+ d->dc[d->level].stroke_mode = DRAW_PATTERN;
+ d->dc[d->level].stroke_set = true;
+ }
+ else if(pEmr->elp.elpBrushStyle == U_BS_DIBPATTERN || pEmr->elp.elpBrushStyle == U_BS_DIBPATTERNPT){
+ d->dc[d->level].stroke_idx = add_image(d, pEmr, pEmr->cbBits, pEmr->cbBmi, *(uint32_t *) &(pEmr->elp.elpColor), pEmr->offBits, pEmr->offBmi);
+ d->dc[d->level].stroke_mode = DRAW_IMAGE;
+ d->dc[d->level].stroke_set = true;
+ }
+ else { // U_BS_PATTERN and anything strange that falls in, stroke is solid textColor
+ double r, g, b;
+ r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor));
+ g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor));
+ b = SP_COLOR_U_TO_F( U_RGBAGetB(d->dc[d->level].textColor));
+ d->dc[d->level].style.stroke.value.color.set( r, g, b );
+ d->dc[d->level].stroke_mode = DRAW_PAINT;
+ d->dc[d->level].stroke_set = true;
+ }
}
}
@@ -1264,38 +1321,39 @@ Emf::select_brush(PEMF_CALLBACK_DATA d, int index)
if (index >= 0 && index < d->n_obj){
iType = ((PU_EMR) (d->emf_obj[index].lpEMFR))->iType;
if(iType == U_EMR_CREATEBRUSHINDIRECT){
- PU_EMRCREATEBRUSHINDIRECT pEmr = (PU_EMRCREATEBRUSHINDIRECT) d->emf_obj[index].lpEMFR;
- if( pEmr->lb.lbStyle == U_BS_SOLID){
- double r, g, b;
- r = SP_COLOR_U_TO_F( U_RGBAGetR(pEmr->lb.lbColor) );
- g = SP_COLOR_U_TO_F( U_RGBAGetG(pEmr->lb.lbColor) );
- b = SP_COLOR_U_TO_F( U_RGBAGetB(pEmr->lb.lbColor) );
- d->dc[d->level].style.fill.value.color.set( r, g, b );
- d->dc[d->level].fill_mode = DRAW_PAINT;
- d->dc[d->level].fill_set = true;
- }
- else if(pEmr->lb.lbStyle == U_BS_HATCHED){
- d->dc[d->level].fill_idx = add_hatch(d, pEmr->lb.lbHatch, pEmr->lb.lbColor);
- d->dc[d->level].fill_mode = DRAW_PATTERN;
- d->dc[d->level].fill_set = true;
- }
+ PU_EMRCREATEBRUSHINDIRECT pEmr = (PU_EMRCREATEBRUSHINDIRECT) d->emf_obj[index].lpEMFR;
+ if( pEmr->lb.lbStyle == U_BS_SOLID){
+ double r, g, b;
+ r = SP_COLOR_U_TO_F( U_RGBAGetR(pEmr->lb.lbColor) );
+ g = SP_COLOR_U_TO_F( U_RGBAGetG(pEmr->lb.lbColor) );
+ b = SP_COLOR_U_TO_F( U_RGBAGetB(pEmr->lb.lbColor) );
+ d->dc[d->level].style.fill.value.color.set( r, g, b );
+ d->dc[d->level].fill_mode = DRAW_PAINT;
+ d->dc[d->level].fill_set = true;
+ }
+ else if(pEmr->lb.lbStyle == U_BS_HATCHED){
+ d->dc[d->level].fill_idx = add_hatch(d, pEmr->lb.lbHatch, pEmr->lb.lbColor);
+ d->dc[d->level].fill_recidx = index; // used if the hatch needs to be redone due to bkMode, textmode, etc. changes
+ d->dc[d->level].fill_mode = DRAW_PATTERN;
+ d->dc[d->level].fill_set = true;
+ }
}
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
- double r, g, b;
- r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor));
- g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor));
- b = SP_COLOR_U_TO_F( U_RGBAGetB(d->dc[d->level].textColor));
- d->dc[d->level].style.fill.value.color.set( r, g, b );
- d->dc[d->level].fill_mode = DRAW_PAINT;
- }
- else {
- d->dc[d->level].fill_idx = tidx;
- d->dc[d->level].fill_mode = DRAW_IMAGE;
- }
- d->dc[d->level].fill_set = true;
+ 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
+ double r, g, b;
+ r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor));
+ g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor));
+ b = SP_COLOR_U_TO_F( U_RGBAGetB(d->dc[d->level].textColor));
+ d->dc[d->level].style.fill.value.color.set( r, g, b );
+ d->dc[d->level].fill_mode = DRAW_PAINT;
+ }
+ else {
+ d->dc[d->level].fill_idx = tidx;
+ d->dc[d->level].fill_mode = DRAW_IMAGE;
+ }
+ d->dc[d->level].fill_set = true;
}
}
}
@@ -1312,18 +1370,18 @@ Emf::select_font(PEMF_CALLBACK_DATA d, int index)
if (!pEmr)return;
- /* The logfont information always starts with a U_LOGFONT structure but the U_EMREXTCREATEFONTINDIRECTW
- is defined as U_LOGFONT_PANOSE so it can handle one of those if that is actually present. Currently only logfont
- is supported, and the remainder, it it really is a U_LOGFONT_PANOSE record, is ignored
+ /* The logfont information always starts with a U_LOGFONT structure but the U_EMREXTCREATEFONTINDIRECTW
+ is defined as U_LOGFONT_PANOSE so it can handle one of those if that is actually present. Currently only logfont
+ is supported, and the remainder, it it really is a U_LOGFONT_PANOSE record, is ignored
*/
int cur_level = d->level;
d->level = d->emf_obj[index].level;
double font_size = pix_to_abs_size( d, pEmr->elfw.elfLogFont.lfHeight );
- /* snap the font_size to the nearest 1/32nd of a point.
- (The size is converted from Pixels to points, snapped, and converted back.)
- See the notes where d->D2Pscale[XY] are set for the reason why.
- Typically this will set the font to the desired exact size. If some peculiar size
- was intended this will, at worst, make it .03125 off, which is unlikely to be a problem. */
+ /* snap the font_size to the nearest 1/32nd of a point.
+ (The size is converted from Pixels to points, snapped, and converted back.)
+ See the notes where d->D2Pscale[XY] are set for the reason why.
+ Typically this will set the font to the desired exact size. If some peculiar size
+ was intended this will, at worst, make it .03125 off, which is unlikely to be a problem. */
font_size = round(20.0 * 0.8 * font_size)/(20.0 * 0.8);
d->level = cur_level;
d->dc[d->level].style.font_size.computed = font_size;
@@ -1348,14 +1406,14 @@ Emf::select_font(PEMF_CALLBACK_DATA d, int index)
// malformed EMF with empty filename may exist, ignore font change if encountered
char *ctmp = U_Utf16leToUtf8((uint16_t *) (pEmr->elfw.elfLogFont.lfFaceName), U_LF_FACESIZE, NULL);
if(ctmp){
- if (d->dc[d->level].font_name){ free(d->dc[d->level].font_name); }
- if(*ctmp){
- d->dc[d->level].font_name = ctmp;
- }
- else { // Malformed EMF might specify an empty font name
- free(ctmp);
- d->dc[d->level].font_name = strdup("Arial"); // Default font, EMF spec says device can pick whatever it wants
- }
+ if (d->dc[d->level].font_name){ free(d->dc[d->level].font_name); }
+ if(*ctmp){
+ d->dc[d->level].font_name = ctmp;
+ }
+ else { // Malformed EMF might specify an empty font name
+ free(ctmp);
+ d->dc[d->level].font_name = strdup("Arial"); // Default font, EMF spec says device can pick whatever it wants
+ }
}
d->dc[d->level].style.baseline_shift.value = ((pEmr->elfw.elfLogFont.lfEscapement + 3600) % 3600) / 10; // use baseline_shift instead of text_transform to avoid overflow
}
@@ -1387,8 +1445,8 @@ Emf::insert_object(PEMF_CALLBACK_DATA d, int index, int type, PU_ENHMETARECORD p
}
}
-/* Identify probable Adobe Illustrator produced EMF files, which do strange things with the scaling.
- The few so far observed all had this format.
+/* Identify probable Adobe Illustrator produced EMF files, which do strange things with the scaling.
+ The few so far observed all had this format.
*/
int Emf::AI_hack(PU_EMRHEADER pEmr){
int ret=0;
@@ -1398,9 +1456,9 @@ int Emf::AI_hack(PU_EMRHEADER pEmr){
char *string = NULL;
if(pEmr->nDescription)string = U_Utf16leToUtf8((uint16_t *)((char *) pEmr + pEmr->offDescription), pEmr->nDescription, NULL);
if(string){
- if((pEmr->nDescription >= 13) &&
+ if((pEmr->nDescription >= 13) &&
(0==strcmp("Adobe Systems",string)) &&
- (nEmr->emr.iType == U_EMR_SETMAPMODE) &&
+ (nEmr->emr.iType == U_EMR_SETMAPMODE) &&
(nEmr->iMode == U_MM_ANISOTROPIC)){ ret=1; }
free(string);
}
@@ -1408,75 +1466,75 @@ int Emf::AI_hack(PU_EMRHEADER pEmr){
}
/**
- \fn create a UTF-32LE buffer and fill it with UNICODE unknown character
- \param count number of copies of the Unicode unknown character to fill with
+ \fn create a UTF-32LE buffer and fill it with UNICODE unknown character
+ \param count number of copies of the Unicode unknown character to fill with
*/
uint32_t *Emf::unknown_chars(size_t count){
- uint32_t *res = (uint32_t *) malloc(sizeof(uint32_t) * (count + 1));
- if(!res)throw "Inkscape fatal memory allocation error - cannot continue";
- for(uint32_t i=0; i<count; i++){ res[i] = 0xFFFD; }
- res[count]=0;
- return res;
+ uint32_t *res = (uint32_t *) malloc(sizeof(uint32_t) * (count + 1));
+ if(!res)throw "Inkscape fatal memory allocation error - cannot continue";
+ for(uint32_t i=0; i<count; i++){ res[i] = 0xFFFD; }
+ res[count]=0;
+ return res;
}
/**
- \fn store SVG for an image given the pixmap and various coordinate information
- \param d
- \param pEmr
- \param dx (double) destination x in inkscape pixels
- \param dy (double) destination y in inkscape pixels
- \param dw (double) destination width in inkscape pixels
- \param dh (double) destination height in inkscape pixels
- \param sx (int) source x in src image pixels
- \param sy (int) source y in src image pixels
- \param iUsage
- \param offBits
- \param cbBits
- \param offBmi
- \param cbBmi
+ \fn store SVG for an image given the pixmap and various coordinate information
+ \param d
+ \param pEmr
+ \param dx (double) destination x in inkscape pixels
+ \param dy (double) destination y in inkscape pixels
+ \param dw (double) destination width in inkscape pixels
+ \param dh (double) destination height in inkscape pixels
+ \param sx (int) source x in src image pixels
+ \param sy (int) source y in src image pixels
+ \param iUsage
+ \param offBits
+ \param cbBits
+ \param offBmi
+ \param cbBmi
*/
void Emf::common_image_extraction(PEMF_CALLBACK_DATA d, void *pEmr,
- double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh,
- uint32_t iUsage, uint32_t offBits, uint32_t cbBits, uint32_t offBmi, uint32_t cbBmi){
-
- SVGOStringStream tmp_image;
- int dibparams;
-
- tmp_image << " y=\"" << dy << "\"\n x=\"" << dx <<"\"\n ";
-
- // The image ID is filled in much later when tmp_image is converted
-
-
- MEMPNG mempng; // PNG in memory comes back in this
- mempng.buffer = NULL;
-
- char *rgba_px = NULL; // RGBA pixels
- char *sub_px = NULL; // RGBA pixels, subarray
- const 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(
+ double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh,
+ uint32_t iUsage, uint32_t offBits, uint32_t cbBits, uint32_t offBmi, uint32_t cbBmi){
+
+ SVGOStringStream tmp_image;
+ int dibparams;
+
+ tmp_image << " y=\"" << dy << "\"\n x=\"" << dx <<"\"\n ";
+
+ // The image ID is filled in much later when tmp_image is converted
+
+
+ MEMPNG mempng; // PNG in memory comes back in this
+ mempng.buffer = NULL;
+
+ char *rgba_px = NULL; // RGBA pixels
+ char *sub_px = NULL; // RGBA pixels, subarray
+ const 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
@@ -1486,66 +1544,67 @@ void Emf::common_image_extraction(PEMF_CALLBACK_DATA d, void *pEmr,
colortype, // DIB BitCount Enumeration
numCt, // Color table used if not 0
invert // If DIB rows are in opposite order from RGBA rows
- ) &&
- rgba_px)
- {
- sub_px = RGBA_to_RGBA(
- rgba_px, // full pixel array from DIB
- width, // Width of pixel array
- height, // Height of pixel array
- sx,sy, // starting point in pixel array
- &sw,&sh // columns/rows to extract from the pixel array (output array size)
- );
-
- if(!sub_px)sub_px=rgba_px;
- toPNG( // Get the image from the RGBA px into mempng
- &mempng,
- sw, sh, // size of the extracted pixel array
- sub_px);
- free(sub_px);
- }
- }
- gchar *base64String;
- if(dibparams == U_BI_JPEG){
- 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){
- 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){
- tmp_image << " xlink:href=\"data:image/png;base64,";
- gchar *base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
- free(mempng.buffer);
- tmp_image << base64String ;
- g_free(base64String);
- }
- else {
- tmp_image << " xlink:href=\"data:image/png;base64,";
- // insert a random 3x4 blotch otherwise
- tmp_image << "iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII=";
- }
-
- tmp_image << "\"\n height=\"" << dh << "\"\n width=\"" << dw << "\"\n";
-
- tmp_image << " transform=" << current_matrix(d, dx, dy, 1); // calculate appropriate offset
- *(d->outsvg) += "\n\t <image\n";
- *(d->outsvg) += tmp_image.str().c_str();
-
- *(d->outsvg) += "/> \n";
- *(d->path) = "";
+ ) &&
+ rgba_px
+ ){
+ sub_px = RGBA_to_RGBA(
+ rgba_px, // full pixel array from DIB
+ width, // Width of pixel array
+ height, // Height of pixel array
+ sx,sy, // starting point in pixel array
+ &sw,&sh // columns/rows to extract from the pixel array (output array size)
+ );
+
+ if(!sub_px)sub_px=rgba_px;
+ toPNG( // Get the image from the RGBA px into mempng
+ &mempng,
+ sw, sh, // size of the extracted pixel array
+ sub_px
+ );
+ free(sub_px);
+ }
+ }
+ gchar *base64String;
+ if(dibparams == U_BI_JPEG){
+ 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){
+ 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){
+ tmp_image << " xlink:href=\"data:image/png;base64,";
+ gchar *base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
+ free(mempng.buffer);
+ tmp_image << base64String ;
+ g_free(base64String);
+ }
+ else {
+ tmp_image << " xlink:href=\"data:image/png;base64,";
+ // insert a random 3x4 blotch otherwise
+ tmp_image << "iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII=";
+ }
+
+ tmp_image << "\"\n height=\"" << dh << "\"\n width=\"" << dw << "\"\n";
+
+ tmp_image << " transform=" << current_matrix(d, dx, dy, 1); // calculate appropriate offset
+ *(d->outsvg) += "\n\t <image\n";
+ *(d->outsvg) += tmp_image.str().c_str();
+
+ *(d->outsvg) += "/> \n";
+ *(d->path) = "";
}
/**
- \fn myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DATA lpData)
- \param contents binary contents of an EMF file
- \param length length in bytes of contents
- \param d Inkscape data structures returned by this call
+ \fn myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DATA lpData)
+ \param contents binary contents of an EMF file
+ \param length length in bytes of contents
+ \param d Inkscape data structures returned by this call
*/
//THis was a callback, just build it into a normal function
int Emf::myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DATA d)
@@ -1555,6 +1614,8 @@ int Emf::myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DA
int OK =1;
PU_ENHMETARECORD lpEMFR;
TCHUNK_SPECS tsp;
+ uint32_t tbkMode = U_TRANSPARENT; // holds proposed change to bkMode, if text is involved saving these to the DC must wait until the text is written
+ U_COLORREF tbkColor = U_RGB(255, 255, 255); // holds proposed change to bkColor
/* initialize the tsp for text reassembly */
tsp.string = NULL;
@@ -1572,29 +1633,34 @@ int Emf::myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DA
tsp.color.Reserved = 0; /* not used */
tsp.italics = 0;
tsp.weight = 80;
+ tsp.decoration = TXTDECOR_NONE;
tsp.condensed = 100;
tsp.co = 0;
tsp.fi_idx = -1; /* set to an invalid */
-
+
while(OK){
- if(off>=length)return(0); //normally should exit from while after EMREOF sets OK to false.
+ if(off>=length)return(0); //normally should exit from while after EMREOF sets OK to false.
lpEMFR = (PU_ENHMETARECORD)(contents + off);
// Uncomment the following to track down toxic records
//std::cout << "record type: " << lpEMFR->iType << " length: " << lpEMFR->nSize << " offset: " << off <<std::endl;
off += lpEMFR->nSize;
-
+
SVGOStringStream tmp_outsvg;
SVGOStringStream tmp_path;
SVGOStringStream tmp_str;
SVGOStringStream dbg_str;
-
- emr_mask = emr_properties(lpEMFR->iType);
+
+ emr_mask = emr_properties(lpEMFR->iType);
if(emr_mask == U_EMR_INVALID){ throw "Inkscape fatal memory allocation error - cannot continue"; }
/* Uncomment the following to track down text problems */
//std::cout << "tri->dirty:"<< d->tri->dirty << " emr_mask: " << std::hex << emr_mask << std::dec << std::endl;
- if ( (emr_mask != 0xFFFFFFFF) && (emr_mask & U_DRAW_TEXT) && d->tri->dirty){ // next record is valid type and forces pending text to be drawn immediately
+
+ // 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)){
TR_layout_analyze(d->tri);
TR_layout_2_svg(d->tri);
SVGOStringStream ts;
@@ -1602,52 +1668,78 @@ int Emf::myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DA
*(d->outsvg) += ts.str().c_str();
d->tri = trinfo_clear(d->tri);
}
+ if(d->dc[d->level].dirty){ //Apply the delayed background changes, clear the flag
+ d->dc[d->level].bkMode = tbkMode;
+ memcpy(&(d->dc[d->level].bkColor),&tbkColor, sizeof(U_COLORREF));
+
+ if(d->dc[d->level].dirty & DIRTY_TEXT){
+ // U_COLORREF and TRCOLORREF are exactly the same in memory, but the compiler needs some convincing...
+ if(tbkMode == U_TRANSPARENT){ (void) trinfo_load_bk(d->tri, BKCLR_NONE, *(TRCOLORREF *) &tbkColor); }
+ else { (void) trinfo_load_bk(d->tri, BKCLR_LINE, *(TRCOLORREF *) &tbkColor); } // Opaque
+ }
+
+ /* It is possible to have a series of EMF records that would result in
+ the following creating hash patterns which are never used. For instance, if
+ there were a series of records that changed the background color but did nothing
+ else.
+ */
+ if((d->dc[d->level].stroke_mode == DRAW_PATTERN) && (d->dc[d->level].dirty & DIRTY_STROKE)){
+ select_extpen(d, d->dc[d->level].stroke_recidx);
+ }
+
+ if((d->dc[d->level].fill_mode == DRAW_PATTERN) && (d->dc[d->level].dirty & DIRTY_FILL)){
+ select_brush(d, d->dc[d->level].fill_recidx);
+ }
+
+ d->dc[d->level].dirty = 0;
+ }
//std::cout << "BEFORE DRAW logic d->mask: " << std::hex << d->mask << " emr_mask: " << emr_mask << std::dec << std::endl;
/*
std::cout << "BEFORE DRAW"
- << " test0 " << ( d->mask & U_DRAW_VISIBLE)
- << " test1 " << ( d->mask & U_DRAW_FORCE)
- << " test2 " << (emr_mask & U_DRAW_ALTERS)
+ << " test0 " << ( d->mask & U_DRAW_VISIBLE)
+ << " test1 " << ( d->mask & U_DRAW_FORCE)
+ << " test2 " << (emr_mask & U_DRAW_ALTERS)
<< " test3 " << (emr_mask & U_DRAW_VISIBLE)
<< " test4 " << !(d->mask & U_DRAW_ONLYTO)
<< " test5 " << ((d->mask & U_DRAW_ONLYTO) && !(emr_mask & U_DRAW_ONLYTO) )
<< std::endl;
*/
- if ( (emr_mask != 0xFFFFFFFF) && // next record is valid type
- (d->mask & U_DRAW_VISIBLE) && // This record is drawable
- ( (d->mask & U_DRAW_FORCE) || // This draw is forced by STROKE/FILL/STROKEANDFILL PATH
- (emr_mask & U_DRAW_ALTERS) || // Next record would alter the drawing environment in some way
- ( (emr_mask & U_DRAW_VISIBLE) // Next record is visible...
- &&
- (
- ( !(d->mask & U_DRAW_ONLYTO) ) // Non *TO records cannot be followed by any Visible
- ||
- ((d->mask & U_DRAW_ONLYTO) && !(emr_mask & U_DRAW_ONLYTO) ) // *TO records can only be followed by other *TO records
- )
+ if(
+ (emr_mask != 0xFFFFFFFF) && // 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
+ (emr_mask & U_DRAW_ALTERS) || // Next record would alter the drawing environment in some way
+ (
+ (emr_mask & U_DRAW_VISIBLE) && // Next record is visible...
+ (
+ ( !(d->mask & U_DRAW_ONLYTO) ) || // Non *TO records cannot be followed by any Visible
+ ((d->mask & U_DRAW_ONLYTO) && !(emr_mask & U_DRAW_ONLYTO) )// *TO records can only be followed by other *TO records
+ )
)
- )
- ){
+ )
+ ){
// std::cout << "PATH DRAW at TOP" << std::endl;
- *(d->outsvg) += " <path "; // this is the ONLY place <path should be used!!!!
- if(d->drawtype){ // explicit draw type EMR record
- output_style(d, d->drawtype);
- }
- else if(d->mask & U_DRAW_CLOSED){ // implicit draw type
- output_style(d, U_EMR_STROKEANDFILLPATH);
- }
- else {
- 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) += *(d->path);
- *(d->outsvg) += " \" /> \n";
- *(d->path) = "";
- // reset the flags
- d->mask = 0;
- d->drawtype = 0;
+ *(d->outsvg) += " <path "; // this is the ONLY place <path should be used!!!!
+ if(d->drawtype){ // explicit draw type EMR record
+ output_style(d, d->drawtype);
+ }
+ else if(d->mask & U_DRAW_CLOSED){ // implicit draw type
+ output_style(d, U_EMR_STROKEANDFILLPATH);
+ }
+ else {
+ 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) += *(d->path);
+ *(d->outsvg) += " \" /> \n";
+ *(d->path) = "";
+ // reset the flags
+ d->mask = 0;
+ d->drawtype = 0;
}
// std::cout << "AFTER DRAW logic d->mask: " << std::hex << d->mask << " emr_mask: " << emr_mask << std::dec << std::endl;
@@ -1681,31 +1773,31 @@ std::cout << "BEFORE DRAW"
d->PixelsInX = pEmr->rclBounds.right - pEmr->rclBounds.left + 1;
d->PixelsInY = pEmr->rclBounds.bottom - pEmr->rclBounds.top + 1;
- /*
- calculate ratio of Inkscape dpi/EMF device dpi
- This can cause problems later due to accuracy limits in the EMF. A high resolution
- EMF might have a final D2Pscale[XY] of 0.074998, and adjusting the (integer) device size
- by 1 will still not get it exactly to 0.075. Later when the font size is calculated it
- can end up as 29.9992 or 22.4994 instead of the intended 30 or 22.5. This is handled by
- snapping font sizes to the nearest .01. The best estimate is made by using both values.
+ /*
+ calculate ratio of Inkscape dpi/EMF device dpi
+ This can cause problems later due to accuracy limits in the EMF. A high resolution
+ EMF might have a final D2Pscale[XY] of 0.074998, and adjusting the (integer) device size
+ by 1 will still not get it exactly to 0.075. Later when the font size is calculated it
+ can end up as 29.9992 or 22.4994 instead of the intended 30 or 22.5. This is handled by
+ snapping font sizes to the nearest .01. The best estimate is made by using both values.
*/
if ((pEmr->szlMillimeters.cx + pEmr->szlMillimeters.cy) && ( pEmr->szlDevice.cx + pEmr->szlDevice.cy)){
- d->E2IdirY = 1.0; // assume MM_TEXT, if not, this will be changed later
- d->D2PscaleX = d->D2PscaleY = PX_PER_MM *
- (double)(pEmr->szlMillimeters.cx + pEmr->szlMillimeters.cy)/
- (double)( pEmr->szlDevice.cx + pEmr->szlDevice.cy);
+ d->E2IdirY = 1.0; // assume MM_TEXT, if not, this will be changed later
+ d->D2PscaleX = d->D2PscaleY = PX_PER_MM *
+ (double)(pEmr->szlMillimeters.cx + pEmr->szlMillimeters.cy)/
+ (double)( pEmr->szlDevice.cx + pEmr->szlDevice.cy);
}
trinfo_load_qe(d->tri, d->D2PscaleX); /* quantization error that will affect text positions */
- /* Adobe Illustrator files set mapmode to MM_ANISOTROPIC and somehow or other this
+ /* Adobe Illustrator files set mapmode to MM_ANISOTROPIC and somehow or other this
converts the rclFrame values from MM_HIMETRIC to MM_HIENGLISH, with another factor of 3 thrown
in for good measure. Ours not to question why...
*/
if(AI_hack(pEmr)){
- d->MM100InX *= 25.4/(10.0*3.0);
- d->MM100InY *= 25.4/(10.0*3.0);
- d->D2PscaleX *= 25.4/(10.0*3.0);
- d->D2PscaleY *= 25.4/(10.0*3.0);
+ d->MM100InX *= 25.4/(10.0*3.0);
+ d->MM100InY *= 25.4/(10.0*3.0);
+ d->D2PscaleX *= 25.4/(10.0*3.0);
+ d->D2PscaleY *= 25.4/(10.0*3.0);
}
d->MMX = d->MM100InX / 100.0;
@@ -1718,7 +1810,7 @@ std::cout << "BEFORE DRAW"
d->ulCornerInX = pEmr->rclBounds.left;
d->ulCornerInY = pEmr->rclBounds.top;
d->ulCornerOutX = d->ulCornerInX * d->D2PscaleX;
- d->ulCornerOutY = d->ulCornerInY * d->E2IdirY * d->D2PscaleY;
+ d->ulCornerOutY = d->ulCornerInY * d->E2IdirY * d->D2PscaleY;
tmp_outdef <<
" width=\"" << d->MMX << "mm\"\n" <<
@@ -1733,7 +1825,7 @@ std::cout << "BEFORE DRAW"
if (pEmr->nHandles) {
d->n_obj = pEmr->nHandles;
d->emf_obj = new EMF_OBJECT[d->n_obj];
-
+
// Init the new emf_obj list elements to null, provided the
// dynamic allocation succeeded.
if ( d->emf_obj != NULL )
@@ -1825,7 +1917,7 @@ std::cout << "BEFORE DRAW"
}
tmp_path << tmp_str.str().c_str();
-
+
break;
}
case U_EMR_POLYBEZIERTO:
@@ -1926,8 +2018,8 @@ std::cout << "BEFORE DRAW"
d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].sizeWnd.cx;
d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].sizeWnd.cy;
if(d->dc[d->level].ScaleInY < 0){
- d->dc[d->level].ScaleInY *= -1.0;
- d->E2IdirY = -1.0;
+ d->dc[d->level].ScaleInY *= -1.0;
+ d->E2IdirY = -1.0;
}
}
else {
@@ -1963,14 +2055,14 @@ std::cout << "BEFORE DRAW"
if (!d->dc[d->level].sizeWnd.cx || !d->dc[d->level].sizeWnd.cy) {
d->dc[d->level].sizeWnd = d->dc[d->level].sizeView;
}
-
+
/* scales logical to EMF pixels, transfer a negative sign on Y, if any */
if (d->dc[d->level].sizeWnd.cx && d->dc[d->level].sizeWnd.cy) {
d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.cx / (double) d->dc[d->level].sizeWnd.cx;
d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.cy / (double) d->dc[d->level].sizeWnd.cy;
- if(d->dc[d->level].ScaleInY < 0){
- d->dc[d->level].ScaleInY *= -1.0;
- d->E2IdirY = -1.0;
+ if( d->dc[d->level].ScaleInY < 0){
+ d->dc[d->level].ScaleInY *= -1.0;
+ d->E2IdirY = -1.0;
}
}
else {
@@ -2004,36 +2096,49 @@ std::cout << "BEFORE DRAW"
dbg_str << "<!-- U_EMR_SETMAPMODE -->\n";
PU_EMRSETMAPMODE pEmr = (PU_EMRSETMAPMODE) lpEMFR;
switch (pEmr->iMode){
- case U_MM_TEXT:
- default:
- // Use all values from the header.
- break;
- /* For all of the following the indicated scale this will be encoded in WindowExtEx/ViewportExtex
- and show up in ScaleIn[XY]
- */
- case U_MM_LOMETRIC: // 1 LU = 0.1 mm,
- case U_MM_HIMETRIC: // 1 LU = 0.01 mm
- case U_MM_LOENGLISH: // 1 LU = 0.1 in
- case U_MM_HIENGLISH: // 1 LU = 0.01 in
- case U_MM_TWIPS: // 1 LU = 1/1440 in
- d->E2IdirY = -1.0;
- // Use d->D2Pscale[XY] values from the header.
- break;
- case U_MM_ISOTROPIC: // ScaleIn[XY] should be set elsewhere by SETVIEWPORTEXTEX and SETWINDOWEXTEX
- case U_MM_ANISOTROPIC:
- break;
- }
- break;
- }
- case U_EMR_SETBKMODE: dbg_str << "<!-- U_EMR_SETBKMODE -->\n"; break;
+ case U_MM_TEXT:
+ default:
+ // Use all values from the header.
+ break;
+ /* For all of the following the indicated scale this will be encoded in WindowExtEx/ViewportExtex
+ and show up in ScaleIn[XY]
+ */
+ case U_MM_LOMETRIC: // 1 LU = 0.1 mm,
+ case U_MM_HIMETRIC: // 1 LU = 0.01 mm
+ case U_MM_LOENGLISH: // 1 LU = 0.1 in
+ case U_MM_HIENGLISH: // 1 LU = 0.01 in
+ case U_MM_TWIPS: // 1 LU = 1/1440 in
+ d->E2IdirY = -1.0;
+ // Use d->D2Pscale[XY] values from the header.
+ break;
+ case U_MM_ISOTROPIC: // ScaleIn[XY] should be set elsewhere by SETVIEWPORTEXTEX and SETWINDOWEXTEX
+ case U_MM_ANISOTROPIC:
+ break;
+ }
+ break;
+ }
+ case U_EMR_SETBKMODE:
+ {
+ dbg_str << "<!-- U_EMR_SETBKMODE -->\n";
+ PU_EMRSETBKMODE pEmr = (PU_EMRSETBKMODE) lpEMFR;
+ tbkMode = pEmr->iMode;
+ if(tbkMode != d->dc[d->level].bkMode){
+ d->dc[d->level].dirty |= DIRTY_TEXT;
+ if(tbkMode != d->dc[d->level].bkMode){
+ if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; }
+ if(d->dc[d->level].stroke_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_STROKE; }
+ }
+ memcpy(&tbkColor,&(d->dc[d->level].bkColor),sizeof(U_COLORREF));
+ }
+ break;
+ }
case U_EMR_SETPOLYFILLMODE:
{
dbg_str << "<!-- U_EMR_SETPOLYFILLMODE -->\n";
PU_EMRSETPOLYFILLMODE pEmr = (PU_EMRSETPOLYFILLMODE) lpEMFR;
d->dc[d->level].style.fill_rule.value =
- (pEmr->iMode == U_ALTERNATE ? 0 :
- pEmr->iMode == U_WINDING ? 1 : 0);
+ (pEmr->iMode == U_ALTERNATE ? 0 : (pEmr->iMode == U_WINDING ? 1 : 0));
break;
}
case U_EMR_SETROP2:
@@ -2067,6 +2172,11 @@ std::cout << "BEFORE DRAW"
PU_EMRSETTEXTCOLOR pEmr = (PU_EMRSETTEXTCOLOR) lpEMFR;
d->dc[d->level].textColor = pEmr->crColor;
+ if(tbkMode != d->dc[d->level].bkMode){
+ if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; }
+ if(d->dc[d->level].stroke_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_STROKE; }
+ }
+ // not text_dirty, because multicolored complex text is supported in libTERE
break;
}
case U_EMR_SETBKCOLOR:
@@ -2074,7 +2184,13 @@ std::cout << "BEFORE DRAW"
dbg_str << "<!-- U_EMR_SETBKCOLOR -->\n";
PU_EMRSETBKCOLOR pEmr = (PU_EMRSETBKCOLOR) lpEMFR;
- d->dc[d->level].bkColor = pEmr->crColor;
+ tbkColor = pEmr->crColor;
+ if(memcmp(&tbkColor, &(d->dc[d->level].bkColor), sizeof(U_COLORREF))){
+ d->dc[d->level].dirty |= DIRTY_TEXT;
+ if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; }
+ if(d->dc[d->level].stroke_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_STROKE; }
+ tbkMode = d->dc[d->level].bkMode;
+ }
break;
}
case U_EMR_OFFSETCLIPRGN: dbg_str << "<!-- U_EMR_OFFSETCLIPRGN -->\n"; break;
@@ -2141,7 +2257,7 @@ std::cout << "BEFORE DRAW"
case U_EMR_RESTOREDC:
{
dbg_str << "<!-- U_EMR_RESTOREDC -->\n";
-
+
PU_EMRRESTOREDC pEmr = (PU_EMRRESTOREDC) lpEMFR;
int old_level = d->level;
if (pEmr->iRelative >= 0) {
@@ -2157,8 +2273,8 @@ std::cout << "BEFORE DRAW"
delete[] d->dc[old_level].style.stroke_dash.dash;
}
if(d->dc[old_level].font_name){
- free(d->dc[old_level].font_name); // else memory leak
- d->dc[old_level].font_name = NULL;
+ free(d->dc[old_level].font_name); // else memory leak
+ d->dc[old_level].font_name = NULL;
}
old_level--;
}
@@ -2227,7 +2343,7 @@ std::cout << "BEFORE DRAW"
d->dc[d->level].worldTransform.eM22 = c22;;
d->dc[d->level].worldTransform.eDx = c31;
d->dc[d->level].worldTransform.eDy = c32;
-
+
break;
}
case U_MWT_RIGHTMULTIPLY:
@@ -2382,6 +2498,7 @@ std::cout << "BEFORE DRAW"
}
case U_EMR_DELETEOBJECT:
dbg_str << "<!-- U_EMR_DELETEOBJECT -->\n";
+ // Objects here are not deleted until the draw completes, new ones may write over an existing one.
break;
case U_EMR_ANGLEARC:
dbg_str << "<!-- U_EMR_ANGLEARC -->\n";
@@ -2406,7 +2523,7 @@ std::cout << "BEFORE DRAW"
d->mask |= emr_mask;
- *(d->outsvg) += " <ellipse ";
+ *(d->outsvg) += " <ellipse ";
output_style(d, lpEMFR->iType); //
*(d->outsvg) += "\n\t";
*(d->outsvg) += tmp_ellipse.str().c_str();
@@ -2444,40 +2561,40 @@ std::cout << "BEFORE DRAW"
double f1 = 1.0 - f;
double cnx = corner.cx/2;
double cny = corner.cy/2;
-
+
SVGOStringStream tmp_rectangle;
tmp_rectangle << "\n"
- << " M "
+ << " M "
<< pix_to_xy(d, rc.left , rc.top + cny )
<< "\n";
- tmp_rectangle << " C "
+ tmp_rectangle << " C "
<< pix_to_xy(d, rc.left , rc.top + cny*f1 )
- << " "
+ << " "
<< pix_to_xy(d, rc.left + cnx*f1 , rc.top )
- << " "
+ << " "
<< pix_to_xy(d, rc.left + cnx , rc.top )
<< "\n";
- tmp_rectangle << " L "
+ tmp_rectangle << " L "
<< pix_to_xy(d, rc.right - cnx , rc.top )
<< "\n";
- tmp_rectangle << " C "
+ tmp_rectangle << " C "
<< pix_to_xy(d, rc.right - cnx*f1 , rc.top )
- << " "
+ << " "
<< pix_to_xy(d, rc.right , rc.top + cny*f1 )
- << " "
+ << " "
<< pix_to_xy(d, rc.right , rc.top + cny )
<< "\n";
tmp_rectangle << " L "
<< pix_to_xy(d, rc.right , rc.bottom - cny )
<< "\n";
- tmp_rectangle << " C "
+ tmp_rectangle << " C "
<< pix_to_xy(d, rc.right , rc.bottom - cny*f1 )
<< " "
<< pix_to_xy(d, rc.right - cnx*f1 , rc.bottom )
<< " "
<< pix_to_xy(d, rc.right - cnx , rc.bottom )
<< "\n";
- tmp_rectangle << " L "
+ tmp_rectangle << " L "
<< pix_to_xy(d, rc.left + cnx , rc.bottom )
<< "\n";
tmp_rectangle << " C "
@@ -2503,17 +2620,17 @@ std::cout << "BEFORE DRAW"
int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1);
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 << " ";
- tmp_path << 180.0 * current_rotation(d)/M_PI;
- tmp_path << " ";
- tmp_path << " " << f1 << "," << f2 << " ";
- tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
- d->mask |= emr_mask;
+ tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y);
+ tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ;
+ tmp_path << " ";
+ tmp_path << 180.0 * current_rotation(d)/M_PI;
+ tmp_path << " ";
+ tmp_path << " " << f1 << "," << f2 << " ";
+ tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
+ d->mask |= emr_mask;
}
else {
- dbg_str << "<!-- ARC record is invalid -->\n";
+ dbg_str << "<!-- ARC record is invalid -->\n";
}
break;
}
@@ -2524,18 +2641,18 @@ std::cout << "BEFORE DRAW"
int f1;
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 << " ";
- tmp_path << 180.0 * current_rotation(d)/M_PI;
- tmp_path << " ";
- tmp_path << " " << f1 << "," << f2 << " ";
- tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
- tmp_path << " z ";
- d->mask |= emr_mask;
+ tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y);
+ tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ;
+ tmp_path << " ";
+ tmp_path << 180.0 * current_rotation(d)/M_PI;
+ tmp_path << " ";
+ tmp_path << " " << f1 << "," << f2 << " ";
+ tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
+ tmp_path << " z ";
+ d->mask |= emr_mask;
}
else {
- dbg_str << "<!-- CHORD record is invalid -->\n";
+ dbg_str << "<!-- CHORD record is invalid -->\n";
}
break;
}
@@ -2546,19 +2663,19 @@ std::cout << "BEFORE DRAW"
int f1;
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, center.x, center.y);
- tmp_path << "\n\tL " << pix_to_xy(d, start.x, start.y);
- tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ;
- tmp_path << " ";
- tmp_path << 180.0 * current_rotation(d)/M_PI;
- tmp_path << " ";
- tmp_path << " " << f1 << "," << f2 << " ";
- tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
- tmp_path << " z ";
- d->mask |= emr_mask;
+ tmp_path << "\n\tM " << pix_to_xy(d, center.x, center.y);
+ tmp_path << "\n\tL " << pix_to_xy(d, start.x, start.y);
+ tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ;
+ tmp_path << " ";
+ tmp_path << 180.0 * current_rotation(d)/M_PI;
+ tmp_path << " ";
+ tmp_path << " " << f1 << "," << f2 << " ";
+ tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
+ tmp_path << " z ";
+ d->mask |= emr_mask;
}
else {
- dbg_str << "<!-- PIE record is invalid -->\n";
+ dbg_str << "<!-- PIE record is invalid -->\n";
}
break;
}
@@ -2587,20 +2704,20 @@ std::cout << "BEFORE DRAW"
int f1;
int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1);
if(!emr_arc_points( lpEMFR, &f1, f2, &center, &start, &end, &size)){
- // draw a line from current position to start
- tmp_path << "\n\tL " << pix_to_xy(d, start.x, start.y);
- tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y);
- tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ;
- tmp_path << " ";
- tmp_path << 180.0 * current_rotation(d)/M_PI;
- tmp_path << " ";
- tmp_path << " " << f1 << "," << f2 << " ";
- tmp_path << pix_to_xy(d, end.x, end.y)<< " ";
-
- d->mask |= emr_mask;
+ // draw a line from current position to start
+ tmp_path << "\n\tL " << pix_to_xy(d, start.x, start.y);
+ tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y);
+ tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ;
+ tmp_path << " ";
+ tmp_path << 180.0 * current_rotation(d)/M_PI;
+ tmp_path << " ";
+ tmp_path << " " << f1 << "," << f2 << " ";
+ tmp_path << pix_to_xy(d, end.x, end.y)<< " ";
+
+ d->mask |= emr_mask;
}
else {
- dbg_str << "<!-- ARCTO record is invalid -->\n";
+ dbg_str << "<!-- ARCTO record is invalid -->\n";
}
break;
}
@@ -2653,12 +2770,12 @@ std::cout << "BEFORE DRAW"
{
dbg_str << "<!-- U_EMR_FILLPATH -->\n";
if(d->mask & U_DRAW_PATH){ // Operation only effects declared paths
- if(!(d->mask & U_DRAW_CLOSED)){ // Close a path not explicitly closed by an EMRCLOSEFIGURE, otherwise fill makes no sense
- tmp_path << "\n\tz";
- d->mask |= U_DRAW_CLOSED;
- }
- d->mask |= emr_mask;
- d->drawtype = U_EMR_FILLPATH;
+ if(!(d->mask & U_DRAW_CLOSED)){ // Close a path not explicitly closed by an EMRCLOSEFIGURE, otherwise fill makes no sense
+ tmp_path << "\n\tz";
+ d->mask |= U_DRAW_CLOSED;
+ }
+ d->mask |= emr_mask;
+ d->drawtype = U_EMR_FILLPATH;
}
break;
}
@@ -2666,12 +2783,12 @@ std::cout << "BEFORE DRAW"
{
dbg_str << "<!-- U_EMR_STROKEANDFILLPATH -->\n";
if(d->mask & U_DRAW_PATH){ // Operation only effects declared paths
- if(!(d->mask & U_DRAW_CLOSED)){ // Close a path not explicitly closed by an EMRCLOSEFIGURE, otherwise fill makes no sense
- tmp_path << "\n\tz";
- d->mask |= U_DRAW_CLOSED;
- }
- d->mask |= emr_mask;
- d->drawtype = U_EMR_STROKEANDFILLPATH;
+ if(!(d->mask & U_DRAW_CLOSED)){ // Close a path not explicitly closed by an EMRCLOSEFIGURE, otherwise fill makes no sense
+ tmp_path << "\n\tz";
+ d->mask |= U_DRAW_CLOSED;
+ }
+ d->mask |= emr_mask;
+ d->drawtype = U_EMR_STROKEANDFILLPATH;
}
break;
}
@@ -2679,8 +2796,8 @@ std::cout << "BEFORE DRAW"
{
dbg_str << "<!-- U_EMR_STROKEPATH -->\n";
if(d->mask & U_DRAW_PATH){ // Operation only effects declared paths
- d->mask |= emr_mask;
- d->drawtype = U_EMR_STROKEPATH;
+ d->mask |= emr_mask;
+ d->drawtype = U_EMR_STROKEPATH;
}
break;
}
@@ -2698,7 +2815,7 @@ std::cout << "BEFORE DRAW"
case U_EMR_COMMENT:
{
dbg_str << "<!-- U_EMR_COMMENT -->\n";
-
+
PU_EMRCOMMENT pEmr = (PU_EMRCOMMENT) lpEMFR;
char *szTxt = (char *) pEmr->Data;
@@ -2713,13 +2830,13 @@ std::cout << "BEFORE DRAW"
}
if (0 && strlen(tmp_str.str().c_str())) {
- tmp_outsvg << " <!-- \"";
+ tmp_outsvg << " <!-- \"";
tmp_outsvg << tmp_str.str().c_str();
tmp_outsvg << "\" -->\n";
}
-
+
break;
- }
+ }
case U_EMR_FILLRGN: dbg_str << "<!-- U_EMR_FILLRGN -->\n"; break;
case U_EMR_FRAMERGN: dbg_str << "<!-- U_EMR_FRAMERGN -->\n"; break;
case U_EMR_INVERTRGN: dbg_str << "<!-- U_EMR_INVERTRGN -->\n"; break;
@@ -2738,8 +2855,8 @@ std::cout << "BEFORE DRAW"
dbg_str << "<!-- U_EMR_BITBLT -->\n";
PU_EMRBITBLT pEmr = (PU_EMRBITBLT) lpEMFR;
- // Treat all nonImage bitblts as a rectangular write. Definitely not correct, but at
- // least it leaves objects where the operations should have been.
+ // Treat all nonImage bitblts as a rectangular write. Definitely not correct, but at
+ // least it leaves objects where the operations should have been.
if (!pEmr->cbBmiSrc) {
// should be an application of a DIBPATTERNBRUSHPT, use a solid color instead
@@ -2768,12 +2885,12 @@ std::cout << "BEFORE DRAW"
//source position within the bitmap, in pixels
int sx = pEmr->Src.x + pEmr->xformSrc.eDx;
int sy = pEmr->Src.y + pEmr->xformSrc.eDy;
- int sw = 0; // extract all of the image
+ int sw = 0; // extract all of the image
int sh = 0;
if(sx<0)sx=0;
if(sy<0)sy=0;
common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh,
- pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc);
+ pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc);
}
break;
}
@@ -2790,10 +2907,10 @@ std::cout << "BEFORE DRAW"
//source position within the bitmap, in pixels
int sx = pEmr->Src.x + pEmr->xformSrc.eDx;
int sy = pEmr->Src.y + pEmr->xformSrc.eDy;
- int sw = pEmr->cSrc.x; // extract the specified amount of the image
+ int sw = pEmr->cSrc.x; // extract the specified amount of the image
int sh = pEmr->cSrc.y;
common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh,
- pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc);
+ pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc);
}
break;
}
@@ -2812,7 +2929,7 @@ std::cout << "BEFORE DRAW"
int sw = 0; // extract all of the image
int sh = 0;
common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh,
- pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc);
+ pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc);
}
break;
}
@@ -2833,10 +2950,10 @@ std::cout << "BEFORE DRAW"
double dh = pix_to_abs_size( d, pEmr->cDest.y);
int sx = pEmr->Src.x; //source position within the bitmap, in pixels
int sy = pEmr->Src.y;
- int sw = pEmr->cSrc.x; // extract the specified amount of the image
+ int sw = pEmr->cSrc.x; // extract the specified amount of the image
int sh = pEmr->cSrc.y;
common_image_extraction(d,pEmr,dx,dy,dw,dh,sx,sy,sw,sh,
- pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc);
+ pEmr->iUsageSrc, pEmr->offBitsSrc, pEmr->cbBitsSrc, pEmr->offBmiSrc, pEmr->cbBmiSrc);
dbg_str << "<!-- U_EMR_STRETCHDIBITS -->\n";
break;
@@ -2872,7 +2989,7 @@ std::cout << "BEFORE DRAW"
y1 = pEmr->emrtext.ptlReference.y;
cChars = 0;
}
-
+
if (d->dc[d->level].textAlign & U_TA_UPDATECP) {
x1 = d->dc[d->level].cur.x;
y1 = d->dc[d->level].cur.y;
@@ -2885,35 +3002,35 @@ std::cout << "BEFORE DRAW"
uint32_t *dup_wt = NULL;
- if( lpEMFR->iType==U_EMR_EXTTEXTOUTA){
- /* These should be JUST ASCII, but they might not be...
- If it holds Utf-8 or plain ASCII the first call will succeed.
- If not, assume that it holds Latin1.
- If that fails then someting is really screwed up!
- */
- dup_wt = U_Utf8ToUtf32le((char *) pEmr + pEmr->emrtext.offString, pEmr->emrtext.nChars, NULL);
- if(!dup_wt)dup_wt = U_Latin1ToUtf32le((char *) pEmr + pEmr->emrtext.offString, pEmr->emrtext.nChars, NULL);
- if(!dup_wt)dup_wt = unknown_chars(pEmr->emrtext.nChars);
+ if( lpEMFR->iType==U_EMR_EXTTEXTOUTA){
+ /* These should be JUST ASCII, but they might not be...
+ If it holds Utf-8 or plain ASCII the first call will succeed.
+ If not, assume that it holds Latin1.
+ If that fails then someting is really screwed up!
+ */
+ dup_wt = U_Utf8ToUtf32le((char *) pEmr + pEmr->emrtext.offString, pEmr->emrtext.nChars, NULL);
+ if(!dup_wt)dup_wt = U_Latin1ToUtf32le((char *) pEmr + pEmr->emrtext.offString, pEmr->emrtext.nChars, NULL);
+ if(!dup_wt)dup_wt = unknown_chars(pEmr->emrtext.nChars);
}
else if( lpEMFR->iType==U_EMR_EXTTEXTOUTW){
- dup_wt = U_Utf16leToUtf32le((uint16_t *)((char *) pEmr + pEmr->emrtext.offString), pEmr->emrtext.nChars, NULL);
- if(!dup_wt)dup_wt = unknown_chars(pEmr->emrtext.nChars);
+ dup_wt = U_Utf16leToUtf32le((uint16_t *)((char *) pEmr + pEmr->emrtext.offString), pEmr->emrtext.nChars, NULL);
+ if(!dup_wt)dup_wt = unknown_chars(pEmr->emrtext.nChars);
}
else { // U_EMR_SMALLTEXTOUT
- if(pEmrS->fuOptions & U_ETO_SMALL_CHARS){
- dup_wt = U_Utf8ToUtf32le((char *) pEmrS + roff, cChars, NULL);
- }
- else {
- dup_wt = U_Utf16leToUtf32le((uint16_t *)((char *) pEmrS + roff), cChars, NULL);
- }
- if(!dup_wt)dup_wt = unknown_chars(cChars);
+ if(pEmrS->fuOptions & U_ETO_SMALL_CHARS){
+ dup_wt = U_Utf8ToUtf32le((char *) pEmrS + roff, cChars, NULL);
+ }
+ else {
+ dup_wt = U_Utf16leToUtf32le((uint16_t *)((char *) pEmrS + roff), cChars, NULL);
+ }
+ if(!dup_wt)dup_wt = unknown_chars(cChars);
}
msdepua(dup_wt); //convert everything in Microsoft's private use area. For Symbol, Wingdings, Dingbats
if(NonToUnicode(dup_wt, d->dc[d->level].font_name)){
- free(d->dc[d->level].font_name);
- d->dc[d->level].font_name = strdup("Times New Roman");
+ free(d->dc[d->level].font_name);
+ d->dc[d->level].font_name = strdup("Times New Roman");
}
char *ansi_text;
@@ -2921,8 +3038,8 @@ std::cout << "BEFORE DRAW"
free(dup_wt);
// Empty string or starts with an invalid escape/control sequence, which is bogus text. Throw it out before g_markup_escape_text can make things worse
if(*((uint8_t *)ansi_text) <= 0x1F){
- free(ansi_text);
- ansi_text=NULL;
+ free(ansi_text);
+ ansi_text=NULL;
}
if (ansi_text) {
@@ -2947,29 +3064,29 @@ std::cout << "BEFORE DRAW"
tsp.italics = FC_SLANT_ROMAN; break;
}
switch(d->dc[d->level].style.font_weight.value){
- case SP_CSS_FONT_WEIGHT_100: tsp.weight = FC_WEIGHT_THIN ; break;
- case SP_CSS_FONT_WEIGHT_200: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break;
- case SP_CSS_FONT_WEIGHT_300: tsp.weight = FC_WEIGHT_LIGHT ; break;
- case SP_CSS_FONT_WEIGHT_400: tsp.weight = FC_WEIGHT_NORMAL ; break;
- case SP_CSS_FONT_WEIGHT_500: tsp.weight = FC_WEIGHT_MEDIUM ; break;
- case SP_CSS_FONT_WEIGHT_600: tsp.weight = FC_WEIGHT_SEMIBOLD ; break;
- case SP_CSS_FONT_WEIGHT_700: tsp.weight = FC_WEIGHT_BOLD ; break;
- case SP_CSS_FONT_WEIGHT_800: tsp.weight = FC_WEIGHT_EXTRABOLD ; break;
- case SP_CSS_FONT_WEIGHT_900: tsp.weight = FC_WEIGHT_HEAVY ; break;
- case SP_CSS_FONT_WEIGHT_NORMAL: tsp.weight = FC_WEIGHT_NORMAL ; break;
- case SP_CSS_FONT_WEIGHT_BOLD: tsp.weight = FC_WEIGHT_BOLD ; break;
- case SP_CSS_FONT_WEIGHT_LIGHTER: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break;
- case SP_CSS_FONT_WEIGHT_BOLDER: tsp.weight = FC_WEIGHT_EXTRABOLD ; break;
- default: tsp.weight = FC_WEIGHT_NORMAL ; break;
+ case SP_CSS_FONT_WEIGHT_100: tsp.weight = FC_WEIGHT_THIN ; break;
+ case SP_CSS_FONT_WEIGHT_200: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break;
+ case SP_CSS_FONT_WEIGHT_300: tsp.weight = FC_WEIGHT_LIGHT ; break;
+ case SP_CSS_FONT_WEIGHT_400: tsp.weight = FC_WEIGHT_NORMAL ; break;
+ case SP_CSS_FONT_WEIGHT_500: tsp.weight = FC_WEIGHT_MEDIUM ; break;
+ case SP_CSS_FONT_WEIGHT_600: tsp.weight = FC_WEIGHT_SEMIBOLD ; break;
+ case SP_CSS_FONT_WEIGHT_700: tsp.weight = FC_WEIGHT_BOLD ; break;
+ case SP_CSS_FONT_WEIGHT_800: tsp.weight = FC_WEIGHT_EXTRABOLD ; break;
+ case SP_CSS_FONT_WEIGHT_900: tsp.weight = FC_WEIGHT_HEAVY ; break;
+ case SP_CSS_FONT_WEIGHT_NORMAL: tsp.weight = FC_WEIGHT_NORMAL ; break;
+ case SP_CSS_FONT_WEIGHT_BOLD: tsp.weight = FC_WEIGHT_BOLD ; break;
+ case SP_CSS_FONT_WEIGHT_LIGHTER: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break;
+ case SP_CSS_FONT_WEIGHT_BOLDER: tsp.weight = FC_WEIGHT_EXTRABOLD ; break;
+ default: tsp.weight = FC_WEIGHT_NORMAL ; break;
}
// EMF textalignment is a bit strange: 0x6 is center, 0x2 is right, 0x0 is left, the value 0x4 is also drawn left
- tsp.taln = ((d->dc[d->level].textAlign & U_TA_CENTER) == U_TA_CENTER) ? ALICENTER :
- (((d->dc[d->level].textAlign & U_TA_CENTER) == U_TA_LEFT) ? ALILEFT :
- ALIRIGHT);
- tsp.taln |= ((d->dc[d->level].textAlign & U_TA_BASEBIT) ? ALIBASE :
- ((d->dc[d->level].textAlign & U_TA_BOTTOM) ? ALIBOT :
- ALITOP));
+ tsp.taln = ((d->dc[d->level].textAlign & U_TA_CENTER) == U_TA_CENTER) ? ALICENTER :
+ (((d->dc[d->level].textAlign & U_TA_CENTER) == U_TA_LEFT) ? ALILEFT :
+ ALIRIGHT);
+ tsp.taln |= ((d->dc[d->level].textAlign & U_TA_BASEBIT) ? ALIBASE :
+ ((d->dc[d->level].textAlign & U_TA_BOTTOM) ? ALIBOT :
+ ALITOP));
tsp.ldir = (d->dc[d->level].textAlign & U_TA_RTLREADING ? LDIR_RL : LDIR_LR); // language direction
tsp.condensed = FC_WIDTH_NORMAL; // Not implemented well in libTERE (yet)
tsp.ori = d->dc[d->level].style.baseline_shift.value; // For now orientation is always the same as escapement
@@ -2983,19 +3100,19 @@ std::cout << "BEFORE DRAW"
else { tsp.co=0; }
int status = trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ori is actually escapement
- if(status==-1){ // change of escapement, emit what we have and reset
- TR_layout_analyze(d->tri);
- TR_layout_2_svg(d->tri);
- ts << d->tri->out;
- *(d->outsvg) += ts.str().c_str();
- d->tri = trinfo_clear(d->tri);
- (void) trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ignore return status, it must work
+ if(status==-1){ // change of escapement, emit what we have and reset
+ TR_layout_analyze(d->tri);
+ TR_layout_2_svg(d->tri);
+ ts << d->tri->out;
+ *(d->outsvg) += ts.str().c_str();
+ d->tri = trinfo_clear(d->tri);
+ (void) trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ignore return status, it must work
}
-
+
g_free(escaped_text);
free(ansi_text);
}
-
+
break;
}
case U_EMR_POLYBEZIER16:
@@ -3035,7 +3152,7 @@ std::cout << "BEFORE DRAW"
unsigned int first = 0;
d->mask |= emr_mask;
-
+
// skip the first point?
tmp_poly << "\n\tM " << pix_to_xy( d, apts[first].x, apts[first].y ) << " ";
@@ -3198,11 +3315,11 @@ std::cout << "BEFORE DRAW"
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.
+ /* 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_SETLINKEDUFIS: dbg_str << "<!-- U_EMR_SETLINKEDUFIS -->\n"; break;
case U_EMR_SETTEXTJUSTIFICATION: dbg_str << "<!-- U_EMR_SETTEXTJUSTIFICATION -->\n"; break;
@@ -3219,7 +3336,7 @@ 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;
@@ -3251,10 +3368,10 @@ typedef struct
#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]); }
- free(name.strings);
- }
+ if(name.count){
+ for(int i=0; i< name.count; i++){ free(name.strings[i]); }
+ free(name.strings);
+ }
}
SPDocument *
@@ -3266,9 +3383,9 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
memset(&d, 0, sizeof(EMF_CALLBACK_DATA));
for(int i = 0; i < EMF_MAX_DC+1; i++){ // be sure all values and pointers are empty to start with
- memset(&(d.dc[i]),0,sizeof(EMF_DEVICE_CONTEXT));
+ memset(&(d.dc[i]),0,sizeof(EMF_DEVICE_CONTEXT));
}
-
+
d.dc[0].worldTransform.eM11 = 1.0;
d.dc[0].worldTransform.eM12 = 0.0;
d.dc[0].worldTransform.eM21 = 0.0;
@@ -3278,7 +3395,9 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
d.dc[0].font_name = strdup("Arial"); // Default font, EMF spec says device can pick whatever it wants
d.dc[0].textColor = U_RGB(0, 0, 0); // default foreground color (black)
d.dc[0].bkColor = U_RGB(255, 255, 255); // default background color (white)
-
+ d.dc[0].bkMode = U_TRANSPARENT;
+ d.dc[0].dirty = 0;
+
if (uri == NULL) {
return NULL;
}
@@ -3302,24 +3421,34 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
d.images.count = 0;
d.images.strings = NULL;
+ // set up the size default for patterns in defs. This might not be referenced if there are no patterns defined in the drawing.
+
+ *(d.defs) += "\n";
+ *(d.defs) += " <pattern id=\"EMFhbasepattern\" \n";
+ *(d.defs) += " patternUnits=\"userSpaceOnUse\"\n";
+ *(d.defs) += " width=\"6\" \n";
+ *(d.defs) += " height=\"6\" \n";
+ *(d.defs) += " x=\"0\" \n";
+ *(d.defs) += " y=\"0\"> \n";
+ *(d.defs) += " </pattern> \n";
+
+
size_t length;
char *contents;
- if(emf_readdata(uri, &contents, &length))return(NULL);
+ if(emf_readdata(uri, &contents, &length))return(NULL);
d.pDesc = NULL;
-
+
// set up the text reassembly system
if(!(d.tri = trinfo_init(NULL)))return(NULL);
(void) trinfo_load_ft_opts(d.tri, 1,
- FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP,
+ FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP,
FT_KERNING_UNSCALED);
-
+
(void) myEnhMetaFileProc(contents,length, &d);
free(contents);
-
- if (d.pDesc)
- free( d.pDesc );
+ if (d.pDesc){ free( d.pDesc ); }
// std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl;
@@ -3331,17 +3460,17 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
delete d.defs;
free_emf_strings(d.hatches);
free_emf_strings(d.images);
-
+
if (d.emf_obj) {
int i;
for (i=0; i<d.n_obj; i++)
delete_object(&d, i);
delete[] d.emf_obj;
}
-
+
if (d.dc[0].style.stroke_dash.dash)
delete[] d.dc[0].style.stroke_dash.dash;
-
+
for(int i=0; i<=d.level;i++){
if(d.dc[i].font_name)free(d.dc[i].font_name);
}
diff --git a/src/extension/internal/emf-inout.h b/src/extension/internal/emf-inout.h
index db253b375..7d56339fe 100644
--- a/src/extension/internal/emf-inout.h
+++ b/src/extension/internal/emf-inout.h
@@ -22,6 +22,11 @@ namespace Inkscape {
namespace Extension {
namespace Internal {
+#define DIRTY_NONE 0x00
+#define DIRTY_TEXT 0x01
+#define DIRTY_FILL 0x02
+#define DIRTY_STROKE 0x04
+
typedef struct {
int type;
int level;
@@ -37,24 +42,27 @@ typedef struct {
typedef struct emf_device_context {
struct SPStyle style;
char *font_name;
- bool stroke_set;
- int stroke_mode; // enumeration from drawmode, not used if fill_set is not True
- int stroke_idx; // used with DRAW_PATTERN and DRAW_IMAGE to return the appropriate fill
- bool fill_set;
- int fill_mode; // enumeration from drawmode, not used if fill_set is not True
- int fill_idx; // used with DRAW_PATTERN and DRAW_IMAGE to return the appropriate fill
-
- U_SIZEL sizeWnd;
- U_SIZEL sizeView;
- U_POINTL winorg;
- U_POINTL vieworg;
- double ScaleInX, ScaleInY;
- double ScaleOutX, ScaleOutY;
- U_COLORREF textColor;
- U_COLORREF bkColor;
- uint32_t textAlign;
- U_XFORM worldTransform;
- U_POINTL cur;
+ bool stroke_set;
+ int stroke_mode; // enumeration from drawmode, not used if fill_set is not True
+ int stroke_idx; // used with DRAW_PATTERN and DRAW_IMAGE to return the appropriate fill
+ int stroke_recidx;// record used to regenerate hatch when it needs to be redone due to bkmode, textmode, etc. change
+ bool fill_set;
+ int fill_mode; // enumeration from drawmode, not used if fill_set is not True
+ int fill_idx; // used with DRAW_PATTERN and DRAW_IMAGE to return the appropriate fill
+ int fill_recidx; // record used to regenerate hatch when it needs to be redone due to bkmode, textmode, etc. change
+ int dirty; // holds the dirty bits for text, stroke, fill
+ U_SIZEL sizeWnd;
+ U_SIZEL sizeView;
+ U_POINTL winorg;
+ U_POINTL vieworg;
+ double ScaleInX, ScaleInY;
+ double ScaleOutX, ScaleOutY;
+ uint16_t bkMode;
+ U_COLORREF bkColor;
+ U_COLORREF textColor;
+ uint32_t textAlign;
+ U_XFORM worldTransform;
+ U_POINTL cur;
} EMF_DEVICE_CONTEXT, *PEMF_DEVICE_CONTEXT;
#define EMF_MAX_DC 128
@@ -96,18 +104,18 @@ typedef struct {
EMF_DEVICE_CONTEXT dc[EMF_MAX_DC+1]; // FIXME: This should be dynamic..
int level;
- double E2IdirY; // EMF Y direction relative to Inkscape Y direction. Will be negative for MM_LOMETRIC etc.
- double D2PscaleX,D2PscaleY; // EMF device to Inkscape Page scale.
- float MM100InX, MM100InY; // size of the drawing in hundredths of a millimeter
- float PixelsInX, PixelsInY; // size of the drawing, in EMF device pixels
- float PixelsOutX, PixelsOutY;// size of the drawing, in Inkscape pixels
+ double E2IdirY; // EMF Y direction relative to Inkscape Y direction. Will be negative for MM_LOMETRIC etc.
+ double D2PscaleX,D2PscaleY; // EMF device to Inkscape Page scale.
+ float MM100InX, MM100InY; // size of the drawing in hundredths of a millimeter
+ float PixelsInX, PixelsInY; // size of the drawing, in EMF device pixels
+ float PixelsOutX, PixelsOutY; // size of the drawing, in Inkscape pixels
double ulCornerInX,ulCornerInY; // Upper left corner, from header rclBounds, in logical units
double ulCornerOutX,ulCornerOutY; // Upper left corner, in Inkscape pixels
- uint32_t mask; // Draw properties
- int arcdir; //U_AD_COUNTERCLOCKWISE 1 or U_AD_CLOCKWISE 2
+ uint32_t mask; // Draw properties
+ int arcdir; //U_AD_COUNTERCLOCKWISE 1 or U_AD_CLOCKWISE 2
- uint32_t dwRop2; // Binary raster operation, 0 if none (use brush/pen unmolested)
- uint32_t dwRop3; // Ternary raster operation, 0 if none (use brush/pen unmolested)
+ uint32_t dwRop2; // Binary raster operation, 0 if none (use brush/pen unmolested)
+ uint32_t dwRop3; // Ternary raster operation, 0 if none (use brush/pen unmolested)
float MMX;
float MMY;
@@ -147,9 +155,9 @@ 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, char *px);
+ 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, gchar const *filename);
+ 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);
static double current_rotation(PEMF_CALLBACK_DATA d);
diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp
index 30571fc25..3296a1be6 100644
--- a/src/extension/internal/emf-print.cpp
+++ b/src/extension/internal/emf-print.cpp
@@ -81,149 +81,135 @@ namespace Internal {
enum drawmode {DRAW_PAINT, DRAW_PATTERN, DRAW_IMAGE, DRAW_LINEAR_GRADIENT, DRAW_RADIAL_GRADIENT};
struct FFNEXUS {
- char *fontname; //Font name
- FFNEXUS *next; //link to next nexus, NULL if this is the last
- double f1; //Vertical (rotating) offset factor (* font height)
- double f2; //Vertical (nonrotating) offset factor (* font height)
- double f3; //Horizontal (nonrotating) offset factor (* font height)
- };
+ char *fontname; //Font name
+ FFNEXUS *next; //link to next nexus, NULL if this is the last
+ double f1; //Vertical (rotating) offset factor (* font height)
+ double f2; //Vertical (nonrotating) offset factor (* font height)
+ double f3; //Horizontal (nonrotating) offset factor (* font height)
+};
struct GRADVALUES{
- Geom::Point p1; // center or start
- Geom::Point p2; // xhandle or end
- Geom::Point p3; // yhandle or unused
- double r; // radius or unused
- void *grad; // to access the stops information
- int mode; // DRAW_LINEAR_GRADIENT or DRAW_RADIAL_GRADIENT, if GRADVALUES is valid, else any value
- U_COLORREF bgc; // document background color, this is as good a place as any to keep it
- float rgb[3]; // also background color, but as 0-1 float.
- };
+ Geom::Point p1; // center or start
+ Geom::Point p2; // xhandle or end
+ Geom::Point p3; // yhandle or unused
+ double r; // radius or unused
+ void *grad; // to access the stops information
+ int mode; // DRAW_LINEAR_GRADIENT or DRAW_RADIAL_GRADIENT, if GRADVALUES is valid, else any value
+ U_COLORREF bgc; // document background color, this is as good a place as any to keep it
+ float rgb[3]; // also background color, but as 0-1 float.
+};
/* globals */
-static double PX2WORLD = 20.0f;
-static U_XFORM worldTransform;
-static bool FixPPTCharPos, FixPPTDashLine, FixPPTGrad2Polys, FixPPTPatternAsHatch, FixImageRot;
-static FFNEXUS *emf_short_fflist = NULL; //only those fonts so far encountered. This is SHARED with wmf-print.cpp
-static FFNEXUS *emf_long_fflist = NULL; //all the fonts described in ...\share\extensions\fontfix.conf
-static EMFTRACK *et = NULL;
-static EMFHANDLES *eht = NULL;
-static GRADVALUES gv;
+static double PX2WORLD = 20.0f;
+static U_XFORM worldTransform;
+static bool FixPPTCharPos, FixPPTDashLine, FixPPTGrad2Polys, FixPPTPatternAsHatch, FixImageRot;
+static FFNEXUS *emf_short_fflist = NULL; //only those fonts so far encountered. This is SHARED with wmf-print.cpp
+static FFNEXUS *emf_long_fflist = NULL; //all the fonts described in ...\share\extensions\fontfix.conf
+static EMFTRACK *et = NULL;
+static EMFHANDLES *eht = NULL;
+static GRADVALUES gv;
void PrintEmf::read_system_fflist(void){ //this is not called by any other source files
- FFNEXUS *temp=NULL;
- FFNEXUS *ptr=NULL;
- std::fstream fffile;
- std::string instr;
- char fontname[128];
- double f1,f2,f3;
- std::string path_to_ffconf;
-
- if(emf_long_fflist){
- return;
- }
- path_to_ffconf=INKSCAPE_EXTENSIONDIR;
+ FFNEXUS *temp=NULL;
+ FFNEXUS *ptr=NULL;
+ std::fstream fffile;
+ std::string instr;
+ char fontname[128];
+ double f1,f2,f3;
+ std::string path_to_ffconf;
+
+ if(emf_long_fflist)return;
+ char *oldlocale = g_strdup(setlocale(LC_NUMERIC, NULL));
+ setlocale(LC_NUMERIC, "C");
+
+ path_to_ffconf=INKSCAPE_EXTENSIONDIR;
#ifdef WIN32
- path_to_ffconf.append("\\fontfix.conf"); //Windows path syntax
+ path_to_ffconf.append("\\fontfix.conf"); //Windows path syntax
#else
- path_to_ffconf.append("/fontfix.conf"); //Unix/linx path syntax
+ path_to_ffconf.append("/fontfix.conf"); //Unix/linx path syntax
#endif
- //open the input
- fffile.open(path_to_ffconf.c_str(), std::ios::in);
- if(!fffile.is_open()){
- g_error("Unable to open file: %s\n", path_to_ffconf.c_str());
- // throw "boom";
- }
-
- char *oldlocale = g_strdup (setlocale (LC_NUMERIC, NULL));
- setlocale (LC_NUMERIC, "C");
-
- while (std::getline(fffile,instr)){
- if (instr.empty()) {
- continue;
- }
- if(instr[0]=='#'){
- continue;
+ //open the input
+ fffile.open(path_to_ffconf.c_str(), std::ios::in);
+ if(!fffile.is_open()){
+ g_error("Unable to open file: %s\n", path_to_ffconf.c_str());
}
-
- // not a comment, get the 4 values from the line
- int elements=sscanf(instr.c_str(),"%6lf %6lf %6lf %127[^\n\r]",&f1,&f2,&f3, &fontname[0]);
- if(elements!=4){
- setlocale (LC_NUMERIC, oldlocale);
- g_free (oldlocale);
- fffile.close();
- g_error("Expected \"f1 f2 f3 Fontname\" but did not find it in file: %s\n", path_to_ffconf.c_str());
- // throw "boom";
- }
- temp=(FFNEXUS *) calloc(1,sizeof(FFNEXUS)); //This will never be freed
- temp->f1=f1;
- temp->f2=f2;
- temp->f3=f3;
- temp->fontname=strdup(fontname); //This will never be freed
- temp->next=NULL; //just to be explicit, it is already 0
- if(ptr){
- ptr->next=temp;
- ptr=temp;
- }
- else {
- emf_long_fflist=ptr=temp;
+ while (std::getline(fffile,instr)){
+ if(instr[0]=='#')continue;
+ // not a comment, get the 4 values from the line
+ int elements=sscanf(instr.c_str(),"%lf %lf %lf %127[^\n]",&f1,&f2,&f3, &fontname[0]);
+ if(elements!=4){
+ g_error("Expected \"f1 f2 f3 Fontname\" but did not find it in file: %s\n", path_to_ffconf.c_str());
+ }
+ temp=(FFNEXUS *) calloc(1,sizeof(FFNEXUS)); //This will never be freed
+ temp->f1=f1;
+ temp->f2=f2;
+ temp->f3=f3;
+ temp->fontname=strdup(fontname); //This will never be freed
+ temp->next=NULL; //just to be explicit, it is already 0
+ if(ptr){
+ ptr->next=temp;
+ ptr=temp;
+ }
+ else {
+ emf_long_fflist=ptr=temp;
+ }
}
- }
- setlocale (LC_NUMERIC, oldlocale);
- g_free (oldlocale);
- fffile.close();
+ fffile.close();
+
+ setlocale(LC_NUMERIC, oldlocale);
+ g_free(oldlocale);
}
/* Looks for the fontname in the long list. If it does not find it, it adds the default values
to the short list with this fontname. If it does find it, then it adds the specified values.
*/
void PrintEmf::search_long_fflist(const char *fontname, double *f1, double *f2, double *f3){ //this is not called by any other source files
-FFNEXUS *ptr=NULL;
-FFNEXUS *tmp=emf_long_fflist;
- if(!emf_long_fflist){
- g_error("Programming error search_long_fflist called before read_system_fflist\n");
- // throw "boom";
- }
- ptr=emf_long_fflist;
- while(ptr){
- if(!strcmp(ptr->fontname,fontname)){ tmp=ptr; break; }
- ptr=ptr->next;
- }
- //tmp points at either the found name, or the default, the first entry in long_fflist
- if(!emf_short_fflist){
- ptr=emf_short_fflist=(FFNEXUS *) malloc(sizeof(FFNEXUS));
- }
- else {
- ptr=emf_short_fflist;
- while(ptr->next){ ptr=ptr->next; }
- ptr->next=(FFNEXUS *) malloc(sizeof(FFNEXUS));
- ptr=ptr->next;
- }
- ptr->fontname=strdup(tmp->fontname);
- *f1 = ptr->f1 = tmp->f1;
- *f2 = ptr->f2 = tmp->f2;
- *f3 = ptr->f3 = tmp->f3;
- ptr->next=NULL;
+ FFNEXUS *ptr=NULL;
+ FFNEXUS *tmp=emf_long_fflist;
+ if(!emf_long_fflist){
+ g_error("Programming error search_long_fflist called before read_system_fflist\n");
+ }
+ ptr=emf_long_fflist;
+ while(ptr){
+ if(!strcmp(ptr->fontname,fontname)){ tmp=ptr; break; }
+ ptr=ptr->next;
+ }
+ //tmp points at either the found name, or the default, the first entry in long_fflist
+ if(!emf_short_fflist){
+ ptr=emf_short_fflist=(FFNEXUS *) malloc(sizeof(FFNEXUS));
+ }
+ else {
+ ptr=emf_short_fflist;
+ while(ptr->next){ ptr=ptr->next; }
+ ptr->next=(FFNEXUS *) malloc(sizeof(FFNEXUS));
+ ptr=ptr->next;
+ }
+ ptr->fontname=strdup(tmp->fontname);
+ *f1 = ptr->f1 = tmp->f1;
+ *f2 = ptr->f2 = tmp->f2;
+ *f3 = ptr->f3 = tmp->f3;
+ ptr->next=NULL;
}
/* Looks for the fontname in the short list. If it does not find it, it looks in the long_fflist.
Either way it returns the f1, f2, f3 parameters for the font, even if these are for the default.
*/
void PrintEmf::search_short_fflist(const char *fontname, double *f1, double *f2, double *f3){ //this is not called by any other source files
-FFNEXUS *ptr=NULL;
-static FFNEXUS *last=NULL;
- if(!emf_long_fflist){
- g_error("Programming error search_short_fflist called before read_system_fflist\n");
- // throw "boom";
- }
- // This speeds things up a lot - if the same font is called twice in a row, pull it out immediately
- if(last && !strcmp(last->fontname,fontname)){ ptr=last; }
- else { ptr=emf_short_fflist; } // short_fflist may still be NULL
- while(ptr){
- if(!strcmp(ptr->fontname,fontname)){ *f1=ptr->f1; *f2=ptr->f2; *f3=ptr->f3; last=ptr; return; }
- ptr=ptr->next;
- }
- //reach this point only if there is no match
- search_long_fflist(fontname, f1, f2, f3);
+ FFNEXUS *ptr=NULL;
+ static FFNEXUS *last=NULL;
+
+ if(!emf_long_fflist){
+ g_error("Programming error search_short_fflist called before read_system_fflist\n");
+ }
+ // This speeds things up a lot - if the same font is called twice in a row, pull it out immediately
+ if(last && !strcmp(last->fontname,fontname)){ ptr=last; }
+ else { ptr=emf_short_fflist; } // short_fflist may still be NULL
+ while(ptr){
+ if(!strcmp(ptr->fontname,fontname)){ *f1=ptr->f1; *f2=ptr->f2; *f3=ptr->f3; last=ptr; return; }
+ ptr=ptr->next;
+ }
+ //reach this point only if there is no match
+ search_long_fflist(fontname, f1, f2, f3);
}
void PrintEmf::smuggle_adxky_out(const char *string, uint32_t **adx, double *ky, int *ndx, float scale){
@@ -238,14 +224,11 @@ void PrintEmf::smuggle_adxky_out(const char *string, uint32_t **adx, double *ky,
if(!*ndx)return; // this could happen with an empty string
cptr += 7;
ladx = (uint32_t *) malloc(*ndx * sizeof(uint32_t) );
- if(!ladx){
- g_error("Out of memory");
- // throw "Out of memory";
- }
+ if(!ladx)g_message("Out of memory");
*adx=ladx;
for(i=0; i<*ndx; i++,cptr+=7, ladx++){
- sscanf(cptr,"%7f",&fdx);
- *ladx = static_cast<uint32_t>(round(fdx * scale));
+ sscanf(cptr,"%7f",&fdx);
+ *ladx=(uint32_t) round(fdx * scale);
}
cptr++; // skip 2nd fake terminator
sscanf(cptr,"%7f",&fdx);
@@ -256,13 +239,12 @@ void PrintEmf::smuggle_adxky_out(const char *string, uint32_t **adx, double *ky,
inverse of sethexcolor() in emf-inout.cpp
*/
U_COLORREF PrintEmf::gethexcolor(uint32_t color){
-
U_COLORREF out;
- out = U_RGB(
- (color >> 16) & 0xFF,
- (color >> 8) & 0xFF,
- (color >> 0) & 0xFF
- );
+ out = U_RGB(
+ (color >> 16) & 0xFF,
+ (color >> 8) & 0xFF,
+ (color >> 0) & 0xFF
+ );
return(out);
}
@@ -285,7 +267,7 @@ uint32_t PrintEmf::transweight(const unsigned int inkweight){
PrintEmf::PrintEmf (void)
{
- // all of the class variables are initialized elsewhere, many in PrintWmf::Begin,
+ // all of the class variables are initialized elsewhere, many in PrintEmf::Begin,
}
@@ -308,21 +290,21 @@ unsigned int PrintEmf::setup (Inkscape::Extension::Print * /*mod*/)
unsigned int PrintEmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
{
- U_SIZEL szlDev, szlMm;
- U_RECTL rclBounds, rclFrame;
- char *rec;
-
- gchar const *utf8_fn = mod->get_param_string("destination");
- FixPPTCharPos = mod->get_param_bool("FixPPTCharPos");
- FixPPTDashLine = mod->get_param_bool("FixPPTDashLine");
- FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys");
+ U_SIZEL szlDev, szlMm;
+ U_RECTL rclBounds, rclFrame;
+ char *rec;
+ gchar const *utf8_fn = mod->get_param_string("destination");
+
+ FixPPTCharPos = mod->get_param_bool("FixPPTCharPos");
+ FixPPTDashLine = mod->get_param_bool("FixPPTDashLine");
+ FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys");
FixPPTPatternAsHatch = mod->get_param_bool("FixPPTPatternAsHatch");
- FixImageRot = mod->get_param_bool("FixImageRot");
+ FixImageRot = mod->get_param_bool("FixImageRot");
(void) emf_start(utf8_fn, 1000000, 250000, &et); // Initialize the et structure
(void) htable_create(128, 128, &eht); // Initialize the eht structure
- char *ansi_uri = const_cast<char *>(utf8_fn);
+ char *ansi_uri = (char *) utf8_fn;
// width and height in px
@@ -331,18 +313,18 @@ unsigned int PrintEmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
// initialize a few global variables
hbrush = hbrushOld = hpen = 0;
- use_stroke = use_fill = simple_shape = false;
+ use_stroke = use_fill = simple_shape = usebk = false;
Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
if(nv){
- const char *p1 = nv->attribute("pagecolor");
- char *p2;
- uint32_t lc = strtoul( &p1[1], &p2, 16 ); // it looks like "#ABC123"
- if(*p2)lc=0;
- gv.bgc = gethexcolor(lc);
- gv.rgb[0] = static_cast<float>(U_RGBAGetR(gv.bgc)/255.0);
- gv.rgb[1] = static_cast<float>(U_RGBAGetG(gv.bgc)/255.0);
- gv.rgb[2] = static_cast<float>(U_RGBAGetB(gv.bgc)/255.0);
+ const char *p1 = nv->attribute("pagecolor");
+ char *p2;
+ uint32_t lc = strtoul( &p1[1], &p2, 16 ); // it looks like "#ABC123"
+ if(*p2)lc=0;
+ gv.bgc = gethexcolor(lc);
+ gv.rgb[0] = (float) U_RGBAGetR(gv.bgc)/255.0;
+ gv.rgb[1] = (float) U_RGBAGetG(gv.bgc)/255.0;
+ gv.rgb[2] = (float) U_RGBAGetB(gv.bgc)/255.0;
}
bool pageBoundingBox;
@@ -354,9 +336,7 @@ unsigned int PrintEmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
} else {
SPItem* doc_item = doc->getRoot();
Geom::OptRect bbox = doc_item->desktopVisualBounds();
- if (bbox) {
- d = *bbox;
- }
+ if (bbox) d = *bbox;
}
d *= Geom::Scale(IN_PER_PX);
@@ -365,7 +345,7 @@ unsigned int PrintEmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
float dwInchesY = d.height();
// dwInchesX x dwInchesY in micrometer units, dpi=90 -> 3543.3 dpm
- (void) drawing_size(static_cast<int>(ceil(dwInchesX*25.4)), static_cast<int>(ceil(dwInchesY*25.4)), 3.543307, &rclBounds, &rclFrame);
+ (void) drawing_size((int) ceil(dwInchesX*25.4), (int) ceil(dwInchesY*25.4), 3.543307, &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;
@@ -392,17 +372,15 @@ unsigned int PrintEmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
// construct the EMRHEADER record and append it to the EMF in memory
rec = U_EMRHEADER_set( rclBounds, rclFrame, NULL, cbDesc, Description, szlDev, szlMm, 0);
free(Description);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- g_error("Fatal programming error in PrintEmf::begin at EMRHEADER");
- // throw "Fatal programming error in PrintEmf::begin at EMRHEADER";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::begin at EMRHEADER");
}
// Simplest mapping mode, supply all coordinates in pixels
rec = U_EMRSETMAPMODE_set(U_MM_TEXT);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- g_error ("Fatal programming error in PrintEmf::begin at EMRSETMAPMODE");
- // throw "Fatal programming error in PrintEmf::begin at EMRSETMAPMODE";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::begin at EMRSETMAPMODE");
}
@@ -417,35 +395,66 @@ unsigned int PrintEmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
worldTransform.eDy = 0;
rec = U_EMRMODIFYWORLDTRANSFORM_set(worldTransform, U_MWT_LEFTMULTIPLY);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- g_error("Fatal programming error in PrintEmf::begin at EMRMODIFYWORLDTRANSFORM");
- // throw "Fatal programming error in PrintEmf::begin at EMRMODIFYWORLDTRANSFORM";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::begin at EMRMODIFYWORLDTRANSFORM");
}
if (1) {
snprintf(buff, sizeof(buff)-1, "Screen=%dx%dpx, %dx%dmm", PixelsX, PixelsY, MMX, MMY);
rec = textcomment_set(buff);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- g_error("Fatal programming error in PrintEmf::begin at textcomment_set 1");
- // throw "Fatal programming error in PrintEmf::begin at textcomment_set 1";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::begin at textcomment_set 1");
}
snprintf(buff, sizeof(buff)-1, "Drawing=%.1lfx%.1lfpx, %.1lfx%.1lfmm", _width, _height, dwInchesX * MM_PER_IN, dwInchesY * MM_PER_IN);
rec = textcomment_set(buff);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- g_error("Fatal programming error in PrintEmf::begin at textcomment_set 1");
- // throw "Fatal programming error in PrintEmf::begin at textcomment_set 1";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::begin at textcomment_set 1");
}
}
+ /* set some parameters, else the program that reads the EMF may default to other values */
+
+ rec = U_EMRSETBKMODE_set(U_TRANSPARENT);
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::text at U_EMRSETBKMODE_set");
+ }
+
+ hpolyfillmode=U_WINDING;
+ rec = U_EMRSETPOLYFILLMODE_set(U_WINDING);
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::text at U_EMRSETPOLYFILLMODE_set");
+ }
+
+ // Text alignment: (Never changes)
+ // - (x,y) coordinates received by this filter are those of the point where the text
+ // actually starts, and already takes into account the text object's alignment;
+ // - for this reason, the EMF text alignment must always be TA_BASELINE|TA_LEFT.
+ rec = U_EMRSETTEXTALIGN_set(U_TA_BASELINE | U_TA_LEFT);
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::text at U_EMRSETTEXTALIGN_set");
+ }
+
+ htextcolor_rgb[0] = htextcolor_rgb[1] = htextcolor_rgb[2] = 0.0;
+ rec = U_EMRSETTEXTCOLOR_set(U_RGB(0,0,0));
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::text at U_EMRSETTEXTCOLOR_set");
+ }
+
+ rec = U_EMRSETROP2_set(U_R2_COPYPEN);
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::text at U_EMRSETROP2_set");
+ }
+
+ /* miterlimit is set with eah pen, so no need to check for it changes as in WMF */
+
return 0;
}
unsigned int PrintEmf::finish (Inkscape::Extension::Print * /*mod*/)
{
-// std::cout << "finish " << std::endl;
char *rec;
if (!et) return 0;
@@ -453,57 +462,64 @@ unsigned int PrintEmf::finish (Inkscape::Extension::Print * /*mod*/)
// earlier versions had flush of fill here, but it never executed and was removed
rec = U_EMREOF_set(0,NULL,et); // generate the EOF record
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- g_error("Fatal programming error in PrintEmf::finish");
- // throw "Fatal programming error in PrintEmf::finish";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::finish");
}
(void) emf_finish(et, eht); // Finalize and write out the EMF
emf_free(&et); // clean up
htable_free(&eht); // clean up
-// std::cout << "end finish" << std::endl;
return 0;
}
-unsigned int PrintEmf::comment (Inkscape::Extension::Print * /*module*/,
- const char * /*comment*/)
+unsigned int PrintEmf::comment (
+ Inkscape::Extension::Print * /*module*/,
+ const char * /*comment*/)
{
-// std::cout << "comment " << std::endl;
if (!et) return 0;
// earlier versions had flush of fill here, but it never executed and was removed
-// std::cout << "end comment" << std::endl;
return 0;
}
-// Extracth hatchType, hatchColor from a name like
+// Extract hatchType, hatchColor from a name like
// EMFhatch<hatchType>_<hatchColor>
// Where the first one is a number and the second a color in hex.
// hatchType and hatchColor have been set with defaults before this is called.
//
-void PrintEmf::hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor){
- int val;
- uint32_t hcolor=0;
- // name should be EMFhatch or WMFhatch but *MFhatch will be accepted
- if(0!=strncmp(&name[1],"MFhatch",7)){ return; } // not anything we can parse
- name+=8; // EMFhatch already detected
- val = 0;
- while(*name && isdigit(*name)){
- val = 10*val + *name - '0';
- name++;
- }
- *hatchType = val;
- if(*name != '_' || val > U_HS_DITHEREDBKCLR){ // wrong syntax, cannot classify
- *hatchType = -1;
- }
- else {
- name++;
- if(1 != sscanf(name,"%X",&hcolor)){ *hatchType = -1; } // again wrong syntax, cannot classify
- *hatchColor = gethexcolor(hcolor);
- }
- if(*hatchType > U_HS_SOLIDCLR)*hatchType = U_HS_SOLIDCLR;
+void PrintEmf::hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor){
+ int val;
+ uint32_t hcolor=0;
+ uint32_t bcolor=0;
+
+ // name should be EMFhatch or WMFhatch but *MFhatch will be accepted
+ if(0!=strncmp(&name[1],"MFhatch",7)){ return; } // not anything we can parse
+ name += 8; // EMFhatch already detected
+ val = 0;
+ while(*name && isdigit(*name)){
+ val = 10*val + *name - '0';
+ name++;
+ }
+ *hatchType = val;
+ if(*name != '_' || val > U_HS_DITHEREDBKCLR){ // wrong syntax, cannot classify
+ *hatchType = -1;
+ }
+ else {
+ name++;
+ if(2 != sscanf(name,"%X_%X", &hcolor, &bcolor)){ // not a pattern with background
+ if(1 != sscanf(name,"%X", &hcolor)){ *hatchType = -1; } // not a pattern, cannot classify
+ *hatchColor = gethexcolor(hcolor);
+ }
+ else {
+ *hatchColor = gethexcolor(hcolor);
+ *bkColor = gethexcolor(bcolor);
+ usebk = true;
+ }
+ }
+ /* Everything > U_HS_SOLIDCLR is solid, just specify the color in the brush rather than messing around with background or textcolor */
+ if(*hatchType > U_HS_SOLIDCLR)*hatchType = U_HS_SOLIDCLR;
}
//
@@ -513,125 +529,124 @@ void PrintEmf::hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor
// otherwise hatchType is set to -1 and hatchColor is not defined.
//
-void PrintEmf::brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor){
- if(depth==0){
- *epixbuf = NULL;
- *hatchType = -1;
- *hatchColor = U_RGB(0,0,0);
- }
- depth++;
- // first look along the pattern chain, if there is one
- if(SP_IS_PATTERN(parent)){
- for (SPPattern *pat_i = SP_PATTERN(parent); pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) {
- if(SP_IS_IMAGE(pat_i)){
- *epixbuf = ((SPImage *)pat_i)->pixbuf;
- return;
- }
- char temp[32]; // large enough
- temp[31]='\0';
- strncpy(temp,pat_i->getAttribute("id"),31); // Some names may be longer than [EW]MFhatch#_######
- hatch_classify(temp,hatchType,hatchColor);
- if(*hatchType != -1)return;
-
- // still looking? Look at this pattern's children, if there are any
- SPObject *child = pat_i->firstChild();
- while(child && !(*epixbuf) && (*hatchType == -1)){
- brush_classify(child, depth, epixbuf, hatchType, hatchColor);
+void PrintEmf::brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor){
+ if(depth==0){
+ *epixbuf = NULL;
+ *hatchType = -1;
+ *hatchColor = U_RGB(0,0,0);
+ *bkColor = U_RGB(255,255,255);
+ }
+ depth++;
+ // first look along the pattern chain, if there is one
+ if(SP_IS_PATTERN(parent)){
+ for (SPPattern *pat_i = SP_PATTERN(parent); pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) {
+ if(SP_IS_IMAGE(pat_i)){
+ *epixbuf = ((SPImage *)pat_i)->pixbuf;
+ return;
+ }
+ char temp[32]; // large enough
+ temp[31]='\0';
+ strncpy(temp,pat_i->getAttribute("id"),31); // Some names may be longer than [EW]MFhatch#_######
+ hatch_classify(temp, hatchType, hatchColor, bkColor);
+ if(*hatchType != -1)return;
+
+ // still looking? Look at this pattern's children, if there are any
+ SPObject *child = pat_i->firstChild();
+ while(child && !(*epixbuf) && (*hatchType == -1)){
+ brush_classify(child, depth, epixbuf, hatchType, hatchColor, bkColor);
+ child = child->getNext();
+ }
+ }
+ }
+ else if(SP_IS_IMAGE(parent)){
+ *epixbuf = ((SPImage *)parent)->pixbuf;
+ return;
+ }
+ else { // some inkscape rearrangements pass through nodes between pattern and image which are not classified as either.
+ SPObject *child = parent->firstChild();
+ while(child && !(*epixbuf) && (*hatchType == -1)){
+ brush_classify(child, depth, epixbuf, hatchType, hatchColor, bkColor);
child = child->getNext();
- }
- }
- }
- else if(SP_IS_IMAGE(parent)){
- *epixbuf = ((SPImage *)parent)->pixbuf;
- return;
- }
- else { // some inkscape rearrangements pass through nodes between pattern and image which are not classified as either.
- SPObject *child = parent->firstChild();
- while(child && !(*epixbuf) && (*hatchType == -1)){
- brush_classify(child, depth, epixbuf, hatchType, hatchColor);
- child = child->getNext();
- }
- }
+ }
+ }
}
//swap R/B in 4 byte pixel
void PrintEmf::swapRBinRGBA(char *px, int pixels){
- char tmp;
- for(int i=0;i<pixels*4;px+=4,i+=4){
- tmp=px[2];
- px[2]=px[0];
- px[0]=tmp;
- }
+ char tmp;
+ for(int i=0;i<pixels*4;px+=4,i+=4){
+ tmp=px[2];
+ px[2]=px[0];
+ px[0]=tmp;
+ }
}
/* opacity weighting of two colors as float. v1 is the color, op is its opacity, v2 is the background color */
inline float opweight(float v1, float v2, float op){
- return v1*op + v2*(1.0-op);
+ return v1*op + v2*(1.0-op);
}
U_COLORREF PrintEmf::avg_stop_color(SPGradient *gr){
- U_COLORREF cr;
- int last = gr->vector.stops.size() -1;
- if(last>=1){
- float rgbs[3];
- float rgbe[3];
- float ops,ope;
-
- ops = gr->vector.stops[0 ].opacity;
- ope = gr->vector.stops[last].opacity;
- sp_color_get_rgb_floatv(&gr->vector.stops[0 ].color, rgbs);
- sp_color_get_rgb_floatv(&gr->vector.stops[last].color, rgbe);
-
- /* Replace opacity at start & stop with that fraction background color, then average those two for final color. */
- cr = U_RGB(
- 255*(( opweight(rgbs[0],gv.rgb[0],ops) + opweight(rgbe[0],gv.rgb[0],ope) )/2.0),
- 255*(( opweight(rgbs[1],gv.rgb[1],ops) + opweight(rgbe[1],gv.rgb[1],ope) )/2.0),
- 255*(( opweight(rgbs[2],gv.rgb[2],ops) + opweight(rgbe[2],gv.rgb[2],ope) )/2.0)
- );
- }
- else {
- cr = U_RGB(0, 0, 0); // The default fill
- }
- return cr;
+ U_COLORREF cr;
+ int last = gr->vector.stops.size() -1;
+ if(last>=1){
+ float rgbs[3];
+ float rgbe[3];
+ float ops,ope;
+
+ ops = gr->vector.stops[0 ].opacity;
+ ope = gr->vector.stops[last].opacity;
+ sp_color_get_rgb_floatv(&gr->vector.stops[0 ].color, rgbs);
+ sp_color_get_rgb_floatv(&gr->vector.stops[last].color, rgbe);
+
+ /* Replace opacity at start & stop with that fraction background color, then average those two for final color. */
+ cr = U_RGB(
+ 255*(( opweight(rgbs[0],gv.rgb[0],ops) + opweight(rgbe[0],gv.rgb[0],ope) )/2.0),
+ 255*(( opweight(rgbs[1],gv.rgb[1],ops) + opweight(rgbe[1],gv.rgb[1],ope) )/2.0),
+ 255*(( opweight(rgbs[2],gv.rgb[2],ops) + opweight(rgbe[2],gv.rgb[2],ope) )/2.0)
+ );
+ }
+ else {
+ cr = U_RGB(0, 0, 0); // The default fill
+ }
+ return cr;
}
int PrintEmf::hold_gradient(void *gr, int mode){
- gv.mode = mode;
- gv.grad = gr;
- if(mode==DRAW_RADIAL_GRADIENT){
- SPRadialGradient *rg = (SPRadialGradient *) gr;
- gv.r = rg->r.computed; // radius, but of what???
- gv.p1 = Geom::Point(rg->cx.computed, rg->cy.computed); // center
- gv.p2 = Geom::Point(gv.r, 0) + gv.p1; // xhandle
- gv.p3 = Geom::Point(0, -gv.r) + gv.p1; // yhandle
- if (rg->gradientTransform_set) {
- gv.p1 = gv.p1 * rg->gradientTransform;
- gv.p2 = gv.p2 * rg->gradientTransform;
- gv.p3 = gv.p3 * rg->gradientTransform;
- }
- }
- else if(mode==DRAW_LINEAR_GRADIENT){
- SPLinearGradient *lg = (SPLinearGradient *) gr;
- gv.r = 0; // unused
- gv.p1 = Geom::Point (lg->x1.computed, lg->y1.computed); // start
- gv.p2 = Geom::Point (lg->x2.computed, lg->y2.computed); // end
- gv.p3 = Geom::Point (0, 0); // unused
- if (lg->gradientTransform_set) {
- gv.p1 = gv.p1 * lg->gradientTransform;
- gv.p2 = gv.p2 * lg->gradientTransform;
- }
- }
- else {
- g_error("Fatal programming error, hold_gradient() in emf-print.cpp called with invalid draw mode");
- // throw "Fatal programming error, hold_gradient() in emf-print.cpp called with invalid draw mode";
- }
- return 1;
+ gv.mode = mode;
+ gv.grad = gr;
+ if(mode==DRAW_RADIAL_GRADIENT){
+ SPRadialGradient *rg = (SPRadialGradient *) gr;
+ gv.r = rg->r.computed; // radius, but of what???
+ gv.p1 = Geom::Point(rg->cx.computed, rg->cy.computed); // center
+ gv.p2 = Geom::Point(gv.r, 0) + gv.p1; // xhandle
+ gv.p3 = Geom::Point(0, -gv.r) + gv.p1; // yhandle
+ if (rg->gradientTransform_set) {
+ gv.p1 = gv.p1 * rg->gradientTransform;
+ gv.p2 = gv.p2 * rg->gradientTransform;
+ gv.p3 = gv.p3 * rg->gradientTransform;
+ }
+ }
+ else if(mode==DRAW_LINEAR_GRADIENT){
+ SPLinearGradient *lg = (SPLinearGradient *) gr;
+ gv.r = 0; // unused
+ gv.p1 = Geom::Point (lg->x1.computed, lg->y1.computed); // start
+ gv.p2 = Geom::Point (lg->x2.computed, lg->y2.computed); // end
+ gv.p3 = Geom::Point (0, 0); // unused
+ if (lg->gradientTransform_set) {
+ gv.p1 = gv.p1 * lg->gradientTransform;
+ gv.p2 = gv.p2 * lg->gradientTransform;
+ }
+ }
+ else {
+ g_error("Fatal programming error, hold_gradient() in emf-print.cpp called with invalid draw mode");
+ }
+ return 1;
}
// fcolor is defined when gradients are being expanded, it is the color of one stripe or ring.
int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor)
{
-// std::cout << "create_brush " << std::endl;
float rgb[3];
char *rec;
U_LOGBRUSH lb;
@@ -641,6 +656,7 @@ int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor)
uint32_t brushStyle;
int hatchType;
U_COLORREF hatchColor;
+ U_COLORREF bkColor;
uint32_t width = 0; // quiets a harmless compiler warning, initialization not otherwise required.
uint32_t height = 0;
@@ -651,73 +667,74 @@ int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor)
fill_mode = DRAW_PAINT;
brushStyle = U_BS_SOLID;
hatchType = U_HS_SOLIDCLR;
+ bkColor = U_RGB(0, 0, 0);
if(fcolor){ hatchColor = *fcolor; }
else { hatchColor = U_RGB(0, 0, 0); }
if (!fcolor && style) {
if(style->fill.isColor()){
- fill_mode = DRAW_PAINT;
- float opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value);
- if (opacity <= 0.0)opacity = 0.0; // basically the same as no fill
+ fill_mode = DRAW_PAINT;
+ float opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value);
+ if (opacity <= 0.0)opacity = 0.0; // basically the same as no fill
- sp_color_get_rgb_floatv( &style->fill.value.color, rgb );
- hatchColor = U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]);
+ sp_color_get_rgb_floatv( &style->fill.value.color, rgb );
+ hatchColor = U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]);
- fmode = style->fill_rule.computed == 0 ? U_WINDING : (style->fill_rule.computed == 2 ? U_ALTERNATE : U_ALTERNATE);
+ fmode = style->fill_rule.computed == 0 ? U_WINDING : (style->fill_rule.computed == 2 ? U_ALTERNATE : U_ALTERNATE);
}
else if(SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style))){ // must be paint-server
- SPPaintServer *paintserver = style->fill.value.href->getObject();
- SPPattern *pat = SP_PATTERN (paintserver);
- double dwidth = pattern_width(pat);
- double dheight = pattern_height(pat);
- width = dwidth;
- height = dheight;
- brush_classify(pat,0,&pixbuf,&hatchType,&hatchColor);
- if(pixbuf){ fill_mode = DRAW_IMAGE; }
- else { // pattern
- fill_mode = DRAW_PATTERN;
- if(hatchType == -1){ // Not a standard hatch, so force it to something
- hatchType = U_HS_CROSS;
- hatchColor = U_RGB(0xFF,0xC3,0xC3);
- }
- }
- if(FixPPTPatternAsHatch){
- if(hatchType == -1){ // image or unclassified
- fill_mode = DRAW_PATTERN;
- hatchType = U_HS_DIAGCROSS;
- hatchColor = U_RGB(0xFF,0xC3,0xC3);
- }
- }
- brushStyle = U_BS_HATCHED;
+ SPPaintServer *paintserver = style->fill.value.href->getObject();
+ SPPattern *pat = SP_PATTERN (paintserver);
+ double dwidth = pattern_width(pat);
+ double dheight = pattern_height(pat);
+ width = dwidth;
+ height = dheight;
+ brush_classify(pat,0,&pixbuf,&hatchType,&hatchColor,&bkColor);
+ if(pixbuf){ fill_mode = DRAW_IMAGE; }
+ else { // pattern
+ fill_mode = DRAW_PATTERN;
+ if(hatchType == -1){ // Not a standard hatch, so force it to something
+ hatchType = U_HS_CROSS;
+ hatchColor = U_RGB(0xFF,0xC3,0xC3);
+ }
+ }
+ if(FixPPTPatternAsHatch){
+ if(hatchType == -1){ // image or unclassified
+ fill_mode = DRAW_PATTERN;
+ hatchType = U_HS_DIAGCROSS;
+ hatchColor = U_RGB(0xFF,0xC3,0xC3);
+ }
+ }
+ brushStyle = U_BS_HATCHED;
}
else if(SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style))){ // must be a gradient
- // currently we do not do anything with gradients, the code below just sets the color to the average of the stops
- SPPaintServer *paintserver = style->fill.value.href->getObject();
- SPLinearGradient *lg = NULL;
- SPRadialGradient *rg = NULL;
-
- if (SP_IS_LINEARGRADIENT (paintserver)) {
- lg = SP_LINEARGRADIENT(paintserver);
- SP_GRADIENT(lg)->ensureVector(); // when exporting from commandline, vector is not built
- fill_mode = DRAW_LINEAR_GRADIENT;
- }
- else if (SP_IS_RADIALGRADIENT (paintserver)) {
- rg = SP_RADIALGRADIENT(paintserver);
- SP_GRADIENT(rg)->ensureVector(); // when exporting from commandline, vector is not built
- fill_mode = DRAW_RADIAL_GRADIENT;
- }
- else {
- // default fill
- }
-
- if(rg){
- if(FixPPTGrad2Polys){ return hold_gradient(rg, fill_mode); }
- else { hatchColor = avg_stop_color(rg); }
- }
- else if(lg){
- if(FixPPTGrad2Polys){ return hold_gradient(lg, fill_mode); }
- else { hatchColor = avg_stop_color(lg); }
- }
+ // currently we do not do anything with gradients, the code below just sets the color to the average of the stops
+ SPPaintServer *paintserver = style->fill.value.href->getObject();
+ SPLinearGradient *lg = NULL;
+ SPRadialGradient *rg = NULL;
+
+ if (SP_IS_LINEARGRADIENT (paintserver)) {
+ lg = SP_LINEARGRADIENT(paintserver);
+ SP_GRADIENT(lg)->ensureVector(); // when exporting from commandline, vector is not built
+ fill_mode = DRAW_LINEAR_GRADIENT;
+ }
+ else if (SP_IS_RADIALGRADIENT (paintserver)) {
+ rg = SP_RADIALGRADIENT(paintserver);
+ SP_GRADIENT(rg)->ensureVector(); // when exporting from commandline, vector is not built
+ fill_mode = DRAW_RADIAL_GRADIENT;
+ }
+ else {
+ // default fill
+ }
+
+ if(rg){
+ if(FixPPTGrad2Polys){ return hold_gradient(rg, fill_mode); }
+ else { hatchColor = avg_stop_color(rg); }
+ }
+ else if(lg){
+ if(FixPPTGrad2Polys){ return hold_gradient(lg, fill_mode); }
+ else { hatchColor = avg_stop_color(lg); }
+ }
}
}
else { // if (!style)
@@ -727,74 +744,87 @@ int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor)
lb = logbrush_set(brushStyle, hatchColor, hatchType);
switch(fill_mode){
- case DRAW_LINEAR_GRADIENT: // fill with average color unless gradients are converted to slices
- case DRAW_RADIAL_GRADIENT: // ditto
- case DRAW_PAINT:
- case DRAW_PATTERN:
- rec = createbrushindirect_set(&brush, eht, lb);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::create_brush at createbrushindirect_set";
- }
- break;
- case DRAW_IMAGE:
- char *px;
- char *rgba_px;
- uint32_t cbPx;
- uint32_t colortype;
- PU_RGBQUAD ct;
- int numCt;
- U_BITMAPINFOHEADER Bmih;
- PU_BITMAPINFO Bmi;
- rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // 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);
- // Not sure why the next swap is needed because the preceding does it, and the code is identical
- // to that in stretchdibits_set, which does not need this.
- swapRBinRGBA(px, width*height);
- Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0);
- Bmi = bitmapinfo_set(Bmih, ct);
- rec = createdibpatternbrushpt_set(&brush, eht, U_DIB_RGB_COLORS, Bmi, cbPx, px);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::create_brush at createdibpatternbrushpt_set";
- }
- free(px);
- free(Bmi); // ct will be NULL because of colortype
- break;
+ case DRAW_LINEAR_GRADIENT: // fill with average color unless gradients are converted to slices
+ case DRAW_RADIAL_GRADIENT: // ditto
+ case DRAW_PAINT:
+ case DRAW_PATTERN:
+ // 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_EMRSETBKCOLOR_set(bkColor);
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::create_brush at U_EMRSETBKCOLOR_set");
+ }
+ rec = U_EMRSETBKMODE_set(U_OPAQUE);
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::create_brush at U_EMRSETBKMODE_set");
+ }
+ }
+ rec = createbrushindirect_set(&brush, eht, lb);
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::create_brush at createbrushindirect_set");
+ }
+ break;
+ case DRAW_IMAGE:
+ char *px;
+ char *rgba_px;
+ uint32_t cbPx;
+ uint32_t colortype;
+ PU_RGBQUAD ct;
+ int numCt;
+ U_BITMAPINFOHEADER Bmih;
+ PU_BITMAPINFO Bmi;
+ rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // 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);
+ // Not sure why the next swap is needed because the preceding does it, and the code is identical
+ // to that in stretchdibits_set, which does not need this.
+ swapRBinRGBA(px, width*height);
+ Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0);
+ Bmi = bitmapinfo_set(Bmih, ct);
+ rec = createdibpatternbrushpt_set(&brush, eht, U_DIB_RGB_COLORS, Bmi, cbPx, px);
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::create_brush at createdibpatternbrushpt_set");
+ }
+ free(px);
+ free(Bmi); // ct will be NULL because of colortype
+ break;
}
+
hbrush = brush; // need this later for destroy_brush
rec = selectobject_set(brush, eht);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::create_brush at selectobject_set";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::create_brush at selectobject_set");
}
- rec = U_EMRSETPOLYFILLMODE_set(fmode);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::create_brush at U_EMRSETPOLYdrawmode_set";
+ if(fmode != hpolyfillmode){
+ hpolyfillmode=fmode;
+ rec = U_EMRSETPOLYFILLMODE_set(fmode);
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::create_brush at U_EMRSETPOLYdrawmode_set");
+ }
}
-// std::cout << "end create_brush " << std::endl;
+
return 0;
}
void PrintEmf::destroy_brush()
{
-// std::cout << "destroy_brush " << std::endl;
char *rec;
// before an object may be safely deleted it must no longer be selected
// select in a stock object to deselect this one, the stock object should
// never be used because we always select in a new one before drawing anythingrestore previous brush, necessary??? Would using a default stock object not work?
rec = selectobject_set(U_NULL_BRUSH, eht);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::destroy_brush at selectobject_set";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::destroy_brush at selectobject_set");
}
if (hbrush){
- rec = deleteobject_set(&hbrush, eht);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::destroy_brush";
- }
- hbrush = 0;
+ rec = deleteobject_set(&hbrush, eht);
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::destroy_brush");
+ }
+ hbrush = 0;
}
-// std::cout << "end destroy_brush" << std::endl;
}
@@ -812,6 +842,7 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform)
GdkPixbuf *pixbuf;
int hatchType;
U_COLORREF hatchColor;
+ U_COLORREF bkColor;
uint32_t width,height;
char *px=NULL;
char *rgba_px;
@@ -821,100 +852,110 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform)
int numCt=0;
U_BITMAPINFOHEADER Bmih;
PU_BITMAPINFO Bmi=NULL;
-// std::cout << "create_pen " << std::endl;
if (!et) return 0;
// set a default stroke in case we can't figure out a better way to do it
- brushStyle = U_BS_SOLID;
+ brushStyle = U_BS_SOLID;
hatchColor = U_RGB(0, 0, 0);
hatchType = U_HS_HORIZONTAL;
+ bkColor = U_RGB(0, 0, 0);
if (style) {
float rgb[3];
if(SP_IS_PATTERN(SP_STYLE_STROKE_SERVER(style))){ // must be paint-server
- SPPaintServer *paintserver = style->stroke.value.href->getObject();
- SPPattern *pat = SP_PATTERN (paintserver);
- double dwidth = pattern_width(pat);
- double dheight = pattern_height(pat);
- width = dwidth;
- height = dheight;
- brush_classify(pat,0,&pixbuf,&hatchType,&hatchColor);
- if(pixbuf){
- brushStyle = U_BS_DIBPATTERN;
- rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // 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);
- // Not sure why the next swap is needed because the preceding does it, and the code is identical
- // to that in stretchdibits_set, which does not need this.
- swapRBinRGBA(px, width*height);
- Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0);
- Bmi = bitmapinfo_set(Bmih, ct);
- }
- else { // pattern
- brushStyle = U_BS_HATCHED;
- if(hatchType == -1){ // Not a standard hatch, so force it to something
- hatchType = U_HS_CROSS;
- hatchColor = U_RGB(0xFF,0xC3,0xC3);
- }
- }
- if(FixPPTPatternAsHatch){
- if(hatchType == -1){ // image or unclassified
- brushStyle = U_BS_HATCHED;
- hatchType = U_HS_DIAGCROSS;
- hatchColor = U_RGB(0xFF,0xC3,0xC3);
- }
- }
+ SPPaintServer *paintserver = style->stroke.value.href->getObject();
+ SPPattern *pat = SP_PATTERN (paintserver);
+ double dwidth = pattern_width(pat);
+ double dheight = pattern_height(pat);
+ width = dwidth;
+ height = dheight;
+ brush_classify(pat,0,&pixbuf,&hatchType,&hatchColor,&bkColor);
+ if(pixbuf){
+ brushStyle = U_BS_DIBPATTERN;
+ rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // 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);
+ // Not sure why the next swap is needed because the preceding does it, and the code is identical
+ // to that in stretchdibits_set, which does not need this.
+ swapRBinRGBA(px, width*height);
+ Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0);
+ Bmi = bitmapinfo_set(Bmih, ct);
+ }
+ else { // pattern
+ brushStyle = U_BS_HATCHED;
+ if(usebk){ // OPAQUE mode ALWAYS cancels after the next draw, otherwise it would mess up future text output.
+ rec = U_EMRSETBKCOLOR_set(bkColor);
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::create_pen at U_EMRSETBKCOLOR_set");
+ }
+ rec = U_EMRSETBKMODE_set(U_OPAQUE);
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::create_pen at U_EMRSETBKMODE_set");
+ }
+ }
+ if(hatchType == -1){ // Not a standard hatch, so force it to something
+ hatchType = U_HS_CROSS;
+ hatchColor = U_RGB(0xFF,0xC3,0xC3);
+ }
+ }
+ if(FixPPTPatternAsHatch){
+ if(hatchType == -1){ // image or unclassified
+ brushStyle = U_BS_HATCHED;
+ hatchType = U_HS_DIAGCROSS;
+ hatchColor = U_RGB(0xFF,0xC3,0xC3);
+ }
+ }
}
else if(SP_IS_GRADIENT(SP_STYLE_STROKE_SERVER(style))){ // must be a gradient
- // currently we do not do anything with gradients, the code below has no net effect.
-
- SPPaintServer *paintserver = style->stroke.value.href->getObject();
- if (SP_IS_LINEARGRADIENT (paintserver)) {
- SPLinearGradient *lg=SP_LINEARGRADIENT(paintserver);
-
- SP_GRADIENT(lg)->ensureVector(); // when exporting from commandline, vector is not built
-
- Geom::Point p1 (lg->x1.computed, lg->y1.computed);
- Geom::Point p2 (lg->x2.computed, lg->y2.computed);
-
- if (lg->gradientTransform_set) {
- p1 = p1 * lg->gradientTransform;
- p2 = p2 * lg->gradientTransform;
- }
- hatchColor = avg_stop_color(lg);
- }
- else if (SP_IS_RADIALGRADIENT (paintserver)) {
- SPRadialGradient *rg=SP_RADIALGRADIENT(paintserver);
-
- SP_GRADIENT(rg)->ensureVector(); // when exporting from commandline, vector is not built
- double r = rg->r.computed;
-
- Geom::Point c (rg->cx.computed, rg->cy.computed);
- Geom::Point xhandle_point(r, 0);
- Geom::Point yhandle_point(0, -r);
- yhandle_point += c;
- xhandle_point += c;
- if (rg->gradientTransform_set) {
- c = c * rg->gradientTransform;
- yhandle_point = yhandle_point * rg->gradientTransform;
- xhandle_point = xhandle_point * rg->gradientTransform;
- }
- hatchColor = avg_stop_color(rg);
- }
- else {
- // default fill
- }
+ // currently we do not do anything with gradients, the code below has no net effect.
+
+ SPPaintServer *paintserver = style->stroke.value.href->getObject();
+ if (SP_IS_LINEARGRADIENT (paintserver)) {
+ SPLinearGradient *lg=SP_LINEARGRADIENT(paintserver);
+
+ SP_GRADIENT(lg)->ensureVector(); // when exporting from commandline, vector is not built
+
+ Geom::Point p1 (lg->x1.computed, lg->y1.computed);
+ Geom::Point p2 (lg->x2.computed, lg->y2.computed);
+
+ if (lg->gradientTransform_set) {
+ p1 = p1 * lg->gradientTransform;
+ p2 = p2 * lg->gradientTransform;
+ }
+ hatchColor = avg_stop_color(lg);
+ }
+ else if (SP_IS_RADIALGRADIENT (paintserver)) {
+ SPRadialGradient *rg=SP_RADIALGRADIENT(paintserver);
+
+ SP_GRADIENT(rg)->ensureVector(); // when exporting from commandline, vector is not built
+ double r = rg->r.computed;
+
+ Geom::Point c (rg->cx.computed, rg->cy.computed);
+ Geom::Point xhandle_point(r, 0);
+ Geom::Point yhandle_point(0, -r);
+ yhandle_point += c;
+ xhandle_point += c;
+ if (rg->gradientTransform_set) {
+ c = c * rg->gradientTransform;
+ yhandle_point = yhandle_point * rg->gradientTransform;
+ xhandle_point = xhandle_point * rg->gradientTransform;
+ }
+ hatchColor = avg_stop_color(rg);
+ }
+ else {
+ // default fill
+ }
}
else if(style->stroke.isColor()){ // test last, always seems to be set, even for other types above
- sp_color_get_rgb_floatv( &style->stroke.value.color, rgb );
- brushStyle = U_BS_SOLID;
- hatchColor = U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]);
- hatchType = U_HS_SOLIDCLR;
+ sp_color_get_rgb_floatv( &style->stroke.value.color, rgb );
+ brushStyle = U_BS_SOLID;
+ hatchColor = U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]);
+ hatchType = U_HS_SOLIDCLR;
}
else {
- // default fill
+ // default fill
}
@@ -933,50 +974,36 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform)
if(!style->stroke_width.computed){return 0;} //if width is 0 do not (reset) the pen, it should already be NULL_PEN
uint32_t linewidth = MAX( 1, (uint32_t) (scale * style->stroke_width.computed * PX2WORLD) );
- if (style->stroke_linecap.computed == 0) {
- linecap = U_PS_ENDCAP_FLAT;
- }
- else if (style->stroke_linecap.computed == 1) {
- linecap = U_PS_ENDCAP_ROUND;
- }
- else if (style->stroke_linecap.computed == 2) {
- linecap = U_PS_ENDCAP_SQUARE;
- }
+ if ( style->stroke_linecap.computed == 0){ linecap = U_PS_ENDCAP_FLAT; }
+ else if (style->stroke_linecap.computed == 1){ linecap = U_PS_ENDCAP_ROUND; }
+ else if (style->stroke_linecap.computed == 2){ linecap = U_PS_ENDCAP_SQUARE; }
- if (style->stroke_linejoin.computed == 0) {
- linejoin = U_PS_JOIN_MITER;
- }
- else if (style->stroke_linejoin.computed == 1) {
- linejoin = U_PS_JOIN_ROUND;
- }
- else if (style->stroke_linejoin.computed == 2) {
- linejoin = U_PS_JOIN_BEVEL;
- }
+ if ( style->stroke_linejoin.computed == 0){ linejoin = U_PS_JOIN_MITER; }
+ else if (style->stroke_linejoin.computed == 1){ linejoin = U_PS_JOIN_ROUND; }
+ else if (style->stroke_linejoin.computed == 2){ linejoin = U_PS_JOIN_BEVEL; }
if (style->stroke_dash.n_dash &&
style->stroke_dash.dash )
{
if(FixPPTDashLine){ // will break up line into many smaller lines. Override gradient if that was set, cannot do both.
- brushStyle = U_BS_SOLID;
- hatchType = U_HS_HORIZONTAL;
+ brushStyle = U_BS_SOLID;
+ hatchType = U_HS_HORIZONTAL;
}
else {
- int i = 0;
- while (linestyle != U_PS_USERSTYLE &&
- (i < style->stroke_dash.n_dash)) {
- if (style->stroke_dash.dash[i] > 0.00000001)
- linestyle = U_PS_USERSTYLE;
- i++;
- }
-
- if (linestyle == U_PS_USERSTYLE) {
- 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]);
- }
- }
- }
+ int i = 0;
+ while ( (linestyle != U_PS_USERSTYLE) && (i < style->stroke_dash.n_dash) ){
+ if (style->stroke_dash.dash[i] > 0.00000001){ linestyle = U_PS_USERSTYLE; }
+ i++;
+ }
+
+ if (linestyle == U_PS_USERSTYLE) {
+ 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]);
+ }
+ }
+ }
}
elp = extlogpen_set(
@@ -1002,16 +1029,16 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform)
}
rec = extcreatepen_set(&pen, eht, Bmi, cbPx, px, elp );
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::create_pen at extcreatepen_set";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::create_pen at extcreatepen_set");
}
free(elp);
if(Bmi)free(Bmi);
if(px)free(px); // ct will always be NULL
rec = selectobject_set(pen, eht);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::create_pen at selectobject_set";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::create_pen at selectobject_set");
}
hpen = pen; // need this later for destroy_pen
@@ -1021,45 +1048,39 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform)
if (miterlimit < 1)miterlimit = 1;
rec = U_EMRSETMITERLIMIT_set((uint32_t) miterlimit);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::create_pen at U_EMRSETMITERLIMIT_set";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::create_pen at U_EMRSETMITERLIMIT_set");
}
}
- if (n_dash) {
- delete[] dash;
- }
+ if (n_dash) { delete[] dash; }
return 0;
-// std::cout << "end create_pen" << std::endl;
}
// set the current pen to the stock object NULL_PEN and then delete the defined pen object, if there is one.
void PrintEmf::destroy_pen()
{
-// std::cout << "destroy_pen hpen: " << hpen<< std::endl;
char *rec = NULL;
// before an object may be safely deleted it must no longer be selected
// select in a stock object to deselect this one, the stock object should
// never be used because we always select in a new one before drawing anythingrestore previous brush, necessary??? Would using a default stock object not work?
rec = selectobject_set(U_NULL_PEN, eht);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::destroy_pen at selectobject_set";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::destroy_pen at selectobject_set");
}
if (hpen){
- rec = deleteobject_set(&hpen, eht);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::destroy_pen";
- }
- hpen = 0;
+ rec = deleteobject_set(&hpen, eht);
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::destroy_pen");
+ }
+ hpen = 0;
}
-// std::cout << "end destroy_pen " << std::endl;
}
unsigned int PrintEmf::bind(Inkscape::Extension::Print * /*mod*/, Geom::Affine const &transform, float /*opacity*/)
{
-// std::cout << "bind " << std::endl;
if (!m_tr_stack.empty()) {
Geom::Affine tr_top = m_tr_stack.top();
m_tr_stack.push(transform * tr_top);
@@ -1067,15 +1088,12 @@ unsigned int PrintEmf::bind(Inkscape::Extension::Print * /*mod*/, Geom::Affine c
m_tr_stack.push(transform);
}
-// std::cout << "end bind" << std::endl;
return 1;
}
unsigned int PrintEmf::release(Inkscape::Extension::Print * /*mod*/)
{
-// std::cout << "release " << std::endl;
m_tr_stack.pop();
-// std::cout << "end release" << std::endl;
return 1;
}
@@ -1108,24 +1126,24 @@ U_COLORREF PrintEmf::weight_colors(U_COLORREF c1, U_COLORREF c2, double t){
/* convert from center ellipse to SVGEllipticalArc ellipse
- From:
- http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
- A point (x,y) on the arc can be found by:
-
- {x,y} = {cx,cy} + {cosF,-sinF,sinF,cosF} x {rxcosT,rysinT}
-
- where
- {cx,cy} is the center of the ellipse
- F is the rotation angle of the X axis of the ellipse from the true X axis
- T is the rotation angle around the ellipse
- {,,,} is the rotation matrix
- rx,ry are the radii of the ellipse's axes
+ From:
+ http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
+ A point (x,y) on the arc can be found by:
- For SVG parameterization need two points.
- Arbitrarily we can use T=0 and T=pi
- Since the sweep is 180 the flags are always 0:
+ {x,y} = {cx,cy} + {cosF,-sinF,sinF,cosF} x {rxcosT,rysinT}
- F is in RADIANS, but the SVGEllipticalArc needs degrees!
+ where
+ {cx,cy} is the center of the ellipse
+ F is the rotation angle of the X axis of the ellipse from the true X axis
+ T is the rotation angle around the ellipse
+ {,,,} is the rotation matrix
+ rx,ry are the radii of the ellipse's axes
+
+ For SVG parameterization need two points.
+ Arbitrarily we can use T=0 and T=pi
+ Since the sweep is 180 the flags are always 0:
+
+ F is in RADIANS, but the SVGEllipticalArc needs degrees!
*/
Geom::PathVector PrintEmf::center_ellipse_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F){
@@ -1212,26 +1230,22 @@ Geom::PathVector PrintEmf::rect_cutter(Geom::Point ctr, Geom::Point pos, Geom::P
return outres;
}
-/* Convert from SPWindRule to livarot's FillRule
- This is similar to what sp_selected_path_boolop() does
+/* Convert from SPWindRule to livarot's FillRule
+ This is similar to what sp_selected_path_boolop() does
*/
FillRule PrintEmf::SPWR_to_LVFR(SPWindRule wr){
FillRule fr;
- if(wr == SP_WIND_RULE_EVENODD){
- fr = fill_oddEven;
- }
- else {
- fr = fill_nonZero;
- }
+ if(wr == SP_WIND_RULE_EVENODD){ fr = fill_oddEven; }
+ else { fr = fill_nonZero; }
return fr;
}
-unsigned int PrintEmf::fill(Inkscape::Extension::Print * /*mod*/,
- Geom::PathVector const &pathv, Geom::Affine const & /*transform*/, SPStyle const *style,
- Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/)
+unsigned int PrintEmf::fill(
+ Inkscape::Extension::Print * /*mod*/,
+ Geom::PathVector const &pathv, Geom::Affine const & /*transform*/, SPStyle const *style,
+ Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/)
{
-// std::cout << "fill " << std::endl;
using Geom::X;
using Geom::Y;
@@ -1243,186 +1257,184 @@ unsigned int PrintEmf::fill(Inkscape::Extension::Print * /*mod*/,
fill_transform = tf;
if (create_brush(style, NULL)){ // 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.
-
- The overlap is needed to avoid antialiasing artifacts when edges are not strictly aligned on pixel boundaries.
- There is an inevitable loss of accuracy saving through an EMF file because of the integer coordinate system.
- Keep the overlap quite large so that loss of accuracy does not remove an overlap.
- */
- destroy_pen(); //this sets the NULL_PEN, otherwise gradient slices may display with boundaries, see longer explanation below
- Geom::Path cutter;
- float rgb[3];
- U_COLORREF wc,c1,c2;
- FillRule frb = SPWR_to_LVFR( (SPWindRule) style->fill_rule.computed);
- double doff,doff_base,doff_range;
- double divisions= 128.0;
- int nstops;
- int istop = 1;
- float opa; // opacity at stop
-
- 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;
- 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;
- c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa );
-
- doff = 0.0;
- doff_base = 0.0;
- doff_range = tg->vector.stops[1].offset; // next or last stop
-
- if(gv.mode==DRAW_RADIAL_GRADIENT){
- Geom::Point xv = gv.p2 - gv.p1; // X' vector
- Geom::Point yv = gv.p3 - gv.p1; // Y' vector
- Geom::Point xuv = Geom::unit_vector(xv); // X' unit vector
- double rx = hypot(xv[X],xv[Y]);
- double ry = hypot(yv[X],yv[Y]);
- double range = fmax(rx,ry); // 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;
-
- /* radial gradient might stop part way through the shape, fill with outer color from there to "infinity".
- Do this first so that outer colored ring will overlay it.
- */
- pathvc = center_elliptical_hole_as_SVG_PathV(gv.p1, rx*(1.0 - overlap/range), ry*(1.0 - overlap/range), asin(xuv[Y]));
- pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_oddEven, frb);
- wc = weight_opacity(c2);
- (void) create_brush(style, &wc);
- print_pathv(pathvr, fill_transform);
-
- 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;
- wc = weight_colors(c1, c2, (doff - doff_base)/(doff_range-doff_base) );
- (void) create_brush(style, &wc);
-
- pathvc = center_elliptical_ring_as_SVG_PathV(gv.p1, rx*start/range, ry*start/range, rx*stop/range, ry*stop/range, asin(xuv[Y]));
-
- 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){
- istop++;
- if(istop >= nstops)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 );
- }
- }
-
- }
- 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);
-
- 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 - doff_base){
- istop++;
- if(istop >= nstops)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 );
- }
- }
- }
- else {
- throw "Fatal programming error in PrintEmf::fill, invalid gradient type detected";
- }
- use_fill = false; // gradients handled, be sure stroke does not use stroke and fill
+ /*
+ Handle gradients. Uses modified livarot as 2geom boolops is currently broken.
+ Can handle gradients with multiple stops.
+
+ The overlap is needed to avoid antialiasing artifacts when edges are not strictly aligned on pixel boundaries.
+ There is an inevitable loss of accuracy saving through an EMF file because of the integer coordinate system.
+ Keep the overlap quite large so that loss of accuracy does not remove an overlap.
+ */
+ destroy_pen(); //this sets the NULL_PEN, otherwise gradient slices may display with boundaries, see longer explanation below
+ Geom::Path cutter;
+ float rgb[3];
+ U_COLORREF wc,c1,c2;
+ FillRule frb = SPWR_to_LVFR( (SPWindRule) style->fill_rule.computed);
+ double doff,doff_base,doff_range;
+ double divisions= 128.0;
+ int nstops;
+ int istop = 1;
+ float opa; // opacity at stop
+
+ 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;
+ 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;
+ c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa );
+
+ doff = 0.0;
+ doff_base = 0.0;
+ doff_range = tg->vector.stops[1].offset; // next or last stop
+
+ if(gv.mode==DRAW_RADIAL_GRADIENT){
+ Geom::Point xv = gv.p2 - gv.p1; // X' vector
+ Geom::Point yv = gv.p3 - gv.p1; // Y' vector
+ Geom::Point xuv = Geom::unit_vector(xv); // X' unit vector
+ double rx = hypot(xv[X],xv[Y]);
+ double ry = hypot(yv[X],yv[Y]);
+ double range = fmax(rx,ry); // 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;
+
+ /* radial gradient might stop part way through the shape, fill with outer color from there to "infinity".
+ Do this first so that outer colored ring will overlay it.
+ */
+ pathvc = center_elliptical_hole_as_SVG_PathV(gv.p1, rx*(1.0 - overlap/range), ry*(1.0 - overlap/range), asin(xuv[Y]));
+ pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_oddEven, frb);
+ wc = weight_opacity(c2);
+ (void) create_brush(style, &wc);
+ print_pathv(pathvr, fill_transform);
+
+ 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;
+ wc = weight_colors(c1, c2, (doff - doff_base)/(doff_range-doff_base) );
+ (void) create_brush(style, &wc);
+
+ pathvc = center_elliptical_ring_as_SVG_PathV(gv.p1, rx*start/range, ry*start/range, rx*stop/range, ry*stop/range, asin(xuv[Y]));
+
+ 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){
+ istop++;
+ if(istop >= nstops)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 );
+ }
+ }
+ }
+ 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);
+
+ 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 - doff_base){
+ istop++;
+ if(istop >= nstops)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 );
+ }
+ }
+ }
+ else {
+ g_error("Fatal programming error in PrintEmf::fill, invalid gradient type detected");
+ }
+ use_fill = false; // gradients handled, be sure stroke does not use stroke and fill
}
else {
- /*
- Inkscape was not calling create_pen for objects with no border.
- This was because it never called stroke() (next method).
- PPT, and presumably others, pick whatever they want for the border if it is not specified, so no border can
- become a visible border.
- To avoid this force the pen to NULL_PEN if we can determine that no pen will be needed after the fill.
- */
- if (style->stroke.noneSet || style->stroke_width.computed == 0.0){
- destroy_pen(); //this sets the NULL_PEN
- }
+ /*
+ Inkscape was not calling create_pen for objects with no border.
+ This was because it never called stroke() (next method).
+ PPT, and presumably others, pick whatever they want for the border if it is not specified, so no border can
+ become a visible border.
+ To avoid this force the pen to NULL_PEN if we can determine that no pen will be needed after the fill.
+ */
+ if (style->stroke.noneSet || style->stroke_width.computed == 0.0){
+ destroy_pen(); //this sets the NULL_PEN
+ }
- /* postpone fill in case stroke also required AND all stroke paths closed
- Dashes converted to line segments will "open" a closed path.
- */
- bool all_closed = true;
- for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit){
- for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit){
- if (pit->end_default() != pit->end_closed()) { all_closed=false; }
- }
- }
- if (
+ /* postpone fill in case stroke also required AND all stroke paths closed
+ Dashes converted to line segments will "open" a closed path.
+ */
+ bool all_closed = true;
+ for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit){
+ for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit){
+ if (pit->end_default() != pit->end_closed()) { all_closed=false; }
+ }
+ }
+ if (
(style->stroke.noneSet || style->stroke_width.computed == 0.0) ||
(style->stroke_dash.n_dash && style->stroke_dash.dash && FixPPTDashLine) ||
!all_closed
- )
- {
- print_pathv(pathv, fill_transform); // do any fills. side effect: clears fill_pathv
- use_fill = false;
- }
+ ){
+ print_pathv(pathv, fill_transform); // do any fills. side effect: clears fill_pathv
+ use_fill = false;
+ }
}
-// std::cout << "end fill" << std::endl;
return 0;
}
-unsigned int PrintEmf::stroke (Inkscape::Extension::Print * /*mod*/,
- Geom::PathVector const &pathv, const Geom::Affine &/*transform*/, const SPStyle *style,
- Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/)
+unsigned int PrintEmf::stroke (
+ Inkscape::Extension::Print * /*mod*/,
+ Geom::PathVector const &pathv, const Geom::Affine &/*transform*/, const SPStyle *style,
+ Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/)
{
-// std::cout << "stroke " << std::endl;
+ char *rec = NULL;
Geom::Affine tf = m_tr_stack.top();
use_stroke = true;
@@ -1431,46 +1443,52 @@ unsigned int PrintEmf::stroke (Inkscape::Extension::Print * /*mod*/,
if (create_pen(style, tf))return 0;
if (style->stroke_dash.n_dash && style->stroke_dash.dash && FixPPTDashLine ){
- // convert the path, gets its complete length, and then make a new path with parameter length instead of t
- Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw; // pathv-> sbasis
- Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw2; // sbasis using arc length parameter
- Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw3; // new (discontinuous) path, composed of dots/dashes
- Geom::Piecewise<Geom::D2<Geom::SBasis> > first_frag; // first fragment, will be appended at end
- int n_dash = style->stroke_dash.n_dash;
- int i=0; //dash index
- double tlength; // length of tmp_pathpw
- double slength=0.0; // start of gragment
- double elength; // end of gragment
- for (unsigned int i=0; i < pathv.size(); i++) {
- tmp_pathpw.concat(pathv[i].toPwSb());
- }
- tlength = length(tmp_pathpw,0.1);
- tmp_pathpw2 = arc_length_parametrization(tmp_pathpw);
-
- // go around the dash array repeatedly until the entire path is consumed (but not beyond).
- while(slength < tlength){
- elength = slength + style->stroke_dash.dash[i++];
- if(elength > tlength)elength = tlength;
- Geom::Piecewise<Geom::D2<Geom::SBasis> > fragment(portion(tmp_pathpw2, slength, elength));
- if(slength){ tmp_pathpw3.concat(fragment); }
- else { first_frag = fragment; }
- slength = elength;
- slength += style->stroke_dash.dash[i++]; // the gap
- if(i>=n_dash)i=0;
- }
- tmp_pathpw3.concat(first_frag); // may merge line around start point
- Geom::PathVector out_pathv = Geom::path_from_piecewise(tmp_pathpw3, 0.01);
- print_pathv(out_pathv, tf);
+ // convert the path, gets its complete length, and then make a new path with parameter length instead of t
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw; // pathv-> sbasis
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw2; // sbasis using arc length parameter
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw3; // new (discontinuous) path, composed of dots/dashes
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > first_frag; // first fragment, will be appended at end
+ int n_dash = style->stroke_dash.n_dash;
+ int i=0; //dash index
+ double tlength; // length of tmp_pathpw
+ double slength=0.0; // start of gragment
+ double elength; // end of gragment
+ for (unsigned int i=0; i < pathv.size(); i++) {
+ tmp_pathpw.concat(pathv[i].toPwSb());
+ }
+ tlength = length(tmp_pathpw,0.1);
+ tmp_pathpw2 = arc_length_parametrization(tmp_pathpw);
+
+ // go around the dash array repeatedly until the entire path is consumed (but not beyond).
+ while(slength < tlength){
+ elength = slength + style->stroke_dash.dash[i++];
+ if(elength > tlength)elength = tlength;
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > fragment(portion(tmp_pathpw2, slength, elength));
+ if(slength){ tmp_pathpw3.concat(fragment); }
+ else { first_frag = fragment; }
+ slength = elength;
+ slength += style->stroke_dash.dash[i++]; // the gap
+ if(i>=n_dash)i=0;
+ }
+ tmp_pathpw3.concat(first_frag); // may merge line around start point
+ Geom::PathVector out_pathv = Geom::path_from_piecewise(tmp_pathpw3, 0.01);
+ print_pathv(out_pathv, tf);
}
else {
- print_pathv(pathv, tf);
+ print_pathv(pathv, tf);
}
use_stroke = false;
use_fill = false;
+ if(usebk){ // OPAQUE was set, revert to TRANSPARENT
+ usebk = false;
+ rec = U_EMRSETBKMODE_set(U_TRANSPARENT);
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::stroke at U_EMRSETBKMODE_set");
+ }
+ }
-// std::cout << "end stroke " << std::endl;
return 0;
}
@@ -1480,7 +1498,6 @@ unsigned int PrintEmf::stroke (Inkscape::Extension::Print * /*mod*/,
// For other paths it sets a few flags and returns.
bool PrintEmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Affine &transform)
{
-// std::cout << "print_simple_shape " << std::endl <<std::flush;
Geom::PathVector pv = pathv_to_linear_and_cubic_beziers( pathv * transform );
@@ -1528,8 +1545,8 @@ bool PrintEmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff
p0[X] = (p0[X] * PX2WORLD);
p0[Y] = (p0[Y] * PX2WORLD);
- int32_t const x0 = static_cast<int32_t>(round(p0[X]));
- int32_t const y0 = static_cast<int32_t>( round(p0[Y]));
+ int32_t const x0 = (int32_t) round(p0[X]);
+ int32_t const y0 = (int32_t) round(p0[Y]);
lpPoints[i].x = x0;
lpPoints[i].y = y0;
@@ -1550,10 +1567,10 @@ bool PrintEmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff
//p0[Y] = (p0[Y] * PX2WORLD);
p1[Y] = (p1[Y] * PX2WORLD);
- //int32_t const x0 = static_cast<int32_t>(round(p0[X]));
- //int32_t const y0 = static_cast<int32_t>(round(p0[Y]));
- int32_t const x1 = static_cast<int32_t>(round(p1[X]));
- int32_t const y1 = static_cast<int32_t>(round(p1[Y]));
+ //int32_t const x0 = (int32_t) round(p0[X]);
+ //int32_t const y0 = (int32_t) round(p0[Y]);
+ int32_t const x1 = (int32_t) round(p1[X]);
+ int32_t const y1 = (int32_t) round(p1[Y]);
lpPoints[i].x = x1;
lpPoints[i].y = y1;
@@ -1576,14 +1593,14 @@ bool PrintEmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff
p2[Y] = (p2[Y] * PX2WORLD);
p3[Y] = (p3[Y] * PX2WORLD);
- //int32_t const x0 = static_cast<int32_t>(round(p0[X]));
- //int32_t const y0 = static_cast<int32_t>(round(p0[Y]));
- int32_t const x1 = static_cast<int32_t>(round(p1[X]));
- int32_t const y1 = static_cast<int32_t>(round(p1[Y]));
- int32_t const x2 = static_cast<int32_t>(round(p2[X]));
- int32_t const y2 = static_cast<int32_t>(round(p2[Y]));
- int32_t const x3 = static_cast<int32_t>(round(p3[X]));
- int32_t const y3 = static_cast<int32_t>(round(p3[Y]));
+ //int32_t const x0 = (int32_t) round(p0[X]);
+ //int32_t const y0 = (int32_t) round(p0[Y]);
+ int32_t const x1 = (int32_t) round(p1[X]);
+ int32_t const y1 = (int32_t) round(p1[Y]);
+ int32_t const x2 = (int32_t) round(p2[X]);
+ int32_t const y2 = (int32_t) round(p2[Y]);
+ int32_t const x3 = (int32_t) round(p3[X]);
+ int32_t const y3 = (int32_t) round(p3[Y]);
lpPoints[i].x = x1;
lpPoints[i].y = y1;
@@ -1628,115 +1645,113 @@ bool PrintEmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff
if (use_fill && !use_stroke) { // only fill
rec = selectobject_set(U_NULL_PEN, eht);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::print_simple_shape at selectobject_set pen";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::print_simple_shape at selectobject_set pen");
}
}
else if(!use_fill && use_stroke) { // only stroke
rec = selectobject_set(U_NULL_BRUSH, eht);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::print_simple_shape at selectobject_set brush";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::print_simple_shape at selectobject_set brush");
}
}
if (polygon) {
if (rectangle){
- U_RECTL rcl = rectl_set((U_POINTL) {lpPoints[0].x, lpPoints[0].y}, (U_POINTL) {lpPoints[2].x, lpPoints[2].y});
- rec = U_EMRRECTANGLE_set(rcl);
+ U_RECTL rcl = rectl_set((U_POINTL) {lpPoints[0].x, lpPoints[0].y}, (U_POINTL) {lpPoints[2].x, lpPoints[2].y});
+ rec = U_EMRRECTANGLE_set(rcl);
}
else {
- rec = U_EMRPOLYGON_set(U_RCL_DEF, nodes, lpPoints);
+ rec = U_EMRPOLYGON_set(U_RCL_DEF, nodes, lpPoints);
}
}
else if (ellipse) {
U_RECTL rcl = rectl_set((U_POINTL) {lpPoints[6].x, lpPoints[3].y}, (U_POINTL) {lpPoints[0].x, lpPoints[9].y});
rec = U_EMRELLIPSE_set(rcl);
}
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::print_simple_shape at retangle/ellipse/polygon";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::print_simple_shape at retangle/ellipse/polygon");
}
done = true;
// replace the handle we moved above, assuming there was something set already
if (use_fill && !use_stroke && hpen) { // only fill
- rec = selectobject_set(hpen, eht);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::print_simple_shape at selectobject_set pen";
- }
+ rec = selectobject_set(hpen, eht);
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::print_simple_shape at selectobject_set pen");
+ }
}
else if (!use_fill && use_stroke && hbrush){ // only stroke
- rec = selectobject_set(hbrush, eht);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::print_simple_shape at selectobject_set brush";
- }
+ rec = selectobject_set(hbrush, eht);
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::print_simple_shape at selectobject_set brush");
+ }
}
-
}
delete[] lpPoints;
-// std::cout << "end simple_shape " << std::endl;
return done;
}
/** Some parts based on win32.cpp by Lauris Kaplinski <lauris@kaplinski.com>. Was a part of Inkscape
- in the past (or will be in the future?) Not in current trunk. (4/19/2012)
+ in the past (or will be in the future?) Not in current trunk. (4/19/2012)
- Limitations of this code:
- 1. Transparency is lost on export. (Apparently a limitation of the EMF format.)
- 2. Probably messes up if row stride != w*4
- 3. There is still a small memory leak somewhere, possibly in a pixbuf created in a routine
- that calls this one and passes px, but never removes the rest of the pixbuf. The first time
- this is called it leaked 5M (in one test) and each subsequent call leaked around 200K more.
- If this routine is reduced to
- if(1)return(0);
- and called for a single 1280 x 1024 image then the program leaks 11M per call, or roughly the
- size of two bitmaps.
+ Limitations of this code:
+ 1. Transparency is lost on export. (Apparently a limitation of the EMF format.)
+ 2. Probably messes up if row stride != w*4
+ 3. There is still a small memory leak somewhere, possibly in a pixbuf created in a routine
+ that calls this one and passes px, but never removes the rest of the pixbuf. The first time
+ this is called it leaked 5M (in one test) and each subsequent call leaked around 200K more.
+ If this routine is reduced to
+ if(1)return(0);
+ and called for a single 1280 x 1024 image then the program leaks 11M per call, or roughly the
+ size of two bitmaps.
*/
-unsigned int PrintEmf::image(Inkscape::Extension::Print * /* module */, /** not used */
- unsigned char *rgba_px, /** array of pixel values, Gdk::Pixbuf bitmap format */
- unsigned int w, /** width of bitmap */
- unsigned int h, /** height of bitmap */
- unsigned int rs, /** row stride (normally w*4) */
- Geom::Affine const &/*tf_ignore*/, /** WRONG affine transform, use the one from m_tr_stack */
- SPStyle const *style) /** provides indirect link to image object */
+unsigned int PrintEmf::image(
+ Inkscape::Extension::Print * /* module */, /** not used */
+ unsigned char *rgba_px, /** array of pixel values, Gdk::Pixbuf bitmap format */
+ unsigned int w, /** width of bitmap */
+ unsigned int h, /** height of bitmap */
+ unsigned int rs, /** row stride (normally w*4) */
+ Geom::Affine const &tf_ignore, /** WRONG affine transform, use the one from m_tr_stack */
+ SPStyle const *style) /** provides indirect link to image object */
{
-// std::cout << "image " << std::endl;
- double x1,y1,dw,dh;
- char *rec = NULL;
- Geom::Affine tf = m_tr_stack.top();
-
- rec = U_EMRSETSTRETCHBLTMODE_set(U_COLORONCOLOR);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::image at EMRHEADER";
- }
-
- x1= atof(style->object->getAttribute("x"));
- y1= atof(style->object->getAttribute("y"));
- dw= atof(style->object->getAttribute("width"));
- dh= atof(style->object->getAttribute("height"));
- Geom::Point pLL(x1,y1);
- Geom::Point pLL2 = pLL * tf; //location of LL corner in Inkscape coordinates
-
- char *px;
- uint32_t cbPx;
- uint32_t colortype;
- PU_RGBQUAD ct;
- int numCt;
- U_BITMAPINFOHEADER Bmih;
- PU_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);
- Bmi = bitmapinfo_set(Bmih, ct);
-
- U_POINTL Dest = pointl_set(round(pLL2[Geom::X] * PX2WORLD), round(pLL2[Geom::Y] * PX2WORLD));
- 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);
- if(!FixImageRot){ /* Rotate images - some programs cannot read them in correctly if they are rotated */
+ double x1,y1,dw,dh;
+ char *rec = NULL;
+ Geom::Affine tf = m_tr_stack.top();
+
+ rec = U_EMRSETSTRETCHBLTMODE_set(U_COLORONCOLOR);
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::image at EMRHEADER");
+ }
+
+ x1= atof(style->object->getAttribute("x"));
+ y1= atof(style->object->getAttribute("y"));
+ dw= atof(style->object->getAttribute("width"));
+ dh= atof(style->object->getAttribute("height"));
+ Geom::Point pLL(x1,y1);
+ Geom::Point pLL2 = pLL * tf; //location of LL corner in Inkscape coordinates
+
+ char *px;
+ uint32_t cbPx;
+ uint32_t colortype;
+ PU_RGBQUAD ct;
+ int numCt;
+ U_BITMAPINFOHEADER Bmih;
+ PU_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);
+ Bmi = bitmapinfo_set(Bmih, ct);
+
+ U_POINTL Dest = pointl_set(round(pLL2[Geom::X] * PX2WORLD), round(pLL2[Geom::Y] * PX2WORLD));
+ 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);
+ 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;
U_XFORM tmpTransform;
@@ -1748,70 +1763,66 @@ unsigned int PrintEmf::image(Inkscape::Extension::Print * /* module */, /** not
tmpTransform.eDy = (pLL2[Geom::Y] - pLL2prime[Geom::Y]) * PX2WORLD;
rec=U_EMRSAVEDC_set();
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::begin at 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");
}
-
rec = U_EMRMODIFYWORLDTRANSFORM_set(tmpTransform, U_MWT_LEFTMULTIPLY);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::begin at EMRMODIFYWORLDTRANSFORM";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::image at EMRMODIFYWORLDTRANSFORM");
}
-
- }
- rec = U_EMRSTRETCHDIBITS_set(
- U_RCL_DEF, //! Bounding rectangle in device units
- Dest, //! Destination UL corner in logical units
- cDest, //! Destination W & H in logical units
- Src, //! Source UL corner in logical units
- cSrc, //! Source W & H in logical units
- U_DIB_RGB_COLORS, //! DIBColors Enumeration
- U_SRCCOPY, //! RasterOPeration Enumeration
- Bmi, //! (Optional) bitmapbuffer (U_BITMAPINFO section)
- h*rs, //! size in bytes of px
- px //! (Optional) bitmapbuffer (U_BITMAPINFO section)
- );
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::image at U_EMRSTRETCHDIBITS_set";
- }
- free(px);
- free(Bmi);
- if(numCt)free(ct);
-
- if(!FixImageRot){
- rec=U_EMRRESTOREDC_set(-1);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::begin at U_EMRRESTOREDC_set";
- }
- }
+ }
+ rec = U_EMRSTRETCHDIBITS_set(
+ U_RCL_DEF, //! Bounding rectangle in device units
+ Dest, //! Destination UL corner in logical units
+ cDest, //! Destination W & H in logical units
+ Src, //! Source UL corner in logical units
+ cSrc, //! Source W & H in logical units
+ U_DIB_RGB_COLORS, //! DIBColors Enumeration
+ U_SRCCOPY, //! RasterOPeration Enumeration
+ Bmi, //! (Optional) bitmapbuffer (U_BITMAPINFO section)
+ h*rs, //! size in bytes of px
+ px //! (Optional) bitmapbuffer (U_BITMAPINFO section)
+ );
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::image at U_EMRSTRETCHDIBITS_set");
+ }
+ free(px);
+ free(Bmi);
+ if(numCt)free(ct);
+
+ if(!FixImageRot){
+ rec=U_EMRRESTOREDC_set(-1);
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::image at U_EMRRESTOREDC_set");
+ }
+ }
-// std::cout << "end image" << std::endl;
- return 0;
+ return 0;
}
// may also be called with a simple_shape or an empty path, whereupon it just returns without doing anything
unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Affine &transform)
{
-// std::cout << "print_pathv " << std::endl << std::flush;
Geom::Affine tf = transform;
char *rec = NULL;
simple_shape = print_simple_shape(pathv, tf);
if (simple_shape || pathv.empty()){
- if (use_fill){ destroy_brush(); } // these must be cleared even if nothing is drawn or hbrush,hpen fill up
- if (use_stroke){ destroy_pen(); }
- return TRUE;
+ if (use_fill){ destroy_brush(); } // these must be cleared even if nothing is drawn or hbrush,hpen fill up
+ if (use_stroke){ destroy_pen(); }
+ return TRUE;
}
- /* inkscape to EMF scaling is done below, but NOT the rotation/translation transform,
- that is handled by the EMF MODIFYWORLDTRANSFORM record
+ /* inkscape to EMF scaling is done below, but NOT the rotation/translation transform,
+ that is handled by the EMF MODIFYWORLDTRANSFORM record
*/
Geom::PathVector pv = pathv_to_linear_and_cubic_beziers( pathv * tf );
rec = U_EMRBEGINPATH_set();
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::print_pathv at U_EMRBEGINPATH_set";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRBEGINPATH_set");
}
/**
@@ -1828,10 +1839,10 @@ unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af
p0[X] = (p0[X] * PX2WORLD);
p0[Y] = (p0[Y] * PX2WORLD);
- U_POINTL ptl = pointl_set(static_cast<int32_t>(round(p0[X])), static_cast<int32_t>(round(p0[Y])));
+ U_POINTL ptl = pointl_set((int32_t) round(p0[X]), (int32_t) round(p0[Y]));
rec = U_EMRMOVETOEX_set(ptl);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::print_pathv at U_EMRMOVETOEX_set";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRMOVETOEX_set");
}
/**
@@ -1849,13 +1860,13 @@ unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af
//p0[Y] = (p0[Y] * PX2WORLD);
p1[Y] = (p1[Y] * PX2WORLD);
- //int32_t const x0 = static_cast<int32_t>(round(p0[X]));
- //int32_t const y0 = static_cast<int32_t>(round(p0[Y]));
+ //int32_t const x0 = (int32_t) round(p0[X]);
+ //int32_t const y0 = (int32_t) round(p0[Y]);
- ptl = pointl_set(static_cast<int32_t>(round(p1[X])), static_cast<int32_t>(round(p1[Y])));
+ ptl = pointl_set((int32_t) round(p1[X]), (int32_t) round(p1[Y]));
rec = U_EMRLINETO_set(ptl);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::print_pathv at U_EMRLINETO_set";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRLINETO_set");
}
}
else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit))
@@ -1875,14 +1886,14 @@ unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af
p2[Y] = (p2[Y] * PX2WORLD);
p3[Y] = (p3[Y] * PX2WORLD);
- //int32_t const x0 = static_cast<int32_t>(round(p0[X]));
- //int32_t const y0 = static_cast<int32_t>(round(p0[Y]));
- int32_t const x1 = static_cast<int32_t>(round(p1[X]));
- int32_t const y1 = static_cast<int32_t>(round(p1[Y]));
- int32_t const x2 = static_cast<int32_t>(round(p2[X]));
- int32_t const y2 = static_cast<int32_t>(round(p2[Y]));
- int32_t const x3 = static_cast<int32_t>(round(p3[X]));
- int32_t const y3 = static_cast<int32_t>(round(p3[Y]));
+ //int32_t const x0 = (int32_t) round(p0[X]);
+ //int32_t const y0 = (int32_t) round(p0[Y]);
+ int32_t const x1 = (int32_t) round(p1[X]);
+ int32_t const y1 = (int32_t) round(p1[Y]);
+ int32_t const x2 = (int32_t) round(p2[X]);
+ int32_t const y2 = (int32_t) round(p2[Y]);
+ int32_t const x3 = (int32_t) round(p3[X]);
+ int32_t const y3 = (int32_t) round(p3[Y]);
U_POINTL pt[3];
pt[0].x = x1;
@@ -1893,8 +1904,8 @@ unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af
pt[2].y = y3;
rec = U_EMRPOLYBEZIERTO_set(U_RCL_DEF, 3, pt);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::print_pathv at U_EMRPOLYBEZIERTO_set";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRPOLYBEZIERTO_set");
}
}
else
@@ -1905,35 +1916,35 @@ unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af
if (pit->end_default() == pit->end_closed()) { // there may be multiples of this on a single path
rec = U_EMRCLOSEFIGURE_set();
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::print_pathv at U_EMRCLOSEFIGURE_set";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRCLOSEFIGURE_set");
}
}
}
rec = U_EMRENDPATH_set(); // there may be only be one of these on a single path
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::print_pathv at U_EMRENDPATH_set";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRENDPATH_set");
}
// explicit FILL/STROKE commands are needed for each sub section of the path
if (use_fill && !use_stroke){
rec = U_EMRFILLPATH_set(U_RCL_DEF);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::fill at U_EMRFILLPATH_set";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::fill at U_EMRFILLPATH_set");
}
}
else if (use_fill && use_stroke) {
rec = U_EMRSTROKEANDFILLPATH_set(U_RCL_DEF);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::stroke at U_EMRSTROKEANDFILLPATH_set";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::stroke at U_EMRSTROKEANDFILLPATH_set");
}
}
else if (!use_fill && use_stroke){
rec = U_EMRSTROKEPATH_set(U_RCL_DEF);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::stroke at U_EMRSTROKEPATH_set";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::stroke at U_EMRSTROKEPATH_set");
}
}
@@ -1945,8 +1956,6 @@ unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af
destroy_pen();
}
-// std::cout << "end pathv" << std::endl;
-
return TRUE;
}
@@ -1959,7 +1968,6 @@ bool PrintEmf::textToPath(Inkscape::Extension::Print * ext)
unsigned int PrintEmf::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom::Point const &p,
SPStyle const *const style)
{
-// std::cout << "text " << std::endl;
if (!et) return 0;
char *rec = NULL;
@@ -2015,10 +2023,10 @@ unsigned int PrintEmf::text(Inkscape::Extension::Print * /*mod*/, char const *te
}
}
- /* Note that text font sizes are stored into the EMF as fairly small integers and that limits their precision.
- The EMF output files produced here have been designed so that the integer valued pt sizes
- land right on an integer value in the EMF file, so those are exact. However, something like 18.1 pt will be
- somewhat off, so that when it is read back in it becomes 18.11 pt. (For instance.)
+ /* Note that text font sizes are stored into the EMF as fairly small integers and that limits their precision.
+ The EMF output files produced here have been designed so that the integer valued pt sizes
+ land right on an integer value in the EMF file, so those are exact. However, something like 18.1 pt will be
+ somewhat off, so that when it is read back in it becomes 18.11 pt. (For instance.)
*/
int textheight = round(-style->font_size.computed * PX2WORLD * std::min(tf.expansionX(),tf.expansionY()));
if (!hfont) {
@@ -2026,12 +2034,8 @@ unsigned int PrintEmf::text(Inkscape::Extension::Print * /*mod*/, char const *te
// Get font face name. Use changed font name if unicode mapped to one
// of the special fonts.
uint16_t *wfacename;
- if(!newfont){
- wfacename = U_Utf8ToUtf16le(style->text->font_family.value, 0, NULL);
- }
- else {
- wfacename = U_Utf8ToUtf16le(FontName(newfont), 0, NULL);
- }
+ if(!newfont){ wfacename = U_Utf8ToUtf16le(style->text->font_family.value, 0, NULL); }
+ else { wfacename = U_Utf8ToUtf16le(FontName(newfont), 0, NULL); }
// Scale the text to the minimum stretch. (It tends to stay within bounding rectangles even if
// it was streteched asymmetrically.) Few applications support text from EMF which is scaled
@@ -2055,36 +2059,25 @@ unsigned int PrintEmf::text(Inkscape::Extension::Print * /*mod*/, char const *te
free(wfacename);
rec = extcreatefontindirectw_set(&hfont, eht, (char *) &lf, NULL);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::text at extcreatefontindirectw_set";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::text at extcreatefontindirectw_set");
}
}
rec = selectobject_set(hfont, eht);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::text at selectobject_set";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::text at selectobject_set");
}
float rgb[3];
sp_color_get_rgb_floatv( &style->fill.value.color, rgb );
- rec = U_EMRSETTEXTCOLOR_set(U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]));
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::text at U_EMRSETTEXTCOLOR_set";
- }
-
- // Text alignment:
- // - (x,y) coordinates received by this filter are those of the point where the text
- // actually starts, and already takes into account the text object's alignment;
- // - for this reason, the EMF text alignment must always be TA_BASELINE|TA_LEFT.
- rec = U_EMRSETTEXTALIGN_set(U_TA_BASELINE | U_TA_LEFT);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::text at U_EMRSETTEXTALIGN_set";
- }
-
- // Transparent text background
- rec = U_EMRSETBKMODE_set(U_TRANSPARENT);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::text at U_EMRSETBKMODE_set";
+ // only change the text color when it needs to be changed
+ if(memcmp(htextcolor_rgb,rgb,3*sizeof(float))){
+ memcpy(htextcolor_rgb,rgb,3*sizeof(float));
+ rec = U_EMRSETTEXTCOLOR_set(U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]));
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::text at U_EMRSETTEXTCOLOR_set");
+ }
}
Geom::Point p2 = p * tf;
@@ -2099,27 +2092,27 @@ unsigned int PrintEmf::text(Inkscape::Extension::Print * /*mod*/, char const *te
//Conditionally handle compensation for PPT EMF import bug (affects PPT 2003-2010, at least)
if(FixPPTCharPos){
- if(fix90n==1){ //vertical
- dx= 0.0;
- dy= f3 * style->font_size.computed * std::cos( rotb );
- }
- else if(fix90n==2){ //horizontal
- dx= f2 * style->font_size.computed * std::sin( rotb );
- dy= 0.0;
- }
- else {
- dx= f1 * style->font_size.computed * std::sin( rotb );
- dy= f1 * style->font_size.computed * std::cos( rotb );
- }
- p2[Geom::X] += dx;
- p2[Geom::Y] += dy;
+ if(fix90n==1){ //vertical
+ dx= 0.0;
+ dy= f3 * style->font_size.computed * std::cos( rotb );
+ }
+ else if(fix90n==2){ //horizontal
+ dx= f2 * style->font_size.computed * std::sin( rotb );
+ dy= 0.0;
+ }
+ else {
+ dx= f1 * style->font_size.computed * std::sin( rotb );
+ dy= f1 * style->font_size.computed * std::cos( rotb );
+ }
+ p2[Geom::X] += dx;
+ p2[Geom::Y] += dy;
}
p2[Geom::X] = (p2[Geom::X] * PX2WORLD);
p2[Geom::Y] = (p2[Geom::Y] * PX2WORLD);
- int32_t const xpos = static_cast<int32_t>(round(p2[Geom::X]));
- int32_t const ypos = static_cast<int32_t>(round(p2[Geom::Y]));
+ int32_t const xpos = (int32_t) round(p2[Geom::X]);
+ int32_t const ypos = (int32_t) round(p2[Geom::Y]);
// The number of characters in the string is a bit fuzzy. ndx, the number of entries in adx is
// the number of VISIBLE characters, since some may combine from the UTF (8 originally,
@@ -2134,30 +2127,28 @@ unsigned int PrintEmf::text(Inkscape::Extension::Print * /*mod*/, char const *te
free(adx);
rec = U_EMREXTTEXTOUTW_set(U_RCL_DEF,U_GM_COMPATIBLE,1.0,1.0,(PU_EMRTEXT)rec2);
free(rec2);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::text at U_EMREXTTEXTOUTW_set";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::text at U_EMREXTTEXTOUTW_set");
}
// Must deselect an object before deleting it. Put the default font (back) in.
rec = selectobject_set(U_DEVICE_DEFAULT_FONT, eht);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::text at selectobject_set";
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::text at selectobject_set");
}
if(hfont){
- rec = deleteobject_set(&hfont, eht);
- if(!rec || emf_append(reinterpret_cast<PU_ENHMETARECORD>(rec), et, U_REC_FREE)){
- throw "Fatal programming error in PrintEmf::text at deleteobject_set";
- }
+ rec = deleteobject_set(&hfont, eht);
+ if(!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)){
+ g_error("Fatal programming error in PrintEmf::text at deleteobject_set");
+ }
}
-// std::cout << "end text" << std::endl;
return 0;
}
void PrintEmf::init (void)
{
-// std::cout << "init " << std::endl;
read_system_fflist();
/* EMF print */
diff --git a/src/extension/internal/emf-print.h b/src/extension/internal/emf-print.h
index 0832d6e30..6cfe5e46d 100644
--- a/src/extension/internal/emf-print.h
+++ b/src/extension/internal/emf-print.h
@@ -39,6 +39,8 @@ class PrintEmf : public Inkscape::Extension::Implementation::Implementation
U_RECTL rc;
uint32_t hbrush, hbrushOld, hpen, hpenOld;
+ uint32_t hpolyfillmode; // used to minimize redundant records that set this
+ float htextcolor_rgb[3]; // used to minimize redundant records that set this
std::stack<Geom::Affine> m_tr_stack;
Geom::PathVector fill_pathv;
@@ -46,6 +48,7 @@ class PrintEmf : public Inkscape::Extension::Implementation::Implementation
bool use_stroke;
bool use_fill;
bool simple_shape;
+ bool usebk;
unsigned int print_pathv (Geom::PathVector const &pathv, const Geom::Affine &transform);
bool print_simple_shape (Geom::PathVector const &pathv, const Geom::Affine &transform);
@@ -99,8 +102,8 @@ protected:
int create_pen(SPStyle const *style, const Geom::Affine &transform);
void destroy_pen();
- void hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor);
- void brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor);
+ void hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor);
+ void brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor);
void swapRBinRGBA(char *px, int pixels);
U_COLORREF avg_stop_color(SPGradient *gr);
diff --git a/src/extension/internal/text_reassemble.c b/src/extension/internal/text_reassemble.c
index b72bafa33..2518795b6 100644
--- a/src/extension/internal/text_reassemble.c
+++ b/src/extension/internal/text_reassemble.c
@@ -46,7 +46,7 @@ On Windows use:
On Linux use:
- gcc -Wall -DTEST -DTEST -DDBG_TR_PARA -DDBG_TR_INPUT -I. -I/usr/include/freetype2 -o text_reassemble text_reassemble.c uemf_utf.c -lfreetype -lfontconfig -lm
+ gcc -Wall -DTEST -DDBG_TR_PARA -DDBG_TR_INPUT -I. -I/usr/include/freetype2 -o text_reassemble text_reassemble.c uemf_utf.c -lfreetype -lfontconfig -lm
Compilation of object file only (Windows):
@@ -67,8 +67,8 @@ Optional compiler switches for development:
File: text_reassemble.c
-Version: 0.0.5
-Date: 19-FEB-2013
+Version: 0.0.6
+Date: 12-MAR-2013
Author: David Mathog, Biology Division, Caltech
email: mathog@caltech.edu
Copyright: 2013 David Mathog and California Institute of Technology (Caltech)
@@ -989,6 +989,7 @@ TR_INFO *trinfo_init(TR_INFO *tri){
!(tri->cxi = cxinfo_init())
){ tri = trinfo_release(tri); }
tri->use_kern = 1;
+ tri->usebk = BKCLR_NONE;
tri->load_flags = FT_LOAD_NO_SCALE;
tri->kern_mode = FT_KERNING_UNSCALED;
tri->out = NULL; /* This will allocate as needed, it might not ever be needed. */
@@ -1051,7 +1052,7 @@ TR_INFO *trinfo_clear(TR_INFO *tri){
if(tri){
tri->dirty = 0; /* set these back to their defaults */
tri->esc = 0.0;
- /* Do NOT modify use_kern, load_flags, or kern_mode */
+ /* Do NOT modify use_kern, usebk, load_flags, or kern_mode */
if(tri->bri)tri->bri=brinfo_release(tri->bri);
if(tri->tpi)tri->tpi=tpinfo_release(tri->tpi);
@@ -1178,6 +1179,42 @@ int trinfo_load_qe(TR_INFO *tri, double qe){
}
/**
+ \brief Set the background color and whether or not to use it.
+ When background color is turned on each line of text is underwritten with a rectangle
+ of the specified color. The rectangle is the merged bounding rectangle for that line.
+ \returns 0 on success but nothing changed, >0 on error, <0 on success and a value changed.
+ \param tri pointer to TR_INFO structure
+ \param usebk 0 for no background, anything else uses background color
+ \param bkcolor background color to use
+*/
+int trinfo_load_bk(TR_INFO *tri, int usebk, TRCOLORREF bkcolor){
+ int status=0;
+ if(!tri){ status = 1; }
+ else {
+ if((usebk < BKCLR_NONE) || (usebk > BKCLR_ALL)){ status = 2; }
+ else {
+ status = trinfo_check_bk(tri, usebk, bkcolor);
+ tri->usebk = usebk;
+ tri->bkcolor = bkcolor;
+ }
+ }
+ return(status);
+}
+
+/**
+ \brief Are the proposed new background and background color a change?
+ \returns 0 if they are the same, -1 if either is different
+ \param tri pointer to TR_INFO structure
+ \param usebk 0 for no background, anything else uses background color
+ \param bkcolor background color to use
+*/
+int trinfo_check_bk(TR_INFO *tri, int usebk, TRCOLORREF bkcolor){
+ int status = 0;
+ if( (tri->usebk != usebk) || memcmp(&tri->bkcolor,&bkcolor,sizeof(TRCOLORREF))){ status = -1; }
+ return(status);
+}
+
+/**
\brief Set Freetype parameters and kerning mode (if any) in a TRI_INFO structure.
\returns 0 on success, !0 on error.
\param tri pointer to a TR_INFO structure
@@ -1436,29 +1473,28 @@ void TR_layout_2_svg(TR_INFO *tri){
TCHUNK_SPECS *ptsp; /* previous text object in the same line as current text object, if any */
FNT_SPECS *fsp;
CX_SPECS *csp;
+ CX_SPECS *cline_sp;
int i,j,k,jdx,kdx;
int status;
char obuf[1024]; /* big enough for style and so forth */
-#if defined(DBG_TR_PARA) || defined(DBG_TR_INPUT) /* enable debugging code, writes extra information into SVG */
char stransform[128];
double newx,newy;
+ /* The debug section below is difficult to see if usebk is anything other than BKCLR_NONE */
+#if defined(DBG_TR_PARA) || defined(DBG_TR_INPUT) /* enable debugging code, writes extra information into SVG */
/* put rectangles down for each text string - debugging!!! This will not work properly for any Narrow fonts */
+ esc = tri->esc;
+ esc *= 2.0 * M_PI / 360.0; /* degrees to radians and change direction of rotation */
+ sprintf(stransform,"transform=\"matrix(%lf,%lf,%lf,%lf,%lf,%lf)\"\n",cos(esc),-sin(esc),sin(esc),cos(esc), 1.25*x,1.25*y);
for(i=cxi->phase1; i<cxi->used;i++){ /* over all complex members from phase2 == TR_PARA_* complexes */
csp = &(cxi->cx[i]);
- esc = tri->esc;
- esc *= 2.0 * M_PI / 360.0; /* degrees to radians and change direction of rotation */
for(j=0; j<csp->kids.used; j++){ /* over all members of these complexes, which are phase1 complexes */
jdx = csp->kids.members[j]; /* index of phase1 complex (all are TR_TEXT or TR_LINE) */
for(k=0; k<cxi->cx[jdx].kids.used; k++){ /* over all members of the phase1 complex */
kdx = cxi->cx[jdx].kids.members[k]; /* index for text objects in tpi */
tsp = &tpi->chunks[kdx];
if(!j && !k){
- sprintf(stransform,"transform=\"matrix(%lf,%lf,%lf,%lf,%lf,%lf)\"\n",cos(esc),-sin(esc),sin(esc),cos(esc),
- 1.25*x,1.25*y);
- lastx = bri->rects[tsp->rt_tidx].xll;
- lasty = bri->rects[tsp->rt_tidx].yll - tsp->boff;
#ifdef DBG_TR_PARA
TRPRINT(tri, "<rect\n");
TRPRINT(tri, "style=\"color:#0000FF;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:none;stroke:#000000;stroke-width:0.30000001;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;clip-rule:nonzero\"\n");
@@ -1515,6 +1551,71 @@ void TR_layout_2_svg(TR_INFO *tri){
#endif /* DBG_TR_PARA and/or DBG_TR_INPUT */
+ if(tri->usebk){
+ esc = tri->esc;
+ esc *= 2.0 * M_PI / 360.0; /* degrees to radians and change direction of rotation */
+ sprintf(stransform,"transform=\"matrix(%lf,%lf,%lf,%lf,%lf,%lf)\"\n",cos(esc),-sin(esc),sin(esc),cos(esc), 1.25*x,1.25*y);
+
+ for(i=cxi->phase1; i<cxi->used;i++){ /* over all complex members from phase2 == TR_PARA_* complexes */
+ TRPRINT(tri, "<g>\n"); /* group backgrounds for each <text> object in the SVG */
+ csp = &(cxi->cx[i]);
+ for(j=0; j<csp->kids.used; j++){ /* over all members of these complexes, which are phase1 complexes */
+ jdx = csp->kids.members[j]; /* index of phase1 complex (all are TR_TEXT or TR_LINE) */
+ cline_sp = &(cxi->cx[jdx]);
+ if(tri->usebk == BKCLR_LINE){
+ TRPRINT(tri, "<rect\n");
+ sprintf(obuf,"style=\"color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#%2.2X%2.2X%2.2X;;stroke:none;;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;clip-rule:nonzero\"\n",tri->bkcolor.Red,tri->bkcolor.Green,tri->bkcolor.Blue);
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"width=\"%lf\"\n", 1.25*(bri->rects[cline_sp->rt_cidx].xur - bri->rects[cline_sp->rt_cidx].xll));
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"height=\"%lf\"\n",1.25*(bri->rects[cline_sp->rt_cidx].yll - bri->rects[cline_sp->rt_cidx].yur));
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n",1.25*(bri->rects[cline_sp->rt_cidx].xll),1.25*(bri->rects[cline_sp->rt_cidx].yur));
+ TRPRINT(tri, obuf);
+ TRPRINT(tri, stransform);
+ TRPRINT(tri, "/>\n");
+ }
+
+ for(k=0; k<cxi->cx[jdx].kids.used; k++){ /* over all members of the phase1 complex */
+ kdx = cxi->cx[jdx].kids.members[k]; /* index for text objects in tpi */
+ tsp = &tpi->chunks[kdx];
+ if(!j && !k){
+ if(tri->usebk == BKCLR_ALL){
+ TRPRINT(tri, "<rect\n");
+ sprintf(obuf,"style=\"color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#%2.2X%2.2X%2.2X;;stroke:none;;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;clip-rule:nonzero\"\n",tri->bkcolor.Red,tri->bkcolor.Green,tri->bkcolor.Blue);
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"width=\"%lf\"\n", 1.25*(bri->rects[csp->rt_cidx].xur - bri->rects[csp->rt_cidx].xll));
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"height=\"%lf\"\n",1.25*(bri->rects[csp->rt_cidx].yll - bri->rects[csp->rt_cidx].yur));
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n",1.25*(bri->rects[csp->rt_cidx].xll),1.25*(bri->rects[csp->rt_cidx].yur));
+ TRPRINT(tri, obuf);
+ TRPRINT(tri, stransform);
+ TRPRINT(tri, "/>\n");
+ }
+ }
+ if(tri->usebk == BKCLR_FRAG){
+ newx = 1.25*(bri->rects[tsp->rt_tidx].xll);
+ newy = 1.25*(bri->rects[tsp->rt_tidx].yur);
+ TRPRINT(tri, "<rect\n");
+ sprintf(obuf,"style=\"color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#%2.2X%2.2X%2.2X;;stroke:none;;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;clip-rule:nonzero\"\n",tri->bkcolor.Red,tri->bkcolor.Green,tri->bkcolor.Blue);
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"width=\"%lf\"\n", 1.25*(bri->rects[tsp->rt_tidx].xur - bri->rects[tsp->rt_tidx].xll));
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"height=\"%lf\"\n",1.25*(bri->rects[tsp->rt_tidx].yll - bri->rects[tsp->rt_tidx].yur));
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n",newx,newy);
+ TRPRINT(tri, obuf);
+ TRPRINT(tri, stransform);
+ TRPRINT(tri, "/>\n");
+ }
+ }
+ }
+ TRPRINT(tri, "</g>\n"); /* end of grouping for backgrounds for each <text> object in the SVG */
+ }
+ }
+
+
tsp=tpi->chunks;
/* over all complex members from phase2. Paragraphs == TR_PARA_* */
for(i=cxi->phase1; i<cxi->used;i++){
@@ -1563,55 +1664,55 @@ void TR_layout_2_svg(TR_INFO *tri){
break;
}
if(!j){
- TRPRINT(tri, "<text\n");
- TRPRINT(tri, "xml:space=\"preserve\"\n");
- TRPRINT(tri, "style=\"");
- sprintf(obuf,"font-size:%lfpx;",tsp->fs*1.25); /*IMPORTANT, if the FS is given in pt it looks like crap in browsers. As if px != 1.25 pt, maybe 96 dpi not 90?*/
- TRPRINT(tri, obuf);
- sprintf(obuf,"font-style:%s;",(tsp->italics ? "italic" : "normal"));
- TRPRINT(tri, obuf);
- TRPRINT(tri, "font-variant:normal;");
- sprintf(obuf,"font-weight:%d;",TR_weight_FC_to_SVG(tsp->weight));
- TRPRINT(tri, obuf);
- sprintf(obuf,"font-stretch:%s;",(tsp->condensed==100 ? "Normal" : "Condensed"));
- TRPRINT(tri, obuf);
- if(tsp->vadvance){ lineheight = tsp->vadvance *100.0; }
- else { lineheight = 125.0; }
- sprintf(obuf,"line-height:%lf%%;",lineheight);
- TRPRINT(tri, obuf);
- TRPRINT(tri, "letter-spacing:0px;");
- TRPRINT(tri, "word-spacing:0px;");
- TRPRINT(tri, "fill:#000000;");
- TRPRINT(tri, "fill-opacity:1;");
- TRPRINT(tri, "stroke:none;");
- cutat=strcspn((char *)fti->fonts[tsp->fi_idx].fname,":");
- fti->fonts[tsp->fi_idx].fname[cutat]='\0';
- sprintf(obuf,"font-family:%s;",fti->fonts[tsp->fi_idx].fname);
- TRPRINT(tri, obuf);
- switch(csp->type){ /* set up the alignment, if there is one */
- case TR_TEXT:
- case TR_LINE:
- /* these should never occur, this section quiets a compiler warning */
- break;
- case TR_PARA_UJ:
- *obuf='\0';
- break;
- case TR_PARA_LJ:
- sprintf(obuf,"text-align:start;text-anchor:start;");
- break;
- case TR_PARA_CJ:
- sprintf(obuf,"text-align:center;text-anchor:middle;");
- break;
- case TR_PARA_RJ:
- sprintf(obuf,"text-align:end;text-anchor:end;");
- break;
- }
- TRPRINT(tri, obuf);
- TRPRINT(tri, "\"\n"); /* End of style specification */
- sprintf(obuf,"transform=\"matrix(%lf,%lf,%lf,%lf,%lf,%lf)\"\n",cos(esc),-sin(esc),sin(esc),cos(esc),1.25*x,1.25*y);
- TRPRINT(tri, obuf);
- sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n>",1.25*(bri->rects[kdx].xll + recenter),1.25*(bri->rects[kdx].yll - tsp->boff));
- TRPRINT(tri, obuf);
+ TRPRINT(tri, "<text\n");
+ TRPRINT(tri, "xml:space=\"preserve\"\n");
+ TRPRINT(tri, "style=\"");
+ sprintf(obuf,"font-size:%lfpx;",tsp->fs*1.25); /*IMPORTANT, if the FS is given in pt it looks like crap in browsers. As if px != 1.25 pt, maybe 96 dpi not 90?*/
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"font-style:%s;",(tsp->italics ? "italic" : "normal"));
+ TRPRINT(tri, obuf);
+ TRPRINT(tri, "font-variant:normal;");
+ sprintf(obuf,"font-weight:%d;",TR_weight_FC_to_SVG(tsp->weight));
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"font-stretch:%s;",(tsp->condensed==100 ? "Normal" : "Condensed"));
+ TRPRINT(tri, obuf);
+ if(tsp->vadvance){ lineheight = tsp->vadvance *100.0; }
+ else { lineheight = 125.0; }
+ sprintf(obuf,"line-height:%lf%%;",lineheight);
+ TRPRINT(tri, obuf);
+ TRPRINT(tri, "letter-spacing:0px;");
+ TRPRINT(tri, "word-spacing:0px;");
+ TRPRINT(tri, "fill:#000000;");
+ TRPRINT(tri, "fill-opacity:1;");
+ TRPRINT(tri, "stroke:none;");
+ cutat=strcspn((char *)fti->fonts[tsp->fi_idx].fname,":");
+ fti->fonts[tsp->fi_idx].fname[cutat]='\0';
+ sprintf(obuf,"font-family:%s;",fti->fonts[tsp->fi_idx].fname);
+ TRPRINT(tri, obuf);
+ switch(csp->type){ /* set up the alignment, if there is one */
+ case TR_TEXT:
+ case TR_LINE:
+ /* these should never occur, this section quiets a compiler warning */
+ break;
+ case TR_PARA_UJ:
+ *obuf='\0';
+ break;
+ case TR_PARA_LJ:
+ sprintf(obuf,"text-align:start;text-anchor:start;");
+ break;
+ case TR_PARA_CJ:
+ sprintf(obuf,"text-align:center;text-anchor:middle;");
+ break;
+ case TR_PARA_RJ:
+ sprintf(obuf,"text-align:end;text-anchor:end;");
+ break;
+ }
+ TRPRINT(tri, obuf);
+ TRPRINT(tri, "\"\n"); /* End of style specification */
+ sprintf(obuf,"transform=\"matrix(%lf,%lf,%lf,%lf,%lf,%lf)\"\n",cos(esc),-sin(esc),sin(esc),cos(esc),1.25*x,1.25*y);
+ TRPRINT(tri, obuf);
+ sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n>",1.25*(bri->rects[kdx].xll + recenter),1.25*(bri->rects[kdx].yll - tsp->boff));
+ TRPRINT(tri, obuf);
}
sprintf(obuf,"<tspan sodipodi:role=\"line\"\nx=\"%lf\" y=\"%lf\"\n>",
1.25*(bri->rects[kdx].xll + recenter),1.25*(bri->rects[kdx].yll - tsp->boff));
@@ -1646,6 +1747,24 @@ void TR_layout_2_svg(TR_INFO *tri){
TRPRINT(tri, obuf);
sprintf(obuf,"font-style:%s;",(tsp->italics ? "italic" : "normal"));
TRPRINT(tri, obuf);
+ switch(tsp->decoration){
+ case TXTDECOR_NONE:
+ case TXTDECOR_STRIKE2:
+ default:
+ break;
+ case TXTDECOR_UNDER:
+ TRPRINT(tri,"text-decoration:underline;");
+ break;
+ case TXTDECOR_OVER:
+ TRPRINT(tri,"text-decoration:overline;");
+ break;
+ case TXTDECOR_BLINK:
+ TRPRINT(tri,"text-decoration:blink;");
+ break;
+ case TXTDECOR_STRIKE1:
+ TRPRINT(tri,"text-decoration:line-through;");
+ break;
+ }
TRPRINT(tri, "font-variant:normal;");
sprintf(obuf,"font-weight:%d;",TR_weight_FC_to_SVG(tsp->weight));
TRPRINT(tri, obuf);
@@ -1813,7 +1932,7 @@ int TR_layout_analyze(TR_INFO *tri){
#if TEST
#define MAXLINE 2048 /* big enough for testing */
-enum OP_TYPES {OPCOM,OPOOPS,OPFONT,OPESC,OPORI,OPXY,OPFS,OPTEXT,OPALN,OPLDIR,OPMUL,OPITA,OPWGT,OPCND,OPCLR,OPFLAGS,OPEMIT,OPDONE};
+enum OP_TYPES {OPCOM,OPOOPS,OPFONT,OPESC,OPORI,OPXY,OPFS,OPTEXT,OPALN,OPLDIR,OPMUL,OPITA,OPWGT,OPDEC,OPCND,OPCLR,OPBKG,OPBCLR,OPFLAGS,OPEMIT,OPDONE};
int parseit(char *buffer,char **data){
int pre;
@@ -1833,8 +1952,11 @@ int parseit(char *buffer,char **data){
if(0==strcmp("MUL", buffer))return(OPMUL );
if(0==strcmp("ITA", buffer))return(OPITA );
if(0==strcmp("WGT", buffer))return(OPWGT );
+ if(0==strcmp("DEC", buffer))return(OPDEC );
if(0==strcmp("CND", buffer))return(OPCND );
if(0==strcmp("CLR", buffer))return(OPCLR );
+ if(0==strcmp("BKG", buffer))return(OPBKG );
+ if(0==strcmp("BCLR",buffer))return(OPBCLR );
if(0==strcmp("FLAG",buffer))return(OPFLAGS);
if(0==strcmp("EMIT",buffer))return(OPEMIT);
if(0==strcmp("DONE",buffer))return(OPDONE);
@@ -1942,6 +2064,8 @@ int main(int argc, char *argv[]){
int flags=0;
char *infile;
uint32_t utmp32;
+ TRCOLORREF bkcolor;
+ int bkmode;
infile=malloc(strlen(argv[1])+1);
strcpy(infile,argv[1]);
@@ -1960,8 +2084,11 @@ int main(int argc, char *argv[]){
printf(" MUL:(float, multiplicative factor to convert FS,XY units to points).\n");
printf(" ITA:(Italics, 0=normal, 100=italics, 110=oblique).\n");
printf(" WGT:(Weight, 0-215: 80=normal, 200=bold, 215=ultrablack, 0=thin)).\n");
+ printf(" DEC:(Decorate, 00 none, 01 underline, 02 overline, 04 blink, 08 strike1, 10 strike2. SVG only supports some, and only one at a time.)\n");
printf(" CND:(Condensed 50-200: 100=normal, 50=ultracondensed, 75=condensed, 200=expanded).\n");
- printf(" CLR:(RGB color, as 6 HEX digits, like: FF0000 (red) or 0000FF (blue)) \n");
+ printf(" CLR:(Text RGB color, as 6 HEX digits, like: FF0000 (red) or 0000FF (blue)) \n");
+ printf(" BKG:(Background color: 0 none, 1 by input fragment, 2 by assembled line, 3 by entire assembly. Use BCLR, THEN BKG) \n");
+ printf(" BCLR:(Background RGB color, as 6 HEX digits, like: FF0000 (red) or 0000FF (blue)) \n");
printf(" FLAG: Special processing options. 1 EMF compatible text alignment.\n");
printf(" EMIT:(Process everything up to this point, then start clean for remaining input).\n");
printf(" DONE:(no more input, process it).\n");
@@ -1969,7 +2096,7 @@ int main(int argc, char *argv[]){
printf("\n");
printf(" The output is a summary of how the pieces are to be assembled into complex text.\n");
printf("\n");
- printf(" egrep pattern: '^LOAD:|^FONT:|^ESC:|^ORI:|^FS:|^XY:|^TEXT:|^ALN:|^LDIR:|^MUL:|^ITA:|^WGT:|^CND:|^CLR:|^FLAG:|^EMIT:^DONE:'\n");
+ printf(" egrep pattern: '^LOAD:|^FONT:|^ESC:|^ORI:|^FS:|^XY:|^TEXT:|^ALN:|^LDIR:|^MUL:|^ITA:|^WGT:|^CND:|^BKG:|^BCLR:|^CLR:|^FLAG:|^EMIT:^DONE:'\n");
exit(EXIT_FAILURE);
}
@@ -2090,16 +2217,30 @@ int main(int argc, char *argv[]){
case OPWGT:
if(1 != sscanf(data,"%d",&tsp.weight) || tsp.weight < 0 || tsp.weight > 215)boom("Invalid WGT:",lineno);
break;
+ case OPDEC:
+ if(1 != sscanf(data,"%X",&tsp.decoration))boom("Invalid DEC:",lineno);
+ break;
case OPCND:
if(1 != sscanf(data,"%d",&tsp.condensed) || tsp.condensed < 50 || tsp.condensed > 200)boom("Invalid CND:",lineno);
break;
case OPCLR:
if(1 != sscanf(data,"%x",&utmp32) )boom("Invalid CLR:",lineno);
- tsp.color.Red = (utmp32 >> 4) & 0xFF;
- tsp.color.Green = (utmp32 >> 2) & 0xFF;
+ tsp.color.Red = (utmp32 >> 16) & 0xFF;
+ tsp.color.Green = (utmp32 >> 8) & 0xFF;
tsp.color.Blue = (utmp32 >> 0) & 0xFF;
tsp.color.Reserved = 0;
break;
+ case OPBKG:
+ if(1 != sscanf(data,"%d",&bkmode) )boom("Invalid BKG:",lineno);
+ (void) trinfo_load_bk(tri,bkmode,bkcolor);
+ break;
+ case OPBCLR:
+ if(1 != sscanf(data,"%x",&utmp32) )boom("Invalid BCLR:",lineno);
+ bkcolor.Red = (utmp32 >> 16) & 0xFF;
+ bkcolor.Green = (utmp32 >> 8) & 0xFF;
+ bkcolor.Blue = (utmp32 >> 0) & 0xFF;
+ bkcolor.Reserved = 0;
+ break;
case OPFLAGS:
if(1 != sscanf(data,"%d",&flags) )boom("Invalid FLAG:",lineno);
break;
diff --git a/src/extension/internal/text_reassemble.h b/src/extension/internal/text_reassemble.h
index cf8aa6729..950ce1310 100644
--- a/src/extension/internal/text_reassemble.h
+++ b/src/extension/internal/text_reassemble.h
@@ -4,8 +4,8 @@
See text_reassemble.c for notes
File: text_reassemble.h
-Version: 0.0.6
-Date: 19-FEB-2013
+Version: 0.0.7
+Date: 12-FEB-2013
Author: David Mathog, Biology Division, Caltech
email: mathog@caltech.edu
Copyright: 2013 David Mathog and California Institute of Technology (Caltech)
@@ -42,6 +42,32 @@ extern "C" {
#define TRPRINT trinfo_append_out
/** \endcond */
+/** \defgroup color background options
+ Text is underwritten with the background color not at all,
+ by reassembled line, or by full assembly .
+ @{
+*/
+#define BKCLR_NONE 0x00 /**< text is not underwritten with background color (default) */
+#define BKCLR_FRAG 0x01 /**< each fragment of text is underwritten with background color */
+#define BKCLR_LINE 0x02 /**< each line of text is underwritten with background color */
+#define BKCLR_ALL 0x03 /**< entire assembly is underwritten with background color */
+/** @} */
+
+/** \defgroup decoration options
+ One of these values may be present in the decoration field.
+ Unused bits may be used by end user code.
+ SVG output can specify up to STRIKE1.
+ @{
+*/
+#define TXTDECOR_NONE 0x00 /**< text is not decorated (default) */
+#define TXTDECOR_UNDER 0x01 /**< underlined */
+#define TXTDECOR_OVER 0x02 /**< overlined */
+#define TXTDECOR_BLINK 0x04 /**< blinking text */
+#define TXTDECOR_STRIKE1 0x08 /**< single strike throug */
+#define TXTDECOR_STRIKE2 0x10 /**< double strike through */
+/** @} */
+
+
/** \defgroup text alignment types
Location of text's {X,Y} coordinate on bounding rectangle.
Values are compatible with Fontconfig.
@@ -133,6 +159,7 @@ typedef struct {
int italics; /**< italics, as in FontConfig */
int weight; /**< weight, as in FontConfig */
int condensed; /**< condensed, as in FontConfig */
+ int decoration; /**< text decorations, ignored during assembly,used during output */
int co; /**< condensed override, if set Font name included narrow */
int rt_tidx; /**< index of rectangle that contains it */
int fi_idx; /**< index of the font it uses */
@@ -221,6 +248,8 @@ typedef struct {
int kern_mode; /**< FT_KERNING_DEFAULT, FT_KERNING_UNFITTED, or FT_KERNING_UNSCALED */
int outspace; /**< storage in output buffer allocated */
int outused; /**< storage in output buffer in use */
+ int usebk; /**< On output write the background color under the text */
+ TRCOLORREF bkcolor; /**< RGB background color */
} TR_INFO;
/* padding added to rectangles before overlap test */
@@ -300,8 +329,10 @@ TR_INFO *trinfo_release_except_FC(TR_INFO *tri);
TR_INFO *trinfo_clear(TR_INFO *tri);
int trinfo_load_fontname(TR_INFO *tri, uint8_t *fontname, TCHUNK_SPECS *tsp);
int trinfo_load_qe(TR_INFO *tri, double qe);
+int trinfo_load_bk(TR_INFO *tri, int usebk, TRCOLORREF bkcolor);
int trinfo_load_ft_opts(TR_INFO *tri, int use_kern, int load_flags, int kern_mode);
int trinfo_load_textrec(TR_INFO *tri, TCHUNK_SPECS *tsp, double escapement, int flags);
+int trinfo_check_bk(TR_INFO *tri, int usebk, TRCOLORREF bkcolor);
int trinfo_append_out(TR_INFO *tri, char *src);
#ifdef __cplusplus
diff --git a/src/extension/internal/uwmf.c b/src/extension/internal/uwmf.c
index d2448cd09..566fb0065 100644
--- a/src/extension/internal/uwmf.c
+++ b/src/extension/internal/uwmf.c
@@ -17,8 +17,8 @@
/*
File: uwmf.c
-Version: 0.0.9
-Date: 20-FEB-2013
+Version: 0.0.10
+Date: 27-FEB-2013
Author: David Mathog, Biology Division, Caltech
email: mathog@caltech.edu
Copyright: 2013 David Mathog and California Institute of Technology (Caltech)
@@ -5960,6 +5960,17 @@ int U_WMRDIBCREATEPATTERNBRUSH_get(
if(*Style == U_BS_PATTERN){
*Bm16 = (contents + offsetof(U_WMRDIBCREATEPATTERNBRUSH, Src));
*dib = NULL;
+ /* The WMF spec says that Style == U_BS_PATTERN _SHOULD_ be a bitmap16.
+ However there are instances when it is actually a DIB. U_WMRDIBCREATEPATTERNBRUSH_get
+ tries to detect this by looking for bogus values when the BM16 is interpreted as such,
+ and if it finds them, then it returns a dib instead.
+ */
+ U_BITMAP16 TmpBm16;
+ memcpy(&TmpBm16, *Bm16, U_SIZE_BITMAP16);
+ if(TmpBm16.Width <= 0 || TmpBm16.Height <= 0 || TmpBm16.Planes != 1 || TmpBm16.BitsPixel == 0){
+ *Bm16 = NULL;
+ *dib = (contents + offsetof(U_WMRDIBCREATEPATTERNBRUSH, Src));
+ }
}
else { /* from DIB */
*Bm16 = NULL;
diff --git a/src/extension/internal/uwmf.h b/src/extension/internal/uwmf.h
index 30b781885..a97648eb1 100644
--- a/src/extension/internal/uwmf.h
+++ b/src/extension/internal/uwmf.h
@@ -34,8 +34,8 @@
/*
File: uwmf.h
-Version: 0.0.7
-Date: 20-FEB-2013
+Version: 0.0.8
+Date: 27-FEB-2013
Author: David Mathog, Biology Division, Caltech
email: mathog@caltech.edu
Copyright: 2013 David Mathog and California Institute of Technology (Caltech)
@@ -854,7 +854,7 @@ typedef struct {
/** BitmapCoreHeader Object WMF PDF 2.2.2.2
*/
typedef struct {
- uint16_t Size_4[2]; //!< size of U_BECOREHEADER in bytes.
+ uint16_t Size_4[2]; //!< size of U_BITMAPCOREHEADER in bytes.
uint16_t Width; //!< DIB width in pixels.
uint16_t Height; //!< DIB height in pixels.
uint16_t Planes; //!< must be 1
diff --git a/src/extension/internal/uwmf_print.c b/src/extension/internal/uwmf_print.c
index e2d2b0663..bb9f3eb36 100644
--- a/src/extension/internal/uwmf_print.c
+++ b/src/extension/internal/uwmf_print.c
@@ -1013,7 +1013,7 @@ void U_WMRDIBCREATEPATTERNBRUSH_print(const char *contents){
U_BITMAP16 Bm16;
printf(" Style:%d\n", Style );
printf(" cUsage:%d\n", cUsage);
- if(Style == U_BS_PATTERN){
+ if(TBm16){
memcpy(&Bm16, TBm16, U_SIZE_BITMAP16);
printf(" Src:Bitmap16:"); bitmap16_print(Bm16); printf("\n");
}
diff --git a/src/extension/internal/wmf-inout.cpp b/src/extension/internal/wmf-inout.cpp
index dce5d508e..bb931125e 100644
--- a/src/extension/internal/wmf-inout.cpp
+++ b/src/extension/internal/wmf-inout.cpp
@@ -66,7 +66,7 @@ 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
+/** Construct a PNG in memory from an RGB from the WMF file
from:
http://www.lemoda.net/c/write-png/
@@ -83,10 +83,10 @@ Originally here, but moved up
#include <stdlib.h>
#include <stdint.h>
*/
-
-/* Given "bitmap", this returns the pixel of bitmap at the point
- ("x", "y"). */
+
+/* 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)
{
@@ -94,87 +94,86 @@ pixel_t * Wmf::pixel_at (bitmap_t * bitmap, int x, int y)
}
-/* Write "bitmap" to a PNG file specified by "path"; returns 0 on
- success, non-zero on error. */
+/* 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;
+ 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;
+ 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.
+ /* 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){
+ 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;
+ 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;
+ 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);
-
+ 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 *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) {
@@ -184,21 +183,21 @@ void Wmf::toPNG(PMEMPNG accum, int width, int height, const char *px){
*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);
-
+
}
@@ -208,7 +207,7 @@ inverse of gethexcolor() in emf-print.cpp
uint32_t Wmf::sethexcolor(U_COLORREF color){
uint32_t out;
- out = (U_RGBAGetR(color) << 16) +
+ out = (U_RGBAGetR(color) << 16) +
(U_RGBAGetG(color) << 8 ) +
(U_RGBAGetB(color) );
return(out);
@@ -237,7 +236,7 @@ Wmf::check (Inkscape::Extension::Extension * /*module*/)
void
-Wmf::print_document_to_file(SPDocument *doc, const gchar*filename)
+Wmf::print_document_to_file(SPDocument *doc, const gchar *filename)
{
Inkscape::Extension::Print *mod;
SPPrintContext context;
@@ -299,10 +298,10 @@ Wmf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filena
bool new_FixPPTPatternAsHatch = mod->get_param_bool("FixPPTPatternAsHatch"); // force all patterns as standard WMF hatch
TableGen( //possibly regenerate the unicode-convert tables
- mod->get_param_bool("TnrToSymbol"),
- mod->get_param_bool("TnrToWingdings"),
- mod->get_param_bool("TnrToZapfDingbats"),
- mod->get_param_bool("UsePUA")
+ mod->get_param_bool("TnrToSymbol"),
+ mod->get_param_bool("TnrToWingdings"),
+ mod->get_param_bool("TnrToZapfDingbats"),
+ mod->get_param_bool("UsePUA")
);
ext->set_param_bool("FixPPTCharPos",new_FixPPTCharPos); // Remember to add any new ones to PrintWmf::init or a mysterious failure will result!
@@ -327,17 +326,17 @@ double Wmf::current_scale(PWMF_CALLBACK_DATA d){
/* WMF has no worldTranform, so this always returns an Identity rotation matrix, but the offsets may have values.*/
std::string Wmf::current_matrix(PWMF_CALLBACK_DATA d, double x, double y, int useoffset){
- std::stringstream cxform;
- double scale = current_scale(d);
- cxform << "\"matrix(";
- cxform << 1.0/scale; cxform << ",";
- cxform << 0.0; cxform << ",";
- cxform << 0.0; cxform << ",";
- cxform << 1.0/scale; cxform << ",";
- if(useoffset){ cxform << x; cxform << ","; cxform << y; }
- else { cxform << "0,0"; }
- cxform << ")\"";
- return(cxform.str());
+ std::stringstream cxform;
+ double scale = current_scale(d);
+ cxform << "\"matrix(";
+ cxform << 1.0/scale; cxform << ",";
+ cxform << 0.0; cxform << ",";
+ cxform << 0.0; cxform << ",";
+ cxform << 1.0/scale; cxform << ",";
+ if(useoffset){ cxform << x; cxform << ","; cxform << y; }
+ else { cxform << "0,0"; }
+ cxform << ")\"";
+ return(cxform.str());
}
/* WMF has no worldTranform, so this always returns 0. Retain it to keep WMF and WMF in sync as much as possible.*/
@@ -348,358 +347,444 @@ double Wmf::current_rotation(PWMF_CALLBACK_DATA d){
/* Add another 100 blank slots to the hatches array.
*/
void Wmf::enlarge_hatches(PWMF_CALLBACK_DATA d){
- d->hatches.size += 100;
- d->hatches.strings = (char **) realloc(d->hatches.strings,d->hatches.size + sizeof(char *));
+ d->hatches.size += 100;
+ d->hatches.strings = (char **) realloc(d->hatches.strings,d->hatches.size * sizeof(char *));
}
/* See if the pattern name is already in the list. If it is return its position (1->n, not 1-n-1)
*/
int Wmf::in_hatches(PWMF_CALLBACK_DATA d, char *test){
- int i;
- for(i=0; i<d->hatches.count; i++){
- if(strcmp(test,d->hatches.strings[i])==0)return(i+1);
- }
- return(0);
+ int i;
+ for(i=0; i<d->hatches.count; i++){
+ if(strcmp(test,d->hatches.strings[i])==0)return(i+1);
+ }
+ return(0);
}
/* (Conditionally) add a hatch. If a matching hatch already exists nothing happens. If one
- does not exist it is added to the hatches list and also entered into <defs>.
+ does not exist it is added to the hatches list and also entered into <defs>.
+ This is also used to add the path part of the hatches, which they reference with a xlink:href
*/
uint32_t Wmf::add_hatch(PWMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hatchColor){
- char hatchname[64]; // big enough
- char tmpcolor[8];
- uint32_t idx;
-
- if(hatchType==U_HS_DIAGCROSS){ // This is the only one with dependencies on others
- (void) add_hatch(d,U_HS_FDIAGONAL,hatchColor);
- (void) add_hatch(d,U_HS_BDIAGONAL,hatchColor);
- }
-
- sprintf(tmpcolor,"%6.6X",sethexcolor(hatchColor));
- switch(hatchType){
- case U_HS_SOLIDTEXTCLR:
- case U_HS_DITHEREDTEXTCLR:
- sprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].textColor));
- break;
- case U_HS_SOLIDBKCLR:
- case U_HS_DITHEREDBKCLR:
- sprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].bkColor));
- break;
- default:
- break;
- }
-
- // WMF can take solid colors from background or the default text color but on conversion to inkscape
- // these need to go to a defined color. Consequently the hatchType also has to go to a solid color, otherwise
- // on export the background/text might not match at the time this is written, and the colors will shift.
- if(hatchType > U_HS_SOLIDCLR)hatchType = U_HS_SOLIDCLR;
-
- sprintf(hatchname,"WMFhatch%d_%s",hatchType,tmpcolor);
- idx = in_hatches(d,hatchname);
- if(!idx){ // add it if not already present
- if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
- d->hatches.strings[d->hatches.count++]=strdup(hatchname);
-
- *(d->defs) += "\n";
- *(d->defs) += " <pattern id=\"";
- *(d->defs) += hatchname;
- *(d->defs) += "\"\n";
- switch(hatchType){
- case U_HS_HORIZONTAL:
- *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" >\n";
- *(d->defs) += " <path d=\"M 0 0 6 0\" style=\"fill:none;stroke:#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\" />\n";
+ char hatchname[64]; // big enough
+ char hpathname[64]; // big enough
+ char hbkname[64]; // big enough
+ char tmpcolor[8];
+ char bkcolor[8];
+ uint32_t idx;
+
+ switch(hatchType){
+ case U_HS_SOLIDTEXTCLR:
+ case U_HS_DITHEREDTEXTCLR:
+ sprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].textColor));
break;
- case U_HS_VERTICAL:
- *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" >\n";
- *(d->defs) += " <path d=\"M 0 0 0 6\" style=\"fill:none;stroke:#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\" />\n";
+ case U_HS_SOLIDBKCLR:
+ case U_HS_DITHEREDBKCLR:
+ sprintf(tmpcolor,"%6.6X",sethexcolor(d->dc[d->level].bkColor));
break;
- case U_HS_FDIAGONAL:
- *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" viewBox=\"0 0 6 6\" preserveAspectRatio=\"none\" >\n";
- *(d->defs) += " <line x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\" id=\"sub";
- *(d->defs) += hatchname;
- *(d->defs) += "\"/>\n";
- *(d->defs) += " <use xlink:href=\"#sub";
- *(d->defs) += hatchname;
- *(d->defs) += "\" transform=\"translate(6,0)\"/>\n";
- *(d->defs) += " <use xlink:href=\"#sub";
- *(d->defs) += hatchname;
- *(d->defs) += "\" transform=\"translate(-6,0)\"/>\n";
+ default:
+ sprintf(tmpcolor,"%6.6X",sethexcolor(hatchColor));
break;
- case U_HS_BDIAGONAL:
- *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" viewBox=\"0 0 6 6\" preserveAspectRatio=\"none\" >\n";
- *(d->defs) += " <line x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\" id=\"sub";
- *(d->defs) += hatchname;
- *(d->defs) += "\"/>\n";
- *(d->defs) += " <use xlink:href=\"#sub";
- *(d->defs) += hatchname;
- *(d->defs) += "\" transform=\"translate(6,0)\"/>\n";
- *(d->defs) += " <use xlink:href=\"#sub";
- *(d->defs) += hatchname;
- *(d->defs) += "\" transform=\"translate(-6,0)\"/>\n";
+ }
+
+ /* For both bkMode types set the PATH + FOREGROUND COLOR for the indicated standard hatch.
+ This will be used late to compose, or recompose the transparent or opaque final hatch.*/
+
+ std::string refpath; // used to reference later the path pieces which are about to be created
+ sprintf(hpathname,"WMFhpath%d_%s",hatchType,tmpcolor);
+ idx = in_hatches(d,hpathname);
+ if(!idx){ // add path/color if not already present
+ if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
+ d->hatches.strings[d->hatches.count++]=strdup(hpathname);
+
+ *(d->defs) += "\n";
+ switch(hatchType){
+ case U_HS_HORIZONTAL:
+ *(d->defs) += " <path id=\"";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" d=\"M 0 0 6 0\" style=\"fill:none;stroke:#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\" />\n";
+ break;
+ case U_HS_VERTICAL:
+ *(d->defs) += " <path id=\"";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" d=\"M 0 0 0 6\" style=\"fill:none;stroke:#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\" />\n";
+ break;
+ case U_HS_FDIAGONAL:
+ *(d->defs) += " <line id=\"sub";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\"/>\n";
+ break;
+ case U_HS_BDIAGONAL:
+ *(d->defs) += " <line id=\"sub";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\"/>\n";
+ break;
+ case U_HS_CROSS:
+ *(d->defs) += " <path id=\"";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" d=\"M 0 0 6 0 M 0 0 0 6\" style=\"fill:none;stroke:#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\" />\n";
+ break;
+ case U_HS_DIAGCROSS:
+ *(d->defs) += " <line id=\"subfd";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\"/>\n";
+ *(d->defs) += " <line id=\"subbd";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += "\"/>\n";
+ break;
+ case U_HS_SOLIDCLR:
+ case U_HS_DITHEREDCLR:
+ case U_HS_SOLIDTEXTCLR:
+ case U_HS_DITHEREDTEXTCLR:
+ case U_HS_SOLIDBKCLR:
+ case U_HS_DITHEREDBKCLR:
+ default:
+ *(d->defs) += " <path id=\"";
+ *(d->defs) += hpathname;
+ *(d->defs) += "\" d=\"M 0 0 6 0 6 6 0 6 z\" style=\"fill:#";
+ *(d->defs) += tmpcolor;
+ *(d->defs) += ";stroke:none";
+ *(d->defs) += "\" />\n";
+ break;
+ }
+ }
+
+ // References to paths possibly just created above. These will be used in the actual patterns.
+ switch(hatchType){
+ case U_HS_HORIZONTAL:
+ case U_HS_VERTICAL:
+ case U_HS_CROSS:
+ case U_HS_SOLIDCLR:
+ case U_HS_DITHEREDCLR:
+ case U_HS_SOLIDTEXTCLR:
+ case U_HS_DITHEREDTEXTCLR:
+ case U_HS_SOLIDBKCLR:
+ case U_HS_DITHEREDBKCLR:
+ default:
+ refpath += " <use xlink:href=\"#";
+ refpath += hpathname;
+ refpath += "\" />\n";
break;
- case U_HS_CROSS:
- *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" >\n";
- *(d->defs) += " <path d=\"M 0 0 6 0 M 0 0 0 6\" style=\"fill:none;stroke:#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\" />\n";
- break;
- case U_HS_DIAGCROSS:
- *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" viewBox=\"0 0 6 6\" preserveAspectRatio=\"none\" >\n";
- *(d->defs) += " <use xlink:href=\"#sub";
- sprintf(hatchname,"WMFhatch%d_%6.6X",U_HS_FDIAGONAL,sethexcolor(hatchColor));
+ case U_HS_FDIAGONAL:
+ case U_HS_BDIAGONAL:
+ refpath += " <use xlink:href=\"#sub";
+ refpath += hpathname;
+ refpath += "\" />\n";
+ refpath += " <use xlink:href=\"#sub";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(6,0)\" />\n";
+ refpath += " <use xlink:href=\"#sub";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(-6,0)\" />\n";
+ break;
+ case U_HS_DIAGCROSS:
+ refpath += " <use xlink:href=\"#subfd";
+ refpath += hpathname;
+ refpath += "\" />\n";
+ refpath += " <use xlink:href=\"#subfd";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(6,0)\"/>\n";
+ refpath += " <use xlink:href=\"#subfd";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(-6,0)\"/>\n";
+ refpath += " <use xlink:href=\"#subbd";
+ refpath += hpathname;
+ refpath += "\" />\n";
+ refpath += " <use xlink:href=\"#subbd";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(6,0)\"/>\n";
+ refpath += " <use xlink:href=\"#subbd";
+ refpath += hpathname;
+ refpath += "\" transform=\"translate(-6,0)\"/>\n";
+ break;
+ }
+
+ if(d->dc[d->level].bkMode == U_TRANSPARENT || hatchType >= U_HS_SOLIDCLR){
+ sprintf(hatchname,"WMFhatch%d_%s",hatchType,tmpcolor);
+ sprintf(hpathname,"WMFhpath%d_%s",hatchType,tmpcolor);
+ idx = in_hatches(d,hatchname);
+ if(!idx){ // add it if not already present
+ if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
+ d->hatches.strings[d->hatches.count++]=strdup(hatchname);
+ *(d->defs) += "\n";
+ *(d->defs) += " <pattern id=\"";
*(d->defs) += hatchname;
- *(d->defs) += "\" transform=\"translate(0,0)\"/>\n";
- *(d->defs) += " <use xlink:href=\"#sub";
- sprintf(hatchname,"WMFhatch%d_%6.6X",U_HS_BDIAGONAL,sethexcolor(hatchColor));
+ *(d->defs) += "\" xlink:href=\"#WMFhbasepattern\">\n";
+ *(d->defs) += refpath;
+ *(d->defs) += " </pattern>\n";
+ idx = d->hatches.count;
+ }
+ }
+ else { // bkMode==U_OPAQUE
+ /* Set up an object in the defs for this background, if there is not one already there */
+ sprintf(bkcolor,"%6.6X",sethexcolor(d->dc[d->level].bkColor));
+ sprintf(hbkname,"WMFhbkclr_%s",bkcolor);
+ idx = in_hatches(d,hbkname);
+ if(!idx){ // add path/color if not already present. Hatchtype is not needed in the name.
+ if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
+ d->hatches.strings[d->hatches.count++]=strdup(hbkname);
+
+ *(d->defs) += "\n";
+ *(d->defs) += " <rect id=\"";
+ *(d->defs) += hbkname;
+ *(d->defs) += "\" x=\"0\" y=\"0\" width=\"6\" height=\"6\" fill=\"#";
+ *(d->defs) += bkcolor;
+ *(d->defs) += "\" />\n";
+ }
+
+ // this is the pattern, its name will show up in Inkscape's pattern selector
+ sprintf(hatchname,"WMFhatch%d_%s_%s",hatchType,tmpcolor,bkcolor);
+ idx = in_hatches(d,hatchname);
+ if(!idx){ // add it if not already present
+ if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
+ d->hatches.strings[d->hatches.count++]=strdup(hatchname);
+ *(d->defs) += "\n";
+ *(d->defs) += " <pattern id=\"";
*(d->defs) += hatchname;
- *(d->defs) += "\" transform=\"translate(0,0)\"/>\n";
- break;
- case U_HS_SOLIDCLR:
- case U_HS_DITHEREDCLR:
- case U_HS_SOLIDTEXTCLR:
- case U_HS_DITHEREDTEXTCLR:
- case U_HS_SOLIDBKCLR:
- case U_HS_DITHEREDBKCLR:
- default:
- *(d->defs) += " patternUnits=\"userSpaceOnUse\" width=\"6\" height=\"6\" x=\"0\" y=\"0\" >\n";
- *(d->defs) += " <path d=\"M 0 0 6 0 6 6 0 6 z\" style=\"fill:#";
- *(d->defs) += tmpcolor;
- *(d->defs) += ";stroke:none";
+ *(d->defs) += "\" xlink:href=\"#WMFhbasepattern\">\n";
+ *(d->defs) += " <use xlink:href=\"#";
+ *(d->defs) += hbkname;
*(d->defs) += "\" />\n";
- break;
- }
- *(d->defs) += " ";
- *(d->defs) += " </pattern>\n";
- idx = d->hatches.count;
- }
- return(idx-1);
+ *(d->defs) += refpath;
+ *(d->defs) += " </pattern>\n";
+ idx = d->hatches.count;
+ }
+ }
+ return(idx-1);
}
/* Add another 100 blank slots to the images array.
*/
void Wmf::enlarge_images(PWMF_CALLBACK_DATA d){
- d->images.size += 100;
- d->images.strings = (char **) realloc(d->images.strings,d->images.size + sizeof(char *));
+ d->images.size += 100;
+ d->images.strings = (char **) realloc(d->images.strings,d->images.size * sizeof(char *));
}
/* See if the image string is already in the list. If it is return its position (1->n, not 1-n-1)
*/
int Wmf::in_images(PWMF_CALLBACK_DATA d, char *test){
- int i;
- for(i=0; i<d->images.count; i++){
- if(strcmp(test,d->images.strings[i])==0)return(i+1);
- }
- return(0);
+ int i;
+ for(i=0; i<d->images.count; i++){
+ if(strcmp(test,d->images.strings[i])==0)return(i+1);
+ }
+ return(0);
}
/* (Conditionally) add an image from a DIB. If a matching image already exists nothing happens. If one
- does not exist it is added to the images list and also entered into <defs>.
-
+ does not exist it is added to the images list and also entered into <defs>.
+
*/
uint32_t Wmf::add_dib_image(PWMF_CALLBACK_DATA d, const char *dib, uint32_t iUsage){
-
- uint32_t idx;
- char imagename[64]; // big enough
- char xywh[64]; // big enough
- int dibparams;
-
- MEMPNG mempng; // PNG in memory comes back in this
- mempng.buffer = NULL;
-
- char *rgba_px = NULL; // RGBA pixels
- const char *px = NULL; // DIB pixels
- const U_RGBQUAD *ct = NULL; // DIB color table
- int32_t width, height, colortype, numCt, invert;
- if((iUsage != U_DIB_RGB_COLORS) ||
- !(dibparams = wget_DIB_params( // this returns pointers and values, but allocates no memory
- dib,
- &px,
- &ct,
- &numCt,
- &width,
- &height,
- &colortype,
- &invert
- ))
- ){
-
- if(!DIB_to_RGBA(
- px, // DIB pixel array
- ct, // DIB color table
- numCt, // DIB color table number of entries
- &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free.
- width, // Width of pixel array in record
- height, // Height of pixel array in record
- colortype, // DIB BitCount Enumeration
- numCt, // Color table used if not 0
- invert // If DIB rows are in opposite order from RGBA rows
- ) &&
- rgba_px)
- {
- toPNG( // Get the image from the RGBA px into mempng
- &mempng,
- width, height, // of the SRC bitmap
- rgba_px);
- free(rgba_px);
- }
- }
- gchar *base64String;
- if(dibparams == U_BI_JPEG || dibparams==U_BI_PNG){
- base64String = g_base64_encode((guchar*) px, numCt );
- idx = in_images(d, (char *) base64String);
- }
- else if(mempng.buffer){
- base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
- free(mempng.buffer);
- idx = in_images(d, (char *) base64String);
- }
- else {
- // insert a random 3x4 blotch otherwise
- width = 3;
- height = 4;
- base64String = strdup("iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII=");
- idx = in_images(d, (char *) base64String);
- }
- if(!idx){ // add it if not already present - we looked at the actual data for comparison
- if(d->images.count == d->images.size){ enlarge_images(d); }
- idx = d->images.count;
- d->images.strings[d->images.count++]=strdup(base64String);
-
- sprintf(imagename,"WMFimage%d",idx++);
- sprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer
-
- *(d->defs) += "\n";
- *(d->defs) += " <image id=\"";
- *(d->defs) += imagename;
- *(d->defs) += "\"\n ";
- *(d->defs) += xywh;
- *(d->defs) += "\n";
- if(dibparams == U_BI_JPEG){ *(d->defs) += " xlink:href=\"data:image/jpeg;base64,"; }
- else { *(d->defs) += " xlink:href=\"data:image/png;base64,"; }
- *(d->defs) += base64String;
- *(d->defs) += "\"\n";
- *(d->defs) += " />\n";
-
-
- *(d->defs) += "\n";
- *(d->defs) += " <pattern id=\"";
- *(d->defs) += imagename;
- *(d->defs) += "_ref\"\n ";
- *(d->defs) += xywh;
- *(d->defs) += "\n patternUnits=\"userSpaceOnUse\"";
- *(d->defs) += " >\n";
- *(d->defs) += " <use id=\"";
- *(d->defs) += imagename;
- *(d->defs) += "_ign\" ";
- *(d->defs) += " xlink:href=\"#";
- *(d->defs) += imagename;
- *(d->defs) += "\" />\n";
- *(d->defs) += " ";
- *(d->defs) += " </pattern>\n";
- }
- g_free(base64String);
- return(idx-1);
+
+ uint32_t idx;
+ char imagename[64]; // big enough
+ char xywh[64]; // big enough
+ int dibparams;
+
+ MEMPNG mempng; // PNG in memory comes back in this
+ mempng.buffer = NULL;
+
+ char *rgba_px = NULL; // RGBA pixels
+ const char *px = NULL; // DIB pixels
+ const U_RGBQUAD *ct = NULL; // DIB color table
+ int32_t width, height, colortype, numCt, invert;
+ if((iUsage != U_DIB_RGB_COLORS) ||
+ !(dibparams = wget_DIB_params( // this returns pointers and values, but allocates no memory
+ dib,
+ &px,
+ &ct,
+ &numCt,
+ &width,
+ &height,
+ &colortype,
+ &invert
+ ))
+ ){
+
+ if(!DIB_to_RGBA(
+ px, // DIB pixel array
+ ct, // DIB color table
+ numCt, // DIB color table number of entries
+ &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free.
+ width, // Width of pixel array in record
+ height, // Height of pixel array in record
+ colortype, // DIB BitCount Enumeration
+ numCt, // Color table used if not 0
+ invert // If DIB rows are in opposite order from RGBA rows
+ ) &&
+ rgba_px
+ ){
+ toPNG( // Get the image from the RGBA px into mempng
+ &mempng,
+ width, height, // of the SRC bitmap
+ rgba_px
+ );
+ free(rgba_px);
+ }
+ }
+ gchar *base64String;
+ if(dibparams == U_BI_JPEG || dibparams==U_BI_PNG){
+ base64String = g_base64_encode((guchar*) px, numCt );
+ idx = in_images(d, (char *) base64String);
+ }
+ else if(mempng.buffer){
+ base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
+ free(mempng.buffer);
+ idx = in_images(d, (char *) base64String);
+ }
+ else {
+ // insert a random 3x4 blotch otherwise
+ width = 3;
+ height = 4;
+ base64String = g_strdup("iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII=");
+ idx = in_images(d, (char *) base64String);
+ }
+ if(!idx){ // add it if not already present - we looked at the actual data for comparison
+ if(d->images.count == d->images.size){ enlarge_images(d); }
+ idx = d->images.count;
+ d->images.strings[d->images.count++]=strdup(base64String);
+
+ sprintf(imagename,"WMFimage%d",idx++);
+ sprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer
+
+ *(d->defs) += "\n";
+ *(d->defs) += " <image id=\"";
+ *(d->defs) += imagename;
+ *(d->defs) += "\"\n ";
+ *(d->defs) += xywh;
+ *(d->defs) += "\n";
+ if(dibparams == U_BI_JPEG){ *(d->defs) += " xlink:href=\"data:image/jpeg;base64,"; }
+ else { *(d->defs) += " xlink:href=\"data:image/png;base64,"; }
+ *(d->defs) += base64String;
+ *(d->defs) += "\"\n";
+ *(d->defs) += " />\n";
+
+
+ *(d->defs) += "\n";
+ *(d->defs) += " <pattern id=\"";
+ *(d->defs) += imagename;
+ *(d->defs) += "_ref\"\n ";
+ *(d->defs) += xywh;
+ *(d->defs) += "\n patternUnits=\"userSpaceOnUse\"";
+ *(d->defs) += " >\n";
+ *(d->defs) += " <use id=\"";
+ *(d->defs) += imagename;
+ *(d->defs) += "_ign\" ";
+ *(d->defs) += " xlink:href=\"#";
+ *(d->defs) += imagename;
+ *(d->defs) += "\" />\n";
+ *(d->defs) += " ";
+ *(d->defs) += " </pattern>\n";
+ }
+ g_free(base64String);
+ return(idx-1);
}
/* (Conditionally) add an image from a Bitmap16. If a matching image already exists nothing happens. If one
- does not exist it is added to the images list and also entered into <defs>.
-
+ does not exist it is added to the images list and also entered into <defs>.
+
*/
uint32_t Wmf::add_bm16_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char *px){
-
- uint32_t idx;
- char imagename[64]; // big enough
- char xywh[64]; // big enough
-
- MEMPNG mempng; // PNG in memory comes back in this
- mempng.buffer = NULL;
-
- char *rgba_px = NULL; // RGBA pixels
- const U_RGBQUAD *ct = NULL; // color table, always NULL here
- int32_t width, height, colortype, numCt, invert;
- numCt = 0;
- width = Bm16.Width; // bitmap width in pixels.
- height = Bm16.Height; // bitmap height in scan lines.
- colortype = Bm16.BitsPixel; // seems to be BitCount Enumeration
- invert = 0;
- if(colortype < 16)return(0xFFFFFFFF); // these would need a colortable if they were a dib, no idea what bm16 is supposed to do instead.
-
- if(!DIB_to_RGBA( // This is not really a dib, but close enough...
- px, // DIB pixel array
- ct, // DIB color table (always NULL here)
- numCt, // DIB color table number of entries (always 0)
- &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free.
- width, // Width of pixel array
- height, // Height of pixel array
- colortype, // DIB BitCount Enumeration
- numCt, // Color table used if not 0
- invert // If DIB rows are in opposite order from RGBA rows
- ) && rgba_px)
- {
- toPNG( // Get the image from the RGBA px into mempng
- &mempng,
- width, height, // of the SRC bitmap
- rgba_px);
- free(rgba_px);
- }
- gchar *base64String;
- if(mempng.buffer){
- base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
- free(mempng.buffer);
- }
- else {
- // insert a random 3x4 blotch otherwise
- width = 3;
- height = 4;
- base64String = strdup("iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII=");
- }
- idx = in_images(d, (char *) base64String);
- if(!idx){ // add it if not already present - we looked at the actual data for comparison
- if(d->images.count == d->images.size){ enlarge_images(d); }
- idx = d->images.count;
- d->images.strings[d->images.count++]=strdup(base64String);
-
- sprintf(imagename,"WMFimage%d",idx++);
- sprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer
-
- *(d->defs) += "\n";
- *(d->defs) += " <image id=\"";
- *(d->defs) += imagename;
- *(d->defs) += "\"\n ";
- *(d->defs) += xywh;
- *(d->defs) += "\n";
- *(d->defs) += " xlink:href=\"data:image/png;base64,";
- *(d->defs) += base64String;
- *(d->defs) += "\"\n";
- *(d->defs) += " />\n";
-
-
- *(d->defs) += "\n";
- *(d->defs) += " <pattern id=\"";
- *(d->defs) += imagename;
- *(d->defs) += "_ref\"\n ";
- *(d->defs) += xywh;
- *(d->defs) += "\n patternUnits=\"userSpaceOnUse\"";
- *(d->defs) += " >\n";
- *(d->defs) += " <use id=\"";
- *(d->defs) += imagename;
- *(d->defs) += "_ign\" ";
- *(d->defs) += " xlink:href=\"#";
- *(d->defs) += imagename;
- *(d->defs) += "\" />\n";
- *(d->defs) += " ";
- *(d->defs) += " </pattern>\n";
- }
- g_free(base64String);
- return(idx-1);
+
+ uint32_t idx;
+ char imagename[64]; // big enough
+ char xywh[64]; // big enough
+
+ MEMPNG mempng; // PNG in memory comes back in this
+ mempng.buffer = NULL;
+
+ char *rgba_px = NULL; // RGBA pixels
+ const U_RGBQUAD *ct = NULL; // color table, always NULL here
+ int32_t width, height, colortype, numCt, invert;
+ numCt = 0;
+ width = Bm16.Width; // bitmap width in pixels.
+ height = Bm16.Height; // bitmap height in scan lines.
+ colortype = Bm16.BitsPixel; // seems to be BitCount Enumeration
+ invert = 0;
+ if(colortype < 16)return(0xFFFFFFFF); // these would need a colortable if they were a dib, no idea what bm16 is supposed to do instead.
+
+ if(!DIB_to_RGBA(// This is not really a dib, but close enough...
+ px, // DIB pixel array
+ ct, // DIB color table (always NULL here)
+ numCt, // DIB color table number of entries (always 0)
+ &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free.
+ width, // Width of pixel array
+ height, // Height of pixel array
+ colortype, // DIB BitCount Enumeration
+ numCt, // Color table used if not 0
+ invert // If DIB rows are in opposite order from RGBA rows
+ ) && rgba_px)
+ {
+ toPNG( // Get the image from the RGBA px into mempng
+ &mempng,
+ width, height, // of the SRC bitmap
+ rgba_px
+ );
+ free(rgba_px);
+ }
+ gchar *base64String;
+ if(mempng.buffer){
+ base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
+ free(mempng.buffer);
+ }
+ else {
+ // insert a random 3x4 blotch otherwise
+ width = 3;
+ height = 4;
+ base64String = g_strdup("iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII=");
+ }
+ idx = in_images(d, (char *) base64String);
+ if(!idx){ // add it if not already present - we looked at the actual data for comparison
+ if(d->images.count == d->images.size){ enlarge_images(d); }
+ idx = d->images.count;
+ d->images.strings[d->images.count++]=g_strdup(base64String);
+
+ sprintf(imagename,"WMFimage%d",idx++);
+ sprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer
+
+ *(d->defs) += "\n";
+ *(d->defs) += " <image id=\"";
+ *(d->defs) += imagename;
+ *(d->defs) += "\"\n ";
+ *(d->defs) += xywh;
+ *(d->defs) += "\n";
+ *(d->defs) += " xlink:href=\"data:image/png;base64,";
+ *(d->defs) += base64String;
+ *(d->defs) += "\"\n";
+ *(d->defs) += " />\n";
+
+
+ *(d->defs) += "\n";
+ *(d->defs) += " <pattern id=\"";
+ *(d->defs) += imagename;
+ *(d->defs) += "_ref\"\n ";
+ *(d->defs) += xywh;
+ *(d->defs) += "\n patternUnits=\"userSpaceOnUse\"";
+ *(d->defs) += " >\n";
+ *(d->defs) += " <use id=\"";
+ *(d->defs) += imagename;
+ *(d->defs) += "_ign\" ";
+ *(d->defs) += " xlink:href=\"#";
+ *(d->defs) += imagename;
+ *(d->defs) += "\" />\n";
+ *(d->defs) += " </pattern>\n";
+ }
+ g_free(base64String);
+ return(idx-1);
}
void
@@ -713,74 +798,74 @@ Wmf::output_style(PWMF_CALLBACK_DATA d)
sp_color_get_rgb_floatv( &(d->dc[d->level].style.fill.value.color), fill_rgb );
float stroke_rgb[3];
sp_color_get_rgb_floatv(&(d->dc[d->level].style.stroke.value.color), stroke_rgb);
-
+
// for U_WMR_BITBLT with no image, try to approximate some of these operations/
// Assume src color is "white"
if(d->dwRop3){
- switch(d->dwRop3){
- case U_PATINVERT: // treat all of these as black
- case U_SRCINVERT:
- case U_DSTINVERT:
- case U_BLACKNESS:
- case U_SRCERASE:
- case U_NOTSRCCOPY:
- fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=0.0;
- break;
- case U_SRCCOPY: // treat all of these as white
- case U_NOTSRCERASE:
- case U_PATCOPY:
- case U_WHITENESS:
- fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=1.0;
- break;
- case U_SRCPAINT: // use the existing color
- case U_SRCAND:
- case U_MERGECOPY:
- case U_MERGEPAINT:
- case U_PATPAINT:
- default:
- break;
- }
- d->dwRop3 = 0; // might as well reset it here, it must be set for each BITBLT
+ switch(d->dwRop3){
+ case U_PATINVERT: // treat all of these as black
+ case U_SRCINVERT:
+ case U_DSTINVERT:
+ case U_BLACKNESS:
+ case U_SRCERASE:
+ case U_NOTSRCCOPY:
+ fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=0.0;
+ break;
+ case U_SRCCOPY: // treat all of these as white
+ case U_NOTSRCERASE:
+ case U_PATCOPY:
+ case U_WHITENESS:
+ fill_rgb[0]=fill_rgb[1]=fill_rgb[2]=1.0;
+ break;
+ case U_SRCPAINT: // use the existing color
+ case U_SRCAND:
+ case U_MERGECOPY:
+ case U_MERGEPAINT:
+ case U_PATPAINT:
+ default:
+ break;
+ }
+ d->dwRop3 = 0; // might as well reset it here, it must be set for each BITBLT
}
// Implement some of these, the ones where the original screen color does not matter.
- // The options that merge screen and pen colors cannot be done correctly because we
+ // The options that merge screen and pen colors cannot be done correctly because we
// have no way of knowing what color is already on the screen. For those just pass the
- // pen color through.
+ // pen color through.
switch(d->dwRop2){
- case U_R2_BLACK:
- fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 0.0;
- stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 0.0;
- break;
- case U_R2_NOTMERGEPEN:
- case U_R2_MASKNOTPEN:
- break;
- case U_R2_NOTCOPYPEN:
- fill_rgb[0] = 1.0 - fill_rgb[0];
- fill_rgb[1] = 1.0 - fill_rgb[1];
- fill_rgb[2] = 1.0 - fill_rgb[2];
- stroke_rgb[0] = 1.0 - stroke_rgb[0];
- stroke_rgb[1] = 1.0 - stroke_rgb[1];
- stroke_rgb[2] = 1.0 - stroke_rgb[2];
- break;
- case U_R2_MASKPENNOT:
- case U_R2_NOT:
- case U_R2_XORPEN:
- case U_R2_NOTMASKPEN:
- case U_R2_NOTXORPEN:
- case U_R2_NOP:
- case U_R2_MERGENOTPEN:
- case U_R2_COPYPEN:
- case U_R2_MASKPEN:
- case U_R2_MERGEPENNOT:
- case U_R2_MERGEPEN:
- break;
- case U_R2_WHITE:
- fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 1.0;
- stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 1.0;
- break;
- default:
- break;
+ case U_R2_BLACK:
+ fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 0.0;
+ stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 0.0;
+ break;
+ case U_R2_NOTMERGEPEN:
+ case U_R2_MASKNOTPEN:
+ break;
+ case U_R2_NOTCOPYPEN:
+ fill_rgb[0] = 1.0 - fill_rgb[0];
+ fill_rgb[1] = 1.0 - fill_rgb[1];
+ fill_rgb[2] = 1.0 - fill_rgb[2];
+ stroke_rgb[0] = 1.0 - stroke_rgb[0];
+ stroke_rgb[1] = 1.0 - stroke_rgb[1];
+ stroke_rgb[2] = 1.0 - stroke_rgb[2];
+ break;
+ case U_R2_MASKPENNOT:
+ case U_R2_NOT:
+ case U_R2_XORPEN:
+ case U_R2_NOTMASKPEN:
+ case U_R2_NOTXORPEN:
+ case U_R2_NOP:
+ case U_R2_MERGENOTPEN:
+ case U_R2_COPYPEN:
+ case U_R2_MASKPEN:
+ case U_R2_MERGEPENNOT:
+ case U_R2_MERGEPEN:
+ break;
+ case U_R2_WHITE:
+ fill_rgb[0] = fill_rgb[1] = fill_rgb[2] = 1.0;
+ stroke_rgb[0]= stroke_rgb[1]= stroke_rgb[2] = 1.0;
+ break;
+ default:
+ break;
}
@@ -793,33 +878,48 @@ Wmf::output_style(PWMF_CALLBACK_DATA d)
switch(d->dc[d->level].fill_mode){
// both of these use the url(#) method
case DRAW_PATTERN:
- snprintf(tmp, 1023, "fill:url(#%s); ",d->hatches.strings[d->dc[d->level].fill_idx]);
- tmp_style << tmp;
- break;
+ snprintf(tmp, 1023, "fill:url(#%s); ",d->hatches.strings[d->dc[d->level].fill_idx]);
+ tmp_style << tmp;
+ break;
case DRAW_IMAGE:
- snprintf(tmp, 1023, "fill:url(#WMFimage%d_ref); ",d->dc[d->level].fill_idx);
- tmp_style << tmp;
- break;
+ snprintf(tmp, 1023, "fill:url(#WMFimage%d_ref); ",d->dc[d->level].fill_idx);
+ tmp_style << tmp;
+ break;
case DRAW_PAINT:
default: // <-- this should never happen, but just in case...
- snprintf(tmp, 1023,
- "fill:#%02x%02x%02x;",
- SP_COLOR_F_TO_U(fill_rgb[0]),
- SP_COLOR_F_TO_U(fill_rgb[1]),
- SP_COLOR_F_TO_U(fill_rgb[2]));
- tmp_style << tmp;
- break;
- }
- snprintf(tmp, 1023,
- "fill-rule:%s;",
- d->dc[d->level].style.fill_rule.value == 0 ? "evenodd" : "nonzero");
+ snprintf(
+ tmp, 1023,
+ "fill:#%02x%02x%02x;",
+ SP_COLOR_F_TO_U(fill_rgb[0]),
+ SP_COLOR_F_TO_U(fill_rgb[1]),
+ SP_COLOR_F_TO_U(fill_rgb[2])
+ );
+ tmp_style << tmp;
+ break;
+ }
+ snprintf(
+ tmp, 1023,
+ "fill-rule:%s;",
+ (d->dc[d->level].style.fill_rule.value == 0 ? "evenodd" : "nonzero")
+ );
tmp_style << tmp;
tmp_style << "fill-opacity:1;";
- // if the stroke is the same color as the fill, and the right size, do not do it separately
- if (d->dc[d->level].fill_set && d->dc[d->level].stroke_set && d->dc[d->level].style.stroke_width.value == 1 &&
- fill_rgb[0]==stroke_rgb[0] && fill_rgb[1]==stroke_rgb[1] && fill_rgb[2]==stroke_rgb[2])
- {
+ // if the stroke is the same as the fill, and the right size not to change the end size of the object, do not do it separately
+ if(
+ (d->dc[d->level].fill_set ) &&
+ (d->dc[d->level].stroke_set ) &&
+ (d->dc[d->level].style.stroke_width.value == 1 ) &&
+ (d->dc[d->level].fill_mode == d->dc[d->level].stroke_mode) &&
+ (
+ (d->dc[d->level].fill_mode != DRAW_PAINT) ||
+ (
+ (fill_rgb[0]==stroke_rgb[0]) &&
+ (fill_rgb[1]==stroke_rgb[1]) &&
+ (fill_rgb[2]==stroke_rgb[2])
+ )
+ )
+ ){
d->dc[d->level].stroke_set = false;
}
}
@@ -830,42 +930,48 @@ Wmf::output_style(PWMF_CALLBACK_DATA d)
switch(d->dc[d->level].stroke_mode){
// both of these use the url(#) method
case DRAW_PATTERN:
- snprintf(tmp, 1023, "stroke:url(#%s); ",d->hatches.strings[d->dc[d->level].stroke_idx]);
- tmp_style << tmp;
- break;
+ snprintf(tmp, 1023, "stroke:url(#%s); ",d->hatches.strings[d->dc[d->level].stroke_idx]);
+ tmp_style << tmp;
+ break;
case DRAW_IMAGE:
- snprintf(tmp, 1023, "stroke:url(#WMFimage%d_ref); ",d->dc[d->level].stroke_idx);
- tmp_style << tmp;
- break;
+ snprintf(tmp, 1023, "stroke:url(#WMFimage%d_ref); ",d->dc[d->level].stroke_idx);
+ tmp_style << tmp;
+ break;
case DRAW_PAINT:
default: // <-- this should never happen, but just in case...
- snprintf(tmp, 1023,
- "stroke:#%02x%02x%02x;",
- SP_COLOR_F_TO_U(stroke_rgb[0]),
- SP_COLOR_F_TO_U(stroke_rgb[1]),
- SP_COLOR_F_TO_U(stroke_rgb[2]));
- tmp_style << tmp;
- break;
+ snprintf(
+ tmp, 1023,
+ "stroke:#%02x%02x%02x;",
+ SP_COLOR_F_TO_U(stroke_rgb[0]),
+ SP_COLOR_F_TO_U(stroke_rgb[1]),
+ SP_COLOR_F_TO_U(stroke_rgb[2])
+ );
+ tmp_style << tmp;
+ break;
}
if(d->dc[d->level].style.stroke_width.value){
- tmp_style << "stroke-width:" <<
- MAX( 0.001, d->dc[d->level].style.stroke_width.value ) << "px;";
+ tmp_style << "stroke-width:" <<
+ MAX( 0.001, d->dc[d->level].style.stroke_width.value ) << "px;";
}
else { // In a WMF a 0 width pixel means "1 pixel"
- tmp_style << "stroke-width:" << pix_to_abs_size( d, 1 ) << "px;";
+ tmp_style << "stroke-width:" << pix_to_abs_size( d, 1 ) << "px;";
}
tmp_style << "stroke-linecap:" <<
- (d->dc[d->level].style.stroke_linecap.computed == 0 ? "butt" :
- d->dc[d->level].style.stroke_linecap.computed == 1 ? "round" :
- d->dc[d->level].style.stroke_linecap.computed == 2 ? "square" :
- "unknown") << ";";
+ (
+ d->dc[d->level].style.stroke_linecap.computed == 0 ? "butt" :
+ d->dc[d->level].style.stroke_linecap.computed == 1 ? "round" :
+ d->dc[d->level].style.stroke_linecap.computed == 2 ? "square" :
+ "unknown"
+ ) << ";";
tmp_style << "stroke-linejoin:" <<
- (d->dc[d->level].style.stroke_linejoin.computed == 0 ? "miter" :
- d->dc[d->level].style.stroke_linejoin.computed == 1 ? "round" :
- d->dc[d->level].style.stroke_linejoin.computed == 2 ? "bevel" :
- "unknown") << ";";
+ (
+ d->dc[d->level].style.stroke_linejoin.computed == 0 ? "miter" :
+ d->dc[d->level].style.stroke_linejoin.computed == 1 ? "round" :
+ d->dc[d->level].style.stroke_linejoin.computed == 2 ? "bevel" :
+ "unknown"
+ ) << ";";
// Set miter limit if known, even if it is not needed immediately (not miter)
tmp_style << "stroke-miterlimit:" <<
@@ -930,7 +1036,7 @@ Wmf::pix_to_y_point(PWMF_CALLBACK_DATA d, double px, double py)
{
double y = _pix_y_to_point(d, py);
-
+
return y;
}
@@ -945,11 +1051,11 @@ Wmf::pix_to_abs_size(PWMF_CALLBACK_DATA d, double px)
/* returns "x,y" (without the quotes) in inkscape coordinates for a pair of WMF x,y coordinates
*/
std::string Wmf::pix_to_xy(PWMF_CALLBACK_DATA d, double x, double y){
- std::stringstream cxform;
- cxform << pix_to_x_point(d,x,y);
- cxform << ",";
- cxform << pix_to_y_point(d,x,y);
- return(cxform.str());
+ std::stringstream cxform;
+ cxform << pix_to_x_point(d,x,y);
+ cxform << ",";
+ cxform << pix_to_y_point(d,x,y);
+ return(cxform.str());
}
@@ -960,14 +1066,14 @@ Wmf::select_pen(PWMF_CALLBACK_DATA d, int index)
char *record = NULL;
U_PEN up;
- if (index < 0 && index >= d->n_obj)return;
+ if (index < 0 && index >= d->n_obj){ return; }
record = d->wmf_obj[index].record;
- if(!record)return;
+ if(!record){ return; }
d->dc[d->level].active_pen = index;
-
+
(void) U_WMRCREATEPENINDIRECT_get(record, &up);
width = up.Widthw[0]; // width is stored in the first 16 bits of the 32.
-
+
switch (up.Style & U_PS_STYLE_MASK) {
case U_PS_DASH:
case U_PS_DOT:
@@ -993,11 +1099,11 @@ Wmf::select_pen(PWMF_CALLBACK_DATA d, int index)
d->dc[d->level].style.stroke_dash.dash[i++] = 1;
d->dc[d->level].style.stroke_dash.dash[i++] = 1;
}
-
+
d->dc[d->level].style.stroke_dasharray_set = 1;
break;
}
-
+
case U_PS_SOLID:
default:
{
@@ -1062,64 +1168,64 @@ Wmf::select_brush(PWMF_CALLBACK_DATA d, int index)
iType = *(uint8_t *)(record + offsetof(U_METARECORD, iType ) );
if(iType == U_WMR_CREATEBRUSHINDIRECT){
- U_WLOGBRUSH lb;
- (void) U_WMRCREATEBRUSHINDIRECT_get(record, &membrush);
- memcpy(&lb, membrush, U_SIZE_WLOGBRUSH);
- if(lb.Style == U_BS_SOLID){
- double r, g, b;
- r = SP_COLOR_U_TO_F( U_RGBAGetR(lb.Color) );
- g = SP_COLOR_U_TO_F( U_RGBAGetG(lb.Color) );
- b = SP_COLOR_U_TO_F( U_RGBAGetB(lb.Color) );
- d->dc[d->level].style.fill.value.color.set( r, g, b );
- d->dc[d->level].fill_mode = DRAW_PAINT;
- d->dc[d->level].fill_set = true;
- }
- else if(lb.Style == U_BS_HATCHED){
- d->dc[d->level].fill_idx = add_hatch(d, lb.Hatch, lb.Color);
- d->dc[d->level].fill_mode = DRAW_PATTERN;
- d->dc[d->level].fill_set = true;
- }
- else if(lb.Style == U_BS_NULL){
- d->dc[d->level].fill_mode = DRAW_PAINT; // set it to something
- d->dc[d->level].fill_set = false;
- }
-
+ U_WLOGBRUSH lb;
+ (void) U_WMRCREATEBRUSHINDIRECT_get(record, &membrush);
+ memcpy(&lb, membrush, U_SIZE_WLOGBRUSH);
+ if(lb.Style == U_BS_SOLID){
+ double r, g, b;
+ r = SP_COLOR_U_TO_F( U_RGBAGetR(lb.Color) );
+ g = SP_COLOR_U_TO_F( U_RGBAGetG(lb.Color) );
+ b = SP_COLOR_U_TO_F( U_RGBAGetB(lb.Color) );
+ d->dc[d->level].style.fill.value.color.set( r, g, b );
+ d->dc[d->level].fill_mode = DRAW_PAINT;
+ d->dc[d->level].fill_set = true;
+ }
+ else if(lb.Style == U_BS_HATCHED){
+ d->dc[d->level].fill_idx = add_hatch(d, lb.Hatch, lb.Color);
+ d->dc[d->level].fill_recidx = index; // used if the hatch needs to be redone due to bkMode, textmode, etc. changes
+ d->dc[d->level].fill_mode = DRAW_PATTERN;
+ d->dc[d->level].fill_set = true;
+ }
+ else if(lb.Style == U_BS_NULL){
+ d->dc[d->level].fill_mode = DRAW_PAINT; // set it to something
+ d->dc[d->level].fill_set = false;
+ }
}
else if(iType == U_WMR_DIBCREATEPATTERNBRUSH){
- uint32_t tidx;
- uint16_t Style;
- uint16_t cUsage;
- const char *Bm16h; // Pointer to Bitmap16 header (px follows)
- const char *dib; // Pointer to DIB
- (void) U_WMRDIBCREATEPATTERNBRUSH_get(record, &Style, &cUsage, &Bm16h, &dib);
- // Bm16 not handled yet
- if(dib || Bm16h){
- if(dib){ tidx = add_dib_image(d, dib, cUsage); }
- else if(Bm16h){
- U_BITMAP16 Bm16;
- const char *px;
- memcpy(&Bm16, Bm16h, U_SIZE_BITMAP16);
- px = Bm16h + U_SIZE_BITMAP16;
- tidx = add_bm16_image(d, Bm16, px);
- }
- if(tidx == 0xFFFFFFFF){ // Problem with the image, for instance, an unsupported bitmap16 type
- double r, g, b;
- r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor));
- g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor));
- b = SP_COLOR_U_TO_F( U_RGBAGetB(d->dc[d->level].textColor));
- d->dc[d->level].style.fill.value.color.set( r, g, b );
- d->dc[d->level].fill_mode = DRAW_PAINT;
- }
- else {
- d->dc[d->level].fill_idx = tidx;
- d->dc[d->level].fill_mode = DRAW_IMAGE;
- }
- d->dc[d->level].fill_set = true;
- }
- else {
- std::cout << "Please send WMF file to developers - select_brush U_WMR_DIBCREATEPATTERNBRUSH not bm16 or dib, not handled" << std::endl;
- }
- }
+ uint32_t tidx;
+ uint16_t Style;
+ uint16_t cUsage;
+ const char *Bm16h; // Pointer to Bitmap16 header (px follows)
+ const char *dib; // Pointer to DIB
+ (void) U_WMRDIBCREATEPATTERNBRUSH_get(record, &Style, &cUsage, &Bm16h, &dib);
+ // Bm16 not handled yet
+ if(dib || Bm16h){
+ if(dib){ tidx = add_dib_image(d, dib, cUsage); }
+ else if(Bm16h){
+ U_BITMAP16 Bm16;
+ const char *px;
+ memcpy(&Bm16, Bm16h, U_SIZE_BITMAP16);
+ px = Bm16h + U_SIZE_BITMAP16;
+ tidx = add_bm16_image(d, Bm16, px);
+ }
+ if(tidx == 0xFFFFFFFF){ // Problem with the image, for instance, an unsupported bitmap16 type
+ double r, g, b;
+ r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor));
+ g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor));
+ b = SP_COLOR_U_TO_F( U_RGBAGetB(d->dc[d->level].textColor));
+ d->dc[d->level].style.fill.value.color.set( r, g, b );
+ d->dc[d->level].fill_mode = DRAW_PAINT;
+ }
+ else {
+ d->dc[d->level].fill_idx = tidx;
+ d->dc[d->level].fill_mode = DRAW_IMAGE;
+ }
+ d->dc[d->level].fill_set = true;
+ }
+ else {
+ g_message("Please send WMF file to developers - select_brush U_WMR_DIBCREATEPATTERNBRUSH not bm16 or dib, not handled");
+ }
+ }
}
@@ -1135,24 +1241,24 @@ Wmf::select_font(PWMF_CALLBACK_DATA d, int index)
record = d->wmf_obj[index].record;
if (!record)return;
d->dc[d->level].active_font = index;
-
+
(void) U_WMRCREATEFONTINDIRECT_get(record, &memfont);
memcpy(&font,memfont,U_SIZE_FONT_CORE); //make sure it is in a properly aligned structure before touching it
facename = memfont + U_SIZE_FONT_CORE;
- /* The logfont information always starts with a U_LOGFONT structure but the U_WMRCREATEFONTINDIRECT
- is defined as U_LOGFONT_PANOSE so it can handle one of those if that is actually present. Currently only logfont
- is supported, and the remainder, it it really is a U_LOGFONT_PANOSE record, is ignored
+ /* The logfont information always starts with a U_LOGFONT structure but the U_WMRCREATEFONTINDIRECT
+ is defined as U_LOGFONT_PANOSE so it can handle one of those if that is actually present. Currently only logfont
+ is supported, and the remainder, it it really is a U_LOGFONT_PANOSE record, is ignored
*/
int cur_level = d->level;
d->level = d->wmf_obj[index].level;
double font_size = pix_to_abs_size( d, font.Height );
- /* snap the font_size to the nearest 1/32nd of a point.
- (The size is converted from Pixels to points, snapped, and converted back.)
- See the notes where d->D2Pscale[XY] are set for the reason why.
- Typically this will set the font to the desired exact size. If some peculiar size
- was intended this will, at worst, make it .03125 off, which is unlikely to be a problem. */
+ /* snap the font_size to the nearest 1/32nd of a point.
+ (The size is converted from Pixels to points, snapped, and converted back.)
+ See the notes where d->D2Pscale[XY] are set for the reason why.
+ Typically this will set the font to the desired exact size. If some peculiar size
+ was intended this will, at worst, make it .03125 off, which is unlikely to be a problem. */
font_size = round(20.0 * 0.8 * font_size)/(20.0 * 0.8);
d->level = cur_level;
d->dc[d->level].style.font_size.computed = font_size;
@@ -1177,17 +1283,17 @@ Wmf::select_font(PWMF_CALLBACK_DATA d, int index)
// malformed WMF with empty filename may exist, ignore font change if encountered
if(d->dc[d->level].font_name)free(d->dc[d->level].font_name);
- if(*facename){
- d->dc[d->level].font_name = strdup(facename);
+ if(*facename){
+ d->dc[d->level].font_name = strdup(facename);
}
else { // Malformed WMF might specify an empty font name
- d->dc[d->level].font_name = strdup("Arial"); // Default font, WMF spec says device can pick whatever it wants
+ d->dc[d->level].font_name = strdup("Arial"); // Default font, WMF spec says device can pick whatever it wants
}
d->dc[d->level].style.baseline_shift.value = ((font.Escapement + 3600) % 3600) / 10; // use baseline_shift instead of text_transform to avoid overflow
}
-/* Find the first free hole where an object may be stored.
- If there are not any return -1. This is a big error, possibly from a corrupt WMF file.
+/* Find the first free hole where an object may be stored.
+ If there are not any return -1. This is a big error, possibly from a corrupt WMF file.
*/
int Wmf::insertable_object(PWMF_CALLBACK_DATA d)
{
@@ -1202,31 +1308,31 @@ void
Wmf::delete_object(PWMF_CALLBACK_DATA d, int index)
{
if (index >= 0 && index < d->n_obj) {
- // If the active object is deleted set default draw values
- if(index == d->dc[d->level].active_pen){ // Use default pen: solid, black, 1 pixel wide
- d->dc[d->level].active_pen = -1;
- d->dc[d->level].style.stroke_dasharray_set = 0;
- d->dc[d->level].style.stroke_linecap.computed = 2; // U_PS_ENDCAP_SQUARE
- d->dc[d->level].style.stroke_linejoin.computed = 0; // U_PS_JOIN_MITER;
- d->dc[d->level].stroke_set = true;
- d->dc[d->level].style.stroke_width.value = 1.0;
- d->dc[d->level].style.stroke.value.color.set( 0, 0, 0 );
- }
- else if(index == d->dc[d->level].active_brush){
- d->dc[d->level].active_brush = -1;
- d->dc[d->level].fill_set = false;
- }
- else if(index == d->dc[d->level].active_font){
- d->dc[d->level].active_font = -1;
- if(d->dc[d->level].font_name){ free(d->dc[d->level].font_name);}
- d->dc[d->level].font_name = strdup("Arial"); // Default font, WMF spec says device can pick whatever it wants
- d->dc[d->level].style.font_size.computed = 16.0;
- d->dc[d->level].style.font_weight.value = SP_CSS_FONT_WEIGHT_400;
- d->dc[d->level].style.font_style.value = SP_CSS_FONT_STYLE_NORMAL;
- d->dc[d->level].style.text_decoration.underline = 0;
- d->dc[d->level].style.text_decoration.line_through = 0;
- d->dc[d->level].style.baseline_shift.value = 0;
- }
+ // If the active object is deleted set default draw values
+ if(index == d->dc[d->level].active_pen){ // Use default pen: solid, black, 1 pixel wide
+ d->dc[d->level].active_pen = -1;
+ d->dc[d->level].style.stroke_dasharray_set = 0;
+ d->dc[d->level].style.stroke_linecap.computed = 2; // U_PS_ENDCAP_SQUARE
+ d->dc[d->level].style.stroke_linejoin.computed = 0; // U_PS_JOIN_MITER;
+ d->dc[d->level].stroke_set = true;
+ d->dc[d->level].style.stroke_width.value = 1.0;
+ d->dc[d->level].style.stroke.value.color.set( 0, 0, 0 );
+ }
+ else if(index == d->dc[d->level].active_brush){
+ d->dc[d->level].active_brush = -1;
+ d->dc[d->level].fill_set = false;
+ }
+ else if(index == d->dc[d->level].active_font){
+ d->dc[d->level].active_font = -1;
+ if(d->dc[d->level].font_name){ free(d->dc[d->level].font_name);}
+ d->dc[d->level].font_name = strdup("Arial"); // Default font, WMF spec says device can pick whatever it wants
+ d->dc[d->level].style.font_size.computed = 16.0;
+ d->dc[d->level].style.font_weight.value = SP_CSS_FONT_WEIGHT_400;
+ d->dc[d->level].style.font_style.value = SP_CSS_FONT_STYLE_NORMAL;
+ d->dc[d->level].style.text_decoration.underline = 0;
+ d->dc[d->level].style.text_decoration.line_through = 0;
+ d->dc[d->level].style.baseline_shift.value = 0;
+ }
d->wmf_obj[index].type = 0;
@@ -1245,77 +1351,76 @@ Wmf::delete_object(PWMF_CALLBACK_DATA d, int index)
// returns the new index, or -1 on error.
int Wmf::insert_object(PWMF_CALLBACK_DATA d, int type, const char *record)
{
- int index = insertable_object(d);
- if(index>=0){
- d->wmf_obj[index].type = type;
- d->wmf_obj[index].level = d->level;
- d->wmf_obj[index].record = wmr_dup(record);
- }
- return(index);
+ int index = insertable_object(d);
+ if(index>=0){
+ d->wmf_obj[index].type = type;
+ d->wmf_obj[index].level = d->level;
+ d->wmf_obj[index].record = wmr_dup(record);
+ }
+ return(index);
}
/**
- \fn create a UTF-32LE buffer and fill it with UNICODE unknown character
- \param count number of copies of the Unicode unknown character to fill with
+ \fn create a UTF-32LE buffer and fill it with UNICODE unknown character
+ \param count number of copies of the Unicode unknown character to fill with
*/
uint32_t *Wmf::unknown_chars(size_t count){
- uint32_t *res = (uint32_t *) malloc(sizeof(uint32_t) * (count + 1));
- if(!res)throw "Inkscape fatal memory allocation error - cannot continue";
- for(uint32_t i=0; i<count; i++){ res[i] = 0xFFFD; }
- res[count]=0;
- return res;
+ uint32_t *res = (uint32_t *) malloc(sizeof(uint32_t) * (count + 1));
+ if(!res)throw "Inkscape fatal memory allocation error - cannot continue";
+ for(uint32_t i=0; i<count; i++){ res[i] = 0xFFFD; }
+ res[count]=0;
+ return res;
}
/**
- \brief store SVG for an image given the pixmap and various coordinate information
- \param d
- \param dib packed DIB in memory
- \param dx (double) destination x in inkscape pixels
- \param dy (double) destination y in inkscape pixels
- \param dw (double) destination width in inkscape pixels
- \param dh (double) destination height in inkscape pixels
- \param sx (int) source x in src image pixels
- \param sy (int) source y in src image pixels
- \param iUsage
+ \brief store SVG for an image given the pixmap and various coordinate information
+ \param d
+ \param dib packed DIB in memory
+ \param dx (double) destination x in inkscape pixels
+ \param dy (double) destination y in inkscape pixels
+ \param dw (double) destination width in inkscape pixels
+ \param dh (double) destination height in inkscape pixels
+ \param sx (int) source x in src image pixels
+ \param sy (int) source y in src image pixels
+ \param iUsage
*/
void Wmf::common_dib_to_image(PWMF_CALLBACK_DATA d, const char *dib,
- double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh, uint32_t iUsage){
-
- SVGOStringStream tmp_image;
- int dibparams;
-
- tmp_image << " y=\"" << dy << "\"\n x=\"" << dx <<"\"\n ";
-
- // The image ID is filled in much later when tmp_image is converted
-
- MEMPNG mempng; // PNG in memory comes back in this
- mempng.buffer = NULL;
-
- char *rgba_px = NULL; // RGBA pixels
- char *sub_px = NULL; // RGBA pixels, subarray
- const char *px = NULL; // DIB pixels
- const U_RGBQUAD *ct = NULL; // color table
- int32_t width, height, colortype, numCt, invert;
- if((iUsage != U_DIB_RGB_COLORS) ||
- !(dibparams = wget_DIB_params( // this returns pointers and values, but allocates no memory
- dib,
- &px,
- &ct,
- &numCt,
- &width,
- &height,
- &colortype,
- &invert
- ))
- ){
-
- if(sw == 0 || sh == 0){
- sw = width;
- sh = height;
- }
-
- if(!DIB_to_RGBA(
+ double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh, uint32_t iUsage){
+
+ SVGOStringStream tmp_image;
+ int dibparams;
+
+ tmp_image << " y=\"" << dy << "\"\n x=\"" << dx <<"\"\n ";
+
+ // The image ID is filled in much later when tmp_image is converted
+
+ MEMPNG mempng; // PNG in memory comes back in this
+ mempng.buffer = NULL;
+
+ char *rgba_px = NULL; // RGBA pixels
+ char *sub_px = NULL; // RGBA pixels, subarray
+ const char *px = NULL; // DIB pixels
+ const U_RGBQUAD *ct = NULL; // color table
+ int32_t width, height, colortype, numCt, invert;
+ if( (iUsage != U_DIB_RGB_COLORS) ||
+ !(dibparams = wget_DIB_params( // this returns pointers and values, but allocates no memory
+ dib,
+ &px,
+ &ct,
+ &numCt,
+ &width,
+ &height,
+ &colortype,
+ &invert
+ ))
+ ){
+ if(sw == 0 || sh == 0){
+ sw = width;
+ sh = height;
+ }
+
+ if(!DIB_to_RGBA(
px, // DIB pixel array
ct, // DIB color table
numCt, // DIB color table number of entries
@@ -1325,162 +1430,162 @@ void Wmf::common_dib_to_image(PWMF_CALLBACK_DATA d, const char *dib,
colortype, // DIB BitCount Enumeration
numCt, // Color table used if not 0
invert // If DIB rows are in opposite order from RGBA rows
- ) &&
- rgba_px)
- {
- sub_px = RGBA_to_RGBA(
- rgba_px, // full pixel array from DIB
- width, // Width of pixel array
- height, // Height of pixel array
- sx,sy, // starting point in pixel array
- &sw,&sh // columns/rows to extract from the pixel array (output array size)
- );
-
- if(!sub_px)sub_px=rgba_px;
- toPNG( // Get the image from the RGBA px into mempng
- &mempng,
- sw, sh, // size of the extracted pixel array
- sub_px);
- free(sub_px);
- }
- }
- gchar *base64String;
- if(dibparams == U_BI_JPEG){
- 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){
- 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){
- tmp_image << " xlink:href=\"data:image/png;base64,";
- gchar *base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
- free(mempng.buffer);
- tmp_image << base64String ;
- g_free(base64String);
- }
- else {
- tmp_image << " xlink:href=\"data:image/png;base64,";
- // insert a random 3x4 blotch otherwise
- tmp_image << "iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII=";
- }
-
- tmp_image << "\"\n height=\"" << dh << "\"\n width=\"" << dw << "\"\n";
-
- tmp_image << " transform=" << current_matrix(d, 0.0, 0.0, 0); // returns an identity matrix, no offsets.
- *(d->outsvg) += "\n\t <image\n";
- *(d->outsvg) += tmp_image.str().c_str();
-
- *(d->outsvg) += "/> \n";
- *(d->path) = "";
+ ) &&
+ rgba_px
+ ){
+ sub_px = RGBA_to_RGBA(
+ rgba_px, // full pixel array from DIB
+ width, // Width of pixel array
+ height, // Height of pixel array
+ sx,sy, // starting point in pixel array
+ &sw,&sh // columns/rows to extract from the pixel array (output array size)
+ );
+
+ if(!sub_px)sub_px=rgba_px;
+ toPNG( // Get the image from the RGBA px into mempng
+ &mempng,
+ sw, sh, // size of the extracted pixel array
+ sub_px
+ );
+ free(sub_px);
+ }
+ }
+ gchar *base64String;
+ if(dibparams == U_BI_JPEG){
+ 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){
+ 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){
+ tmp_image << " xlink:href=\"data:image/png;base64,";
+ gchar *base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
+ free(mempng.buffer);
+ tmp_image << base64String ;
+ g_free(base64String);
+ }
+ else {
+ tmp_image << " xlink:href=\"data:image/png;base64,";
+ // insert a random 3x4 blotch otherwise
+ tmp_image << "iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII=";
+ }
+
+ tmp_image << "\"\n height=\"" << dh << "\"\n width=\"" << dw << "\"\n";
+
+ tmp_image << " transform=" << current_matrix(d, 0.0, 0.0, 0); // returns an identity matrix, no offsets.
+ *(d->outsvg) += "\n\t <image\n";
+ *(d->outsvg) += tmp_image.str().c_str();
+
+ *(d->outsvg) += "/> \n";
+ *(d->path) = "";
}
/**
\brief store SVG for an image given the pixmap and various coordinate information
- \param d
- \param Bm16 core Bitmap16 header
- \param px pointer to Bitmap16 image data
- \param dx (double) destination x in inkscape pixels
- \param dy (double) destination y in inkscape pixels
- \param dw (double) destination width in inkscape pixels
- \param dh (double) destination height in inkscape pixels
- \param sx (int) source x in src image pixels
- \param sy (int) source y in src image pixels
- \param iUsage
+ \param d
+ \param Bm16 core Bitmap16 header
+ \param px pointer to Bitmap16 image data
+ \param dx (double) destination x in inkscape pixels
+ \param dy (double) destination y in inkscape pixels
+ \param dw (double) destination width in inkscape pixels
+ \param dh (double) destination height in inkscape pixels
+ \param sx (int) source x in src image pixels
+ \param sy (int) source y in src image pixels
+ \param iUsage
*/
void Wmf::common_bm16_to_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char *px,
- double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh){
-
- SVGOStringStream tmp_image;
-
- tmp_image << " y=\"" << dy << "\"\n x=\"" << dx <<"\"\n ";
-
- // The image ID is filled in much later when tmp_image is converted
-
- MEMPNG mempng; // PNG in memory comes back in this
- mempng.buffer = NULL;
-
- char *rgba_px = NULL; // RGBA pixels
- char *sub_px = NULL; // RGBA pixels, subarray
- const U_RGBQUAD *ct = NULL; // color table
- int32_t width, height, colortype, numCt, invert;
-
- numCt = 0;
- width = Bm16.Width; // bitmap width in pixels.
- height = Bm16.Height; // bitmap height in scan lines.
- colortype = Bm16.BitsPixel; // seems to be BitCount Enumeration
- invert = 0;
-
- if(sw == 0 || sh == 0){
- sw = width;
- sh = height;
- }
-
- if(colortype < 16)return; // these would need a colortable if they were a dib, no idea what bm16 is supposed to do instead.
- if(!DIB_to_RGBA( // This is not really a dib, but close enough...
- px, // DIB pixel array
- ct, // DIB color table (always NULL here)
- numCt, // DIB color table number of entries (always 0)
- &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free.
- width, // Width of pixel array
- height, // Height of pixel array
- colortype, // DIB BitCount Enumeration
- numCt, // Color table used if not 0
- invert // If DIB rows are in opposite order from RGBA rows
- ) &&
- rgba_px)
- {
- sub_px = RGBA_to_RGBA(
- rgba_px, // full pixel array from DIB
- width, // Width of pixel array
- height, // Height of pixel array
- sx,sy, // starting point in pixel array
- &sw,&sh // columns/rows to extract from the pixel array (output array size)
- );
-
- if(!sub_px)sub_px=rgba_px;
- toPNG( // Get the image from the RGBA px into mempng
- &mempng,
- sw, sh, // size of the extracted pixel array
- sub_px);
- free(sub_px);
- }
- if(mempng.buffer){
- tmp_image << " xlink:href=\"data:image/png;base64,";
- gchar *base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
- free(mempng.buffer);
- tmp_image << base64String;
- g_free(base64String);
- }
- else {
- tmp_image << " xlink:href=\"data:image/png;base64,";
- // insert a random 3x4 blotch otherwise
- tmp_image << "iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII=";
- }
-
- tmp_image << "\"\n height=\"" << dh << "\"\n width=\"" << dw << "\"\n";
-
- tmp_image << " transform=" << current_matrix(d, 0.0, 0.0, 0); // returns an identity matrix, no offsets.
- *(d->outsvg) += "\n\t <image\n";
- *(d->outsvg) += tmp_image.str().c_str();
-
- *(d->outsvg) += "/> \n";
- *(d->path) = "";
-}
+ double dx, double dy, double dw, double dh, int sx, int sy, int sw, int sh){
+
+ SVGOStringStream tmp_image;
+
+ tmp_image << " y=\"" << dy << "\"\n x=\"" << dx <<"\"\n ";
+
+ // The image ID is filled in much later when tmp_image is converted
+
+ MEMPNG mempng; // PNG in memory comes back in this
+ mempng.buffer = NULL;
+
+ char *rgba_px = NULL; // RGBA pixels
+ char *sub_px = NULL; // RGBA pixels, subarray
+ const U_RGBQUAD *ct = NULL; // color table
+ int32_t width, height, colortype, numCt, invert;
+ numCt = 0;
+ width = Bm16.Width; // bitmap width in pixels.
+ height = Bm16.Height; // bitmap height in scan lines.
+ colortype = Bm16.BitsPixel; // seems to be BitCount Enumeration
+ invert = 0;
+ if(sw == 0 || sh == 0){
+ sw = width;
+ sh = height;
+ }
+
+ if(colortype < 16)return; // these would need a colortable if they were a dib, no idea what bm16 is supposed to do instead.
+ if(!DIB_to_RGBA( // This is not really a dib, but close enough...
+ px, // DIB pixel array
+ ct, // DIB color table (always NULL here)
+ numCt, // DIB color table number of entries (always 0)
+ &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free.
+ width, // Width of pixel array
+ height, // Height of pixel array
+ colortype, // DIB BitCount Enumeration
+ numCt, // Color table used if not 0
+ invert // If DIB rows are in opposite order from RGBA rows
+ ) &&
+ rgba_px
+ ){
+ sub_px = RGBA_to_RGBA(
+ rgba_px, // full pixel array from DIB
+ width, // Width of pixel array
+ height, // Height of pixel array
+ sx,sy, // starting point in pixel array
+ &sw,&sh // columns/rows to extract from the pixel array (output array size)
+ );
+
+ if(!sub_px)sub_px=rgba_px;
+ toPNG( // Get the image from the RGBA px into mempng
+ &mempng,
+ sw, sh, // size of the extracted pixel array
+ sub_px
+ );
+ free(sub_px);
+ }
+ if(mempng.buffer){
+ tmp_image << " xlink:href=\"data:image/png;base64,";
+ gchar *base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size );
+ free(mempng.buffer);
+ tmp_image << base64String;
+ g_free(base64String);
+ }
+ else {
+ tmp_image << " xlink:href=\"data:image/png;base64,";
+ // insert a random 3x4 blotch otherwise
+ tmp_image << "iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII=";
+ }
+
+ tmp_image << "\"\n height=\"" << dh << "\"\n width=\"" << dw << "\"\n";
+
+ tmp_image << " transform=" << current_matrix(d, 0.0, 0.0, 0); // returns an identity matrix, no offsets.
+ *(d->outsvg) += "\n\t <image\n";
+ *(d->outsvg) += tmp_image.str().c_str();
+
+ *(d->outsvg) += "/> \n";
+ *(d->path) = "";
+}
/**
- \fn myMetaFileProc(char *contents, unsigned int length, PWMF_CALLBACK_DATA lpData)
- \returns 1 on success, 0 on error
- \param contents binary contents of an WMF file
- \param length length in bytes of contents
- \param d Inkscape data structures returned by this call
+ \fn myMetaFileProc(char *contents, unsigned int length, PWMF_CALLBACK_DATA lpData)
+ \returns 1 on success, 0 on error
+ \param contents binary contents of an WMF file
+ \param length length in bytes of contents
+ \param d Inkscape data structures returned by this call
*/
//THis was a callback, just build it into a normal function
int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK_DATA d)
@@ -1492,7 +1597,7 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK
uint8_t iType;
int nSize; // size of the current record, in bytes, or an error value if <=0
const char *blimit = contents + length; // 1 byte past the end of the last record
-
+
/* variables used to retrieve data from WMF records */
uint16_t utmp16;
U_POINT16 pt16; // any point
@@ -1515,6 +1620,9 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK
const int16_t *dx; // character spacing for one text mode, inkscape ignores this
double left, right, top, bottom; // values used, because a bounding rect can have values reversed L<->R, T<->B
+ uint16_t tbkMode = U_TRANSPARENT; // holds proposed change to bkMode, if text is involved saving these to the DC must wait until the text is written
+ U_COLORREF tbkColor = U_RGB(255, 255, 255); // holds proposed change to bkColor
+
/* initialize the tsp for text reassembly */
tsp.string = NULL;
tsp.ori = 0.0; /* degrees */
@@ -1531,115 +1639,116 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK
tsp.color.Reserved = 0; /* not used */
tsp.italics = 0;
tsp.weight = 80;
+ tsp.decoration = TXTDECOR_NONE;
tsp.condensed = 100;
tsp.co = 0;
tsp.fi_idx = -1; /* set to an invalid */
-
+
SVGOStringStream dbg_str;
- /* There is very little information in WMF headers, get what is there. In many cases pretty much everything will have to
- default. If there is no placeable header we know pretty much nothing about the size of the page, in which case
- assume that it is 1440 WMF pixels/inch and make the page A4 landscape. That is almost certainly the wrong page size
- but it has to be set to something, and nothing horrible happens if the drawing goes off the page. */
+ /* There is very little information in WMF headers, get what is there. In many cases pretty much everything will have to
+ default. If there is no placeable header we know pretty much nothing about the size of the page, in which case
+ assume that it is 1440 WMF pixels/inch and make the page A4 landscape. That is almost certainly the wrong page size
+ but it has to be set to something, and nothing horrible happens if the drawing goes off the page. */
{
- U_WMRPLACEABLE Placeable;
- U_WMRHEADER Header;
- off = 0;
- nSize = wmfheader_get(contents, blimit, &Placeable, &Header);
- if(!nSize)return(0);
- if(!Header.nObjects){ Header.nObjects = 256; }// there _may_ be WMF files with no objects, more likely it is corrupt. Try to use it anyway.
- d->n_obj = Header.nObjects;
- d->wmf_obj = new WMF_OBJECT[d->n_obj];
- d->low_water = 0; // completely empty at this point, so start searches at 0
-
- // Init the new wmf_obj list elements to null, provided the
- // dynamic allocation succeeded.
- if ( d->wmf_obj != NULL )
- {
- for( int i=0; i < d->n_obj; ++i )
- d->wmf_obj[i].record = NULL;
- } //if
-
- if(!Placeable.Inch){ Placeable.Inch= 1440; }
- if(!Placeable.Dst.right && !Placeable.Dst.left){ // no page size has been supplied
- // This is gross, scan forward looking for a SETWINDOWEXT record, use the first one found to
- // define the page size
- int hold_nSize = off = nSize;
- Placeable.Dst.left = 0;
- Placeable.Dst.top = 0;
- while(OK){
- nSize = U_WMRRECSAFE_get(contents + off, blimit);
- if(nSize){
- iType = *(uint8_t *)(contents + off + offsetof(U_METARECORD, iType ) );
- if(iType == U_WMR_SETWINDOWEXT){
- OK=0;
- nSize = U_WMRSETWINDOWEXT_get(contents + off, &Dst);
- Placeable.Dst.right = Dst.x;
- Placeable.Dst.bottom = Dst.y;
- }
- else if(iType == U_WMR_EOF){
- OK=0;
- // Really messed up WMF, have to set the page to something, make it A4 horizontal
- Placeable.Dst.right = round(((double) Placeable.Inch) * 297.0/25.4);
- Placeable.Dst.bottom = round(((double) Placeable.Inch) * 210.0/25.4);
- }
- else {
- off += nSize;
- }
- }
- }
- off=0;
- nSize = hold_nSize;
- OK=1;
- }
-
- // drawing size in WMF pixels
- d->PixelsInX = Placeable.Dst.right - Placeable.Dst.left + 1;
- d->PixelsInY = Placeable.Dst.bottom - Placeable.Dst.top + 1;
-
- /*
- Set values for Window and ViewPort extents to 0 - not defined yet.
- */
- d->dc[d->level].sizeView.x = d->dc[d->level].sizeWnd.x = 0;
- d->dc[d->level].sizeView.y = d->dc[d->level].sizeWnd.y = 0;
-
- // Upper left corner in device units, usually both 0, but not always
- d->ulCornerInX = Placeable.Dst.left;
- d->ulCornerInY = Placeable.Dst.top;
-
- d->E2IdirY = 1.0; // assume MM_ANISOTROPIC, if not, this will be changed later
- d->D2PscaleX = d->D2PscaleY = PX_PER_IN/(double) Placeable.Inch;
- trinfo_load_qe(d->tri, d->D2PscaleX); /* quantization error that will affect text positions */
-
- // drawing size in Inkscape pixels
- d->PixelsOutX = d->PixelsInX * d->D2PscaleX;
- d->PixelsOutY = d->PixelsInY * d->D2PscaleY;
-
- // Upper left corner in Inkscape units
- d->ulCornerOutX = d->ulCornerInX * d->D2PscaleX;
- d->ulCornerOutY = d->ulCornerInY * d->E2IdirY * d->D2PscaleY;
-
- d->dc[0].style.stroke_width.value = pix_to_abs_size( d, 1 ); // This could not be set until the size of the WMF was known
- dbg_str << "<!-- U_WMR_HEADER -->\n";
-
- *(d->outdef) += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
-
- SVGOStringStream tmp_outdef;
- tmp_outdef << "<svg\n";
- tmp_outdef << " xmlns:svg=\"http://www.w3.org/2000/svg\"\n";
- tmp_outdef << " xmlns=\"http://www.w3.org/2000/svg\"\n";
- tmp_outdef << " xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n";
- tmp_outdef << " xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\"\n"; // needed for sodipodi:role
- tmp_outdef << " version=\"1.0\"\n";
-
- tmp_outdef <<
- " width=\"" << d->PixelsOutX/ PX_PER_MM << "mm\"\n" <<
- " height=\"" << d->PixelsOutY/ PX_PER_MM << "mm\">\n";
- *(d->outdef) += tmp_outdef.str().c_str();
- *(d->outdef) += "<defs>"; // temporary end of header
-
- // d->defs holds any defines which are read in.
+ U_WMRPLACEABLE Placeable;
+ U_WMRHEADER Header;
+ off = 0;
+ nSize = wmfheader_get(contents, blimit, &Placeable, &Header);
+ if(!nSize)return(0);
+ if(!Header.nObjects){ Header.nObjects = 256; }// there _may_ be WMF files with no objects, more likely it is corrupt. Try to use it anyway.
+ d->n_obj = Header.nObjects;
+ d->wmf_obj = new WMF_OBJECT[d->n_obj];
+ d->low_water = 0; // completely empty at this point, so start searches at 0
+
+ // Init the new wmf_obj list elements to null, provided the
+ // dynamic allocation succeeded.
+ if ( d->wmf_obj != NULL )
+ {
+ for( int i=0; i < d->n_obj; ++i )
+ d->wmf_obj[i].record = NULL;
+ } //if
+
+ if(!Placeable.Inch){ Placeable.Inch= 1440; }
+ if(!Placeable.Dst.right && !Placeable.Dst.left){ // no page size has been supplied
+ // This is gross, scan forward looking for a SETWINDOWEXT record, use the first one found to
+ // define the page size
+ int hold_nSize = off = nSize;
+ Placeable.Dst.left = 0;
+ Placeable.Dst.top = 0;
+ while(OK){
+ nSize = U_WMRRECSAFE_get(contents + off, blimit);
+ if(nSize){
+ iType = *(uint8_t *)(contents + off + offsetof(U_METARECORD, iType ) );
+ if(iType == U_WMR_SETWINDOWEXT){
+ OK=0;
+ nSize = U_WMRSETWINDOWEXT_get(contents + off, &Dst);
+ Placeable.Dst.right = Dst.x;
+ Placeable.Dst.bottom = Dst.y;
+ }
+ else if(iType == U_WMR_EOF){
+ OK=0;
+ // Really messed up WMF, have to set the page to something, make it A4 horizontal
+ Placeable.Dst.right = round(((double) Placeable.Inch) * 297.0/25.4);
+ Placeable.Dst.bottom = round(((double) Placeable.Inch) * 210.0/25.4);
+ }
+ else {
+ off += nSize;
+ }
+ }
+ }
+ off=0;
+ nSize = hold_nSize;
+ OK=1;
+ }
+
+ // drawing size in WMF pixels
+ d->PixelsInX = Placeable.Dst.right - Placeable.Dst.left + 1;
+ d->PixelsInY = Placeable.Dst.bottom - Placeable.Dst.top + 1;
+
+ /*
+ Set values for Window and ViewPort extents to 0 - not defined yet.
+ */
+ d->dc[d->level].sizeView.x = d->dc[d->level].sizeWnd.x = 0;
+ d->dc[d->level].sizeView.y = d->dc[d->level].sizeWnd.y = 0;
+
+ // Upper left corner in device units, usually both 0, but not always
+ d->ulCornerInX = Placeable.Dst.left;
+ d->ulCornerInY = Placeable.Dst.top;
+
+ d->E2IdirY = 1.0; // assume MM_ANISOTROPIC, if not, this will be changed later
+ d->D2PscaleX = d->D2PscaleY = PX_PER_IN/(double) Placeable.Inch;
+ trinfo_load_qe(d->tri, d->D2PscaleX); /* quantization error that will affect text positions */
+
+ // drawing size in Inkscape pixels
+ d->PixelsOutX = d->PixelsInX * d->D2PscaleX;
+ d->PixelsOutY = d->PixelsInY * d->D2PscaleY;
+
+ // Upper left corner in Inkscape units
+ d->ulCornerOutX = d->ulCornerInX * d->D2PscaleX;
+ d->ulCornerOutY = d->ulCornerInY * d->E2IdirY * d->D2PscaleY;
+
+ d->dc[0].style.stroke_width.value = pix_to_abs_size( d, 1 ); // This could not be set until the size of the WMF was known
+ dbg_str << "<!-- U_WMR_HEADER -->\n";
+
+ *(d->outdef) += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
+
+ SVGOStringStream tmp_outdef;
+ tmp_outdef << "<svg\n";
+ tmp_outdef << " xmlns:svg=\"http://www.w3.org/2000/svg\"\n";
+ tmp_outdef << " xmlns=\"http://www.w3.org/2000/svg\"\n";
+ tmp_outdef << " xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n";
+ tmp_outdef << " xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\"\n"; // needed for sodipodi:role
+ tmp_outdef << " version=\"1.0\"\n";
+
+ tmp_outdef <<
+ " width=\"" << d->PixelsOutX/ PX_PER_MM << "mm\"\n" <<
+ " height=\"" << d->PixelsOutY/ PX_PER_MM << "mm\">\n";
+ *(d->outdef) += tmp_outdef.str().c_str();
+ *(d->outdef) += "<defs>"; // temporary end of header
+
+ // d->defs holds any defines which are read in.
}
@@ -1653,11 +1762,11 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK
SVGOStringStream tmp_path;
SVGOStringStream tmp_str;
-
- /* Check that the current record size is OK, abort if not.
- Pointer math might wrap, so check both sides of the range.
- Some of the records will reset this with the same value,others will not
- return a value at this time. */
+
+ /* Check that the current record size is OK, abort if not.
+ Pointer math might wrap, so check both sides of the range.
+ Some of the records will reset this with the same value,others will not
+ return a value at this time. */
nSize = U_WMRRECSAFE_get(contents, blimit);
if(!nSize)break;
@@ -1665,13 +1774,17 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK
// Uncomment the following to track down toxic records
// std::cout << "record type: " << (int) iType << " name " << U_wmr_names(iType) << " length: " << nSize << " offset: " << off <<std::endl;
-
- wmr_mask = U_wmr_properties(iType);
+
+ wmr_mask = U_wmr_properties(iType);
if(wmr_mask == U_WMR_INVALID){ throw "Inkscape fatal programming error at U_wmr_properties"; }
/* Uncomment the following to track down text problems */
//std::cout << "tri->dirty:"<< d->tri->dirty << " wmr_mask: " << std::hex << wmr_mask << std::dec << std::endl;
- if ( (wmr_mask != 0xFFFFFFFF) && (wmr_mask & U_DRAW_TEXT) && d->tri->dirty){ // next record is valid type and forces pending text to be drawn immediately
+
+ // incompatible change to text drawing detected (color or background change) forces out existing text
+ // OR
+ // next record is valid type and forces pending text to be drawn immediately
+ if ((d->dc[d->level].dirty & DIRTY_TEXT) || ((wmr_mask != 0xFFFFFFFF) && (wmr_mask & U_DRAW_TEXT) && d->tri->dirty)){
TR_layout_analyze(d->tri);
TR_layout_2_svg(d->tri);
SVGOStringStream ts;
@@ -1679,44 +1792,65 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK
*(d->outsvg) += ts.str().c_str();
d->tri = trinfo_clear(d->tri);
}
+ if(d->dc[d->level].dirty){ //Apply the delayed background changes, clear the flag
+ d->dc[d->level].bkMode = tbkMode;
+ memcpy(&(d->dc[d->level].bkColor),&tbkColor, sizeof(U_COLORREF));
+
+ if(d->dc[d->level].dirty & DIRTY_TEXT){
+ // U_COLORREF and TRCOLORREF are exactly the same in memory, but the compiler needs some convincing...
+ if(tbkMode == U_TRANSPARENT){ (void) trinfo_load_bk(d->tri, BKCLR_NONE, *(TRCOLORREF *) &tbkColor); }
+ else { (void) trinfo_load_bk(d->tri, BKCLR_LINE, *(TRCOLORREF *) &tbkColor); } // Opaque
+ }
+
+ /* It is possible to have a series of EMF records that would result in
+ the following creating hash patterns which are never used. For instance, if
+ there were a series of records that changed the background color but did nothing
+ else.
+ */
+ if((d->dc[d->level].fill_mode == DRAW_PATTERN) && (d->dc[d->level].dirty & DIRTY_FILL)){
+ select_brush(d, d->dc[d->level].fill_recidx);
+ }
+
+ d->dc[d->level].dirty = 0;
+ }
//std::cout << "BEFORE DRAW logic d->mask: " << std::hex << d->mask << " wmr_mask: " << wmr_mask << std::dec << std::endl;
/*
std::cout << "BEFORE DRAW"
- << " test0 " << ( d->mask & U_DRAW_VISIBLE)
- << " test1 " << ( d->mask & U_DRAW_FORCE)
- << " test2 " << (wmr_mask & U_DRAW_ALTERS)
+ << " test0 " << ( d->mask & U_DRAW_VISIBLE)
+ << " test1 " << ( d->mask & U_DRAW_FORCE)
+ << " test2 " << (wmr_mask & U_DRAW_ALTERS)
<< " test3 " << (wmr_mask & U_DRAW_VISIBLE)
<< " test4 " << !(d->mask & U_DRAW_ONLYTO)
<< " test5 " << ((d->mask & U_DRAW_ONLYTO) && !(wmr_mask & U_DRAW_ONLYTO) )
<< std::endl;
*/
- if ( (wmr_mask != 0xFFFFFFFF) && // next record is valid type
- (d->mask & U_DRAW_VISIBLE) && // This record is drawable
- ( (d->mask & U_DRAW_FORCE) || // This draw is forced by STROKE/FILL/STROKEANDFILL PATH
- (wmr_mask & U_DRAW_ALTERS) || // Next record would alter the drawing environment in some way
- ( (wmr_mask & U_DRAW_VISIBLE) // Next record is visible...
- &&
- (
- ( !(d->mask & U_DRAW_ONLYTO) ) // Non *TO records cannot be followed by any Visible
- ||
- ((d->mask & U_DRAW_ONLYTO) && !(wmr_mask & U_DRAW_ONLYTO) ) // *TO records can only be followed by other *TO records
- )
+ if(
+ (wmr_mask != 0xFFFFFFFF) && // next record is valid type
+ (d->mask & U_DRAW_VISIBLE) && // This record is drawable
+ (
+ (d->mask & U_DRAW_FORCE) || // This draw is forced by STROKE/FILL/STROKEANDFILL PATH
+ (wmr_mask & U_DRAW_ALTERS) || // Next record would alter the drawing environment in some way
+ ( (wmr_mask & U_DRAW_VISIBLE) && // Next record is visible...
+ (
+ ( !(d->mask & U_DRAW_ONLYTO) ) || // Non *TO records cannot be followed by any Visible
+ ((d->mask & U_DRAW_ONLYTO) && !(wmr_mask & U_DRAW_ONLYTO) )// *TO records can only be followed by other *TO records
+ )
)
- )
- ){
+ )
+ ){
// std::cout << "PATH DRAW at TOP <<+++++++++++++++++++++++++++++++++++++" << std::endl;
- *(d->outsvg) += " <path "; // this is the ONLY place <path should be used!!!!
- output_style(d);
- *(d->outsvg) += "\n\t";
- *(d->outsvg) += "\n\td=\""; // this is the ONLY place d=" should be used!!!!
- *(d->outsvg) += *(d->path);
- *(d->outsvg) += " \" /> \n";
- *(d->path) = ""; //reset the path
- // reset the flags
- d->mask = 0;
- d->drawtype = 0;
+ *(d->outsvg) += " <path "; // this is the ONLY place <path should be used!!!!
+ output_style(d);
+ *(d->outsvg) += "\n\t";
+ *(d->outsvg) += "\n\td=\""; // this is the ONLY place d=" should be used!!!!
+ *(d->outsvg) += *(d->path);
+ *(d->outsvg) += " \" /> \n";
+ *(d->path) = ""; //reset the path
+ // reset the flags
+ d->mask = 0;
+ d->drawtype = 0;
}
// std::cout << "AFTER DRAW logic d->mask: " << std::hex << d->mask << " wmr_mask: " << wmr_mask << std::dec << std::endl;
switch (iType)
@@ -1725,40 +1859,56 @@ std::cout << "BEFORE DRAW"
{
dbg_str << "<!-- U_WMR_EOF -->\n";
- *(d->outsvg) = *(d->outdef) + *(d->defs) + "\n</defs>\n\n" + *(d->outsvg) + "</svg>\n";
+ *(d->outsvg) = *(d->outdef) + *(d->defs) + "\n</defs>\n\n" + *(d->outsvg) + "</svg>\n";
OK=0;
break;
}
case U_WMR_SETBKCOLOR:
{
dbg_str << "<!-- U_WMR_SETBKCOLOR -->\n";
- nSize = U_WMRSETBKCOLOR_get(contents, &(d->dc[d->level].bkColor));
+ nSize = U_WMRSETBKCOLOR_get(contents, &tbkColor);
+ if(memcmp(&tbkColor, &(d->dc[d->level].bkColor), sizeof(U_COLORREF))){
+ d->dc[d->level].dirty |= DIRTY_TEXT;
+ if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; }
+ tbkMode = d->dc[d->level].bkMode;
+ }
+ break;
+ }
+ case U_WMR_SETBKMODE:{
+ dbg_str << "<!-- U_WMR_SETBKMODE -->\n";
+ nSize = U_WMRSETBKMODE_get(contents, &tbkMode);
+ if(tbkMode != d->dc[d->level].bkMode){
+ d->dc[d->level].dirty |= DIRTY_TEXT;
+ if(tbkMode != d->dc[d->level].bkMode){
+ if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; }
+ }
+ memcpy(&tbkColor,&(d->dc[d->level].bkColor),sizeof(U_COLORREF));
+ }
break;
}
- case U_WMR_SETBKMODE: dbg_str << "<!-- U_WMR_SETBKMODE -->\n"; break;
case U_WMR_SETMAPMODE:
{
dbg_str << "<!-- U_WMR_SETMAPMODE -->\n";
nSize = U_WMRSETMAPMODE_get(contents, &utmp16);
switch (utmp16){
- case U_MM_TEXT:
- default:
- // Use all values from the header.
- break;
- /* For all of the following the indicated scale this will be encoded in WindowExtEx/ViewportExtex
- and show up in ScaleIn[XY]
- */
- case U_MM_LOMETRIC: // 1 LU = 0.1 mm,
- case U_MM_HIMETRIC: // 1 LU = 0.01 mm
- case U_MM_LOENGLISH: // 1 LU = 0.1 in
- case U_MM_HIENGLISH: // 1 LU = 0.01 in
- case U_MM_TWIPS: // 1 LU = 1/1440 in
- d->E2IdirY = -1.0;
- // Use d->D2Pscale[XY] values from the header.
- break;
- case U_MM_ISOTROPIC: // ScaleIn[XY] should be set elsewhere by SETVIEWPORTEXTEX and SETWINDOWEXTEX
- case U_MM_ANISOTROPIC:
- break;
+ case U_MM_TEXT:
+ default:
+ // Use all values from the header.
+ break;
+ /* For all of the following the indicated scale this will be encoded in WindowExtEx/ViewportExtex
+ and show up in ScaleIn[XY]
+ */
+ case U_MM_LOMETRIC: // 1 LU = 0.1 mm,
+ case U_MM_HIMETRIC: // 1 LU = 0.01 mm
+ case U_MM_LOENGLISH: // 1 LU = 0.1 in
+ case U_MM_HIENGLISH: // 1 LU = 0.01 in
+ case U_MM_TWIPS: // 1 LU = 1/1440 in
+ d->E2IdirY = -1.0;
+ // Use d->D2Pscale[XY] values from the header.
+ break;
+ case U_MM_ISOTROPIC: // ScaleIn[XY] should be set elsewhere by SETVIEWPORTEXTEX and SETWINDOWEXTEX
+ case U_MM_ANISOTROPIC:
+ break;
}
break;
}
@@ -1789,6 +1939,10 @@ std::cout << "BEFORE DRAW"
{
dbg_str << "<!-- U_WMR_SETTEXTCOLOR -->\n";
nSize = U_WMRSETTEXTCOLOR_get(contents, &(d->dc[d->level].textColor));
+ if(tbkMode != d->dc[d->level].bkMode){
+ if(d->dc[d->level].fill_mode == DRAW_PATTERN){ d->dc[d->level].dirty |= DIRTY_FILL; }
+ }
+ // not text_dirty, because multicolored complex text is supported in libTERE
break;
}
case U_WMR_SETTEXTJUSTIFICATION: dbg_str << "<!-- U_WMR_SETTEXTJUSTIFICATION -->\n"; break;
@@ -1821,8 +1975,8 @@ std::cout << "BEFORE DRAW"
d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.x / (double) d->dc[d->level].sizeWnd.x;
d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.y / (double) d->dc[d->level].sizeWnd.y;
if(d->dc[d->level].ScaleInY < 0){
- d->dc[d->level].ScaleInY *= -1.0;
- d->E2IdirY = -1.0;
+ d->dc[d->level].ScaleInY *= -1.0;
+ d->E2IdirY = -1.0;
}
}
else {
@@ -1854,14 +2008,14 @@ std::cout << "BEFORE DRAW"
if (!d->dc[d->level].sizeWnd.x || !d->dc[d->level].sizeWnd.y) {
d->dc[d->level].sizeWnd = d->dc[d->level].sizeView;
}
-
+
/* scales logical to WMF pixels, transfer a negative sign on Y, if any */
if (d->dc[d->level].sizeWnd.x && d->dc[d->level].sizeWnd.y) {
d->dc[d->level].ScaleInX = (double) d->dc[d->level].sizeView.x / (double) d->dc[d->level].sizeWnd.x;
d->dc[d->level].ScaleInY = (double) d->dc[d->level].sizeView.y / (double) d->dc[d->level].sizeWnd.y;
if(d->dc[d->level].ScaleInY < 0){
- d->dc[d->level].ScaleInY *= -1.0;
- d->E2IdirY = -1.0;
+ d->dc[d->level].ScaleInY *= -1.0;
+ d->E2IdirY = -1.0;
}
}
else {
@@ -1939,19 +2093,19 @@ std::cout << "BEFORE DRAW"
int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1);
int stat = wmr_arc_points(rc, ArcStart, ArcEnd,&f1, f2, &center, &start, &end, &size);
if(!stat){
- tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y);
- tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ;
- tmp_path << " ";
- tmp_path << 180.0 * current_rotation(d)/M_PI;
- tmp_path << " ";
- tmp_path << " " << f1 << "," << f2 << " ";
- tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
- d->mask |= wmr_mask;
+ tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y);
+ tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ;
+ tmp_path << " ";
+ tmp_path << 180.0 * current_rotation(d)/M_PI;
+ tmp_path << " ";
+ tmp_path << " " << f1 << "," << f2 << " ";
+ tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
+ d->mask |= wmr_mask;
}
else {
- dbg_str << "<!-- ARC record is invalid -->\n";
+ dbg_str << "<!-- ARC record is invalid -->\n";
}
- break;
+ break;
}
case U_WMR_ELLIPSE:
{
@@ -1972,7 +2126,7 @@ std::cout << "BEFORE DRAW"
d->mask |= wmr_mask;
- *(d->outsvg) += " <ellipse ";
+ *(d->outsvg) += " <ellipse ";
output_style(d);
*(d->outsvg) += "\n\t";
*(d->outsvg) += tmp_ellipse.str().c_str();
@@ -1990,19 +2144,19 @@ std::cout << "BEFORE DRAW"
int f1;
int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1);
if(!wmr_arc_points(rc, ArcStart, ArcEnd, &f1, f2, &center, &start, &end, &size)){
- tmp_path << "\n\tM " << pix_to_xy(d, center.x, center.y);
- tmp_path << "\n\tL " << pix_to_xy(d, start.x, start.y);
- tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ;
- tmp_path << " ";
- tmp_path << 180.0 * current_rotation(d)/M_PI;
- tmp_path << " ";
- tmp_path << " " << f1 << "," << f2 << " ";
- tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
- tmp_path << " z ";
- d->mask |= wmr_mask;
+ tmp_path << "\n\tM " << pix_to_xy(d, center.x, center.y);
+ tmp_path << "\n\tL " << pix_to_xy(d, start.x, start.y);
+ tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ;
+ tmp_path << " ";
+ tmp_path << 180.0 * current_rotation(d)/M_PI;
+ tmp_path << " ";
+ tmp_path << " " << f1 << "," << f2 << " ";
+ tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
+ tmp_path << " z ";
+ d->mask |= wmr_mask;
}
else {
- dbg_str << "<!-- PIE record is invalid -->\n";
+ dbg_str << "<!-- PIE record is invalid -->\n";
}
break;
}
@@ -2036,41 +2190,41 @@ std::cout << "BEFORE DRAW"
double f1 = 1.0 - f;
double cnx = Width/2;
double cny = Height/2;
-
-
+
+
SVGOStringStream tmp_rectangle;
tmp_rectangle << "\n"
- << " M "
+ << " M "
<< pix_to_xy(d, left , top + cny )
<< "\n";
- tmp_rectangle << " C "
+ tmp_rectangle << " C "
<< pix_to_xy(d, left , top + cny*f1 )
- << " "
+ << " "
<< pix_to_xy(d, left + cnx*f1 , top )
- << " "
+ << " "
<< pix_to_xy(d, left + cnx , top )
<< "\n";
- tmp_rectangle << " L "
+ tmp_rectangle << " L "
<< pix_to_xy(d, right - cnx , top )
<< "\n";
- tmp_rectangle << " C "
+ tmp_rectangle << " C "
<< pix_to_xy(d, right - cnx*f1 , top )
- << " "
+ << " "
<< pix_to_xy(d, right , top + cny*f1 )
- << " "
+ << " "
<< pix_to_xy(d, right , top + cny )
<< "\n";
tmp_rectangle << " L "
<< pix_to_xy(d, right , bottom - cny )
<< "\n";
- tmp_rectangle << " C "
+ tmp_rectangle << " C "
<< pix_to_xy(d, right , bottom - cny*f1 )
<< " "
<< pix_to_xy(d, right - cnx*f1 , bottom )
<< " "
<< pix_to_xy(d, right - cnx , bottom )
<< "\n";
- tmp_rectangle << " L "
+ tmp_rectangle << " L "
<< pix_to_xy(d, left + cnx , bottom )
<< "\n";
tmp_rectangle << " C "
@@ -2151,7 +2305,7 @@ std::cout << "BEFORE DRAW"
//source position within the bitmap, in pixels
int sx = Src.x;
int sy = Src.y;
- int sw = 0; // extract all of the image
+ int sw = 0; // extract all of the image
int sh = 0;
if(sx<0)sx=0;
if(sy<0)sy=0;
@@ -2188,7 +2342,7 @@ std::cout << "BEFORE DRAW"
//source position within the bitmap, in pixels
int sx = Src.x;
int sy = Src.y;
- int sw = cSrc.x; // extract the specified amount of the image
+ int sw = cSrc.x; // extract the specified amount of the image
int sh = cSrc.y;
if(sx<0)sx=0;
if(sy<0)sy=0;
@@ -2210,8 +2364,8 @@ std::cout << "BEFORE DRAW"
tmp_str << "\n\tM " << pix_to_xy( d, pt16.x, pt16.y) << " ";
for (i=1; i<cPts; i++) {
- memcpy(&pt16,points,U_SIZE_POINT16); points+=U_SIZE_POINT16;
- tmp_str << "\n\tL " << pix_to_xy( d, pt16.x, pt16.y) << " ";
+ memcpy(&pt16,points,U_SIZE_POINT16); points+=U_SIZE_POINT16;
+ tmp_str << "\n\tL " << pix_to_xy( d, pt16.x, pt16.y) << " ";
}
tmp_path << tmp_str.str().c_str();
@@ -2228,19 +2382,19 @@ std::cout << "BEFORE DRAW"
uint32_t utmp4;
memcpy(&utmp4, text ,4);
if(Escape == U_MFE_SETLINECAP){
- switch (utmp4 & U_PS_ENDCAP_MASK) {
- case U_PS_ENDCAP_ROUND: { d->dc[d->level].style.stroke_linecap.computed = 1; break; }
- case U_PS_ENDCAP_SQUARE: { d->dc[d->level].style.stroke_linecap.computed = 2; break; }
- case U_PS_ENDCAP_FLAT:
- default: { d->dc[d->level].style.stroke_linecap.computed = 0; break; }
- }
+ switch (utmp4 & U_PS_ENDCAP_MASK) {
+ case U_PS_ENDCAP_ROUND: { d->dc[d->level].style.stroke_linecap.computed = 1; break; }
+ case U_PS_ENDCAP_SQUARE: { d->dc[d->level].style.stroke_linecap.computed = 2; break; }
+ case U_PS_ENDCAP_FLAT:
+ default: { d->dc[d->level].style.stroke_linecap.computed = 0; break; }
+ }
}
else if(Escape == U_MFE_SETLINEJOIN){
- switch (utmp4 & U_PS_JOIN_MASK) {
- case U_PS_JOIN_BEVEL: { d->dc[d->level].style.stroke_linejoin.computed = 2; break; }
- case U_PS_JOIN_MITER: { d->dc[d->level].style.stroke_linejoin.computed = 0; break; }
- case U_PS_JOIN_ROUND:
- default: { d->dc[d->level].style.stroke_linejoin.computed = 1; break; }
+ switch (utmp4 & U_PS_JOIN_MASK) {
+ case U_PS_JOIN_BEVEL: { d->dc[d->level].style.stroke_linejoin.computed = 2; break; }
+ case U_PS_JOIN_MITER: { d->dc[d->level].style.stroke_linejoin.computed = 0; break; }
+ case U_PS_JOIN_ROUND:
+ default: { d->dc[d->level].style.stroke_linejoin.computed = 1; break; }
}
}
else if(Escape == U_MFE_SETMITERLIMIT){
@@ -2256,7 +2410,7 @@ std::cout << "BEFORE DRAW"
case U_WMR_RESTOREDC:
{
dbg_str << "<!-- U_WMR_RESTOREDC -->\n";
-
+
int16_t DC;
nSize = U_WMRRESTOREDC_get(contents, &DC);
int old_level = d->level;
@@ -2273,8 +2427,8 @@ std::cout << "BEFORE DRAW"
delete[] d->dc[old_level].style.stroke_dash.dash;
}
if(d->dc[old_level].font_name){
- free(d->dc[old_level].font_name); // else memory leak
- d->dc[old_level].font_name = NULL;
+ free(d->dc[old_level].font_name); // else memory leak
+ d->dc[old_level].font_name = NULL;
}
old_level--;
}
@@ -2340,18 +2494,18 @@ std::cout << "BEFORE DRAW"
int f1;
int f2 = (d->arcdir == U_AD_COUNTERCLOCKWISE ? 0 : 1);
if(!wmr_arc_points(rc, ArcStart, ArcEnd, &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 << " ";
- tmp_path << 180.0 * current_rotation(d)/M_PI;
- tmp_path << " ";
- tmp_path << " " << f1 << "," << f2 << " ";
- tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
- tmp_path << " z ";
- d->mask |= wmr_mask;
+ tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y);
+ tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ;
+ tmp_path << " ";
+ tmp_path << 180.0 * current_rotation(d)/M_PI;
+ tmp_path << " ";
+ tmp_path << " " << f1 << "," << f2 << " ";
+ tmp_path << pix_to_xy(d, end.x, end.y) << " \n";
+ tmp_path << " z ";
+ d->mask |= wmr_mask;
}
else {
- dbg_str << "<!-- CHORD record is invalid -->\n";
+ dbg_str << "<!-- CHORD record is invalid -->\n";
}
break;
}
@@ -2360,12 +2514,12 @@ std::cout << "BEFORE DRAW"
case U_WMR_EXTTEXTOUT:
{
if(iType == U_WMR_TEXTOUT){
- dbg_str << "<!-- U_WMR_TEXTOUT -->\n";
- nSize = U_WMRTEXTOUT_get(contents, &Dst, &tlen, &text);
+ dbg_str << "<!-- U_WMR_TEXTOUT -->\n";
+ nSize = U_WMRTEXTOUT_get(contents, &Dst, &tlen, &text);
}
else {
- dbg_str << "<!-- U_WMR_EXTTEXTOUT -->\n";
- nSize = U_WMREXTTEXTOUT_get(contents, &Dst, &tlen, &Opts, &text, &dx, &rc );
+ dbg_str << "<!-- U_WMR_EXTTEXTOUT -->\n";
+ nSize = U_WMREXTTEXTOUT_get(contents, &Dst, &tlen, &Opts, &text, &dx, &rc );
}
double x1,y1;
@@ -2373,7 +2527,7 @@ std::cout << "BEFORE DRAW"
x1 = Dst.x;
y1 = Dst.y;
cChars = tlen;
-
+
if (d->dc[d->level].textAlign & U_TA_UPDATECP) {
x1 = d->dc[d->level].cur.x;
y1 = d->dc[d->level].cur.y;
@@ -2392,8 +2546,8 @@ std::cout << "BEFORE DRAW"
msdepua(dup_wt); //convert everything in Microsoft's private use area. For Symbol, Wingdings, Dingbats
if(NonToUnicode(dup_wt, d->dc[d->level].font_name)){
- free(d->dc[d->level].font_name);
- d->dc[d->level].font_name = strdup("Times New Roman");
+ free(d->dc[d->level].font_name);
+ d->dc[d->level].font_name = strdup("Times New Roman");
}
char *ansi_text;
@@ -2401,8 +2555,8 @@ std::cout << "BEFORE DRAW"
free(dup_wt);
// Empty text or starts with an invalid escape/control sequence, which is bogus text. Throw it out before g_markup_escape_text can make things worse
if(*((uint8_t *)ansi_text) <= 0x1F){
- free(ansi_text);
- ansi_text=NULL;
+ free(ansi_text);
+ ansi_text=NULL;
}
if (ansi_text) {
@@ -2427,27 +2581,32 @@ std::cout << "BEFORE DRAW"
tsp.italics = FC_SLANT_ROMAN; break;
}
switch(d->dc[d->level].style.font_weight.value){
- case SP_CSS_FONT_WEIGHT_100: tsp.weight = FC_WEIGHT_THIN ; break;
- case SP_CSS_FONT_WEIGHT_200: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break;
- case SP_CSS_FONT_WEIGHT_300: tsp.weight = FC_WEIGHT_LIGHT ; break;
- case SP_CSS_FONT_WEIGHT_400: tsp.weight = FC_WEIGHT_NORMAL ; break;
- case SP_CSS_FONT_WEIGHT_500: tsp.weight = FC_WEIGHT_MEDIUM ; break;
- case SP_CSS_FONT_WEIGHT_600: tsp.weight = FC_WEIGHT_SEMIBOLD ; break;
- case SP_CSS_FONT_WEIGHT_700: tsp.weight = FC_WEIGHT_BOLD ; break;
- case SP_CSS_FONT_WEIGHT_800: tsp.weight = FC_WEIGHT_EXTRABOLD ; break;
- case SP_CSS_FONT_WEIGHT_900: tsp.weight = FC_WEIGHT_HEAVY ; break;
- case SP_CSS_FONT_WEIGHT_NORMAL: tsp.weight = FC_WEIGHT_NORMAL ; break;
- case SP_CSS_FONT_WEIGHT_BOLD: tsp.weight = FC_WEIGHT_BOLD ; break;
- case SP_CSS_FONT_WEIGHT_LIGHTER: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break;
- case SP_CSS_FONT_WEIGHT_BOLDER: tsp.weight = FC_WEIGHT_EXTRABOLD ; break;
- default: tsp.weight = FC_WEIGHT_NORMAL ; break;
+ case SP_CSS_FONT_WEIGHT_100: tsp.weight = FC_WEIGHT_THIN ; break;
+ case SP_CSS_FONT_WEIGHT_200: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break;
+ case SP_CSS_FONT_WEIGHT_300: tsp.weight = FC_WEIGHT_LIGHT ; break;
+ case SP_CSS_FONT_WEIGHT_400: tsp.weight = FC_WEIGHT_NORMAL ; break;
+ case SP_CSS_FONT_WEIGHT_500: tsp.weight = FC_WEIGHT_MEDIUM ; break;
+ case SP_CSS_FONT_WEIGHT_600: tsp.weight = FC_WEIGHT_SEMIBOLD ; break;
+ case SP_CSS_FONT_WEIGHT_700: tsp.weight = FC_WEIGHT_BOLD ; break;
+ case SP_CSS_FONT_WEIGHT_800: tsp.weight = FC_WEIGHT_EXTRABOLD ; break;
+ case SP_CSS_FONT_WEIGHT_900: tsp.weight = FC_WEIGHT_HEAVY ; break;
+ case SP_CSS_FONT_WEIGHT_NORMAL: tsp.weight = FC_WEIGHT_NORMAL ; break;
+ case SP_CSS_FONT_WEIGHT_BOLD: tsp.weight = FC_WEIGHT_BOLD ; break;
+ case SP_CSS_FONT_WEIGHT_LIGHTER: tsp.weight = FC_WEIGHT_EXTRALIGHT ; break;
+ case SP_CSS_FONT_WEIGHT_BOLDER: tsp.weight = FC_WEIGHT_EXTRABOLD ; break;
+ default: tsp.weight = FC_WEIGHT_NORMAL ; break;
}
+ // Inkscape cannot display underline or strike-through at present, but enter it into the SVG in any case.
+ if( d->dc[d->level].style.text_decoration.underline){ tsp.decoration = TXTDECOR_UNDER; }
+ else if (d->dc[d->level].style.text_decoration.line_through){ tsp.decoration = TXTDECOR_STRIKE1; }
+ else { tsp.decoration = TXTDECOR_NONE; }
+
// WMF textalignment is a bit strange: 0x6 is center, 0x2 is right, 0x0 is left, the value 0x4 is also drawn left
- tsp.taln = ((d->dc[d->level].textAlign & U_TA_CENTER) == U_TA_CENTER) ? ALICENTER :
+ tsp.taln = ((d->dc[d->level].textAlign & U_TA_CENTER) == U_TA_CENTER) ? ALICENTER :
(((d->dc[d->level].textAlign & U_TA_CENTER) == U_TA_LEFT) ? ALILEFT :
ALIRIGHT);
- tsp.taln |= ((d->dc[d->level].textAlign & U_TA_BASEBIT) ? ALIBASE :
+ tsp.taln |= ((d->dc[d->level].textAlign & U_TA_BASEBIT) ? ALIBASE :
((d->dc[d->level].textAlign & U_TA_BOTTOM) ? ALIBOT :
ALITOP));
tsp.ldir = (d->dc[d->level].textAlign & U_TA_RTLREADING ? LDIR_RL : LDIR_LR); // language direction
@@ -2462,20 +2621,22 @@ std::cout << "BEFORE DRAW"
if(0<= TR_findcasesub(d->dc[d->level].font_name, (char *) "Narrow")){ tsp.co=1; }
else { tsp.co=0; }
- int status = trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ori is actually escapement
- if(status==-1){ // change of escapement, emit what we have and reset
- TR_layout_analyze(d->tri);
- TR_layout_2_svg(d->tri);
- ts << d->tri->out;
- *(d->outsvg) += ts.str().c_str();
- d->tri = trinfo_clear(d->tri);
- (void) trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ignore return status, it must work
+ int status;
+
+ status = trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ori is actually escapement
+ if(status==-1){ // change of escapement, emit what we have and reset
+ TR_layout_analyze(d->tri);
+ TR_layout_2_svg(d->tri);
+ ts << d->tri->out;
+ *(d->outsvg) += ts.str().c_str();
+ d->tri = trinfo_clear(d->tri);
+ (void) trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ignore return status, it must work
}
-
+
g_free(escaped_text);
free(ansi_text);
}
-
+
break;
}
case U_WMR_SETDIBTODEV: dbg_str << "<!-- U_WMR_EXTTEXTOUT -->\n"; break;
@@ -2502,7 +2663,7 @@ std::cout << "BEFORE DRAW"
for (n=0; n < nPolys && i<cpts; n++) {
SVGOStringStream poly_path;
-
+
memcpy(&apt, Points + i, U_SIZE_POINT16); // points may not be aligned, copy them this way
poly_path << "\n\tM " << pix_to_xy( d, apt.x, apt.y) << " ";
@@ -2539,8 +2700,8 @@ std::cout << "BEFORE DRAW"
dbg_str << "<!-- U_WMR_DIBBITBLT -->\n";
nSize = U_WMRDIBBITBLT_get(contents, &Dst, &cwh, &Src, &dwRop3, &dib);
- // Treat all nonImage bitblts as a rectangular write. Definitely not correct, but at
- // least it leaves objects where the operations should have been.
+ // Treat all nonImage bitblts as a rectangular write. Definitely not correct, but at
+ // least it leaves objects where the operations should have been.
if (!dib) {
// should be an application of a DIBPATTERNBRUSHPT, use a solid color instead
@@ -2569,7 +2730,7 @@ std::cout << "BEFORE DRAW"
//source position within the bitmap, in pixels
int sx = Src.x;
int sy = Src.y;
- int sw = 0; // extract all of the image
+ int sw = 0; // extract all of the image
int sh = 0;
if(sx<0)sx=0;
if(sy<0)sy=0;
@@ -2591,7 +2752,7 @@ std::cout << "BEFORE DRAW"
//source position within the bitmap, in pixels
int sx = Src.x;
int sy = Src.y;
- int sw = cSrc.x; // extract the specified amount of the image
+ int sw = cSrc.x; // extract the specified amount of the image
int sh = cSrc.y;
// usageSrc not defined, implicitly it must be U_DIB_RGB_COLORS
common_dib_to_image(d,dib,dx,dy,dw,dh,sx,sy,sw,sh, U_DIB_RGB_COLORS);
@@ -2614,7 +2775,7 @@ std::cout << "BEFORE DRAW"
double dh = pix_to_abs_size( d, cDst.y);
int sx = Src.x; //source position within the bitmap, in pixels
int sy = Src.y;
- int sw = cSrc.x; // extract the specified amount of the image
+ int sw = cSrc.x; // extract the specified amount of the image
int sh = cSrc.y;
uint32_t iUsageSrc;
iUsageSrc = cUsage;
@@ -2627,8 +2788,8 @@ std::cout << "BEFORE DRAW"
case U_WMR_46:
case U_WMR_47:
{
- dbg_str << "<!-- U_WMR_44..47 -->\n";
- break;
+ dbg_str << "<!-- U_WMR_44..47 -->\n";
+ break;
}
case U_WMR_EXTFLOODFILL: dbg_str << "<!-- U_WMR_EXTFLOODFILL -->\n"; break;
case U_WMR_49:
@@ -2799,15 +2960,15 @@ std::cout << "BEFORE DRAW"
case U_WMR_EE:
case U_WMR_EF:
{
- dbg_str << "<!-- U_WMR_EXTFLOODFILL..EF -->\n";
- break;
+ dbg_str << "<!-- U_WMR_EXTFLOODFILL..EF -->\n";
+ break;
}
case U_WMR_DELETEOBJECT:
{
dbg_str << "<!-- U_WMR_DELETEOBJECT -->\n";
nSize = U_WMRDELETEOBJECT_get(contents, &utmp16);
delete_object(d, utmp16);
- break;
+ break;
}
case U_WMR_F1:
case U_WMR_F2:
@@ -2816,8 +2977,8 @@ std::cout << "BEFORE DRAW"
case U_WMR_F5:
case U_WMR_F6:
{
- dbg_str << "<!-- F1..F6 -->\n";
- break;
+ dbg_str << "<!-- F1..F6 -->\n";
+ break;
}
case U_WMR_CREATEPALETTE:
{
@@ -2879,17 +3040,17 @@ std::cout << "BEFORE DRAW"
} //end of while
// When testing, uncomment the following to show the final SVG derived from the WMF
-// std::cout << *(d->outsvg) << std::endl;
+// std::cout << *(d->outsvg) << std::endl;
(void) U_wmr_properties(U_WMR_INVALID); // force the release of the lookup table memory, returned value is irrelevant
return 1;
}
void Wmf::free_wmf_strings(WMF_STRINGS name){
- if(name.count){
- for(int i=0; i< name.count; i++){ free(name.strings[i]); }
- free(name.strings);
- }
+ if(name.count){
+ for(int i=0; i< name.count; i++){ free(name.strings[i]); }
+ free(name.strings);
+ }
}
SPDocument *
@@ -2899,9 +3060,9 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
WMF_CALLBACK_DATA d;
memset(&d, 0, sizeof(WMF_CALLBACK_DATA));
-
+
for(int i = 0; i < WMF_MAX_DC+1; i++){ // be sure all values and pointers are empty to start with
- memset(&(d.dc[i]),0,sizeof(WMF_DEVICE_CONTEXT));
+ memset(&(d.dc[i]),0,sizeof(WMF_DEVICE_CONTEXT));
}
// set default drawing objects, these are active if no object has been selected
d.dc[0].active_pen = -1; // -1 when the default is used instead of a selected object
@@ -2917,6 +3078,8 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
d.dc[0].style.baseline_shift.value = 0;
d.dc[0].textColor = U_RGB(0, 0, 0); // default foreground color (black)
d.dc[0].bkColor = U_RGB(255, 255, 255); // default background color (white)
+ d.dc[0].bkMode = U_TRANSPARENT;
+ d.dc[0].dirty = 0;
// Default pen, WMF files that do not specify a pen are unlikely to look very good!
d.dc[0].style.stroke_dasharray_set = 0;
d.dc[0].style.stroke_linecap.computed = 2; // U_PS_ENDCAP_SQUARE;
@@ -2926,7 +3089,7 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
d.dc[0].style.stroke.value.color.set( 0, 0, 0 );
// Default brush = none, WMF files that do not specify a brush are unlikely to look very good!
d.dc[0].fill_set = false;
-
+
if (uri == NULL) {
return NULL;
}
@@ -2950,16 +3113,28 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
d.images.count = 0;
d.images.strings = NULL;
+ // set up the size default for patterns in defs. This might not be referenced if there are no patterns defined in the drawing.
+
+ *(d.defs) += "\n";
+ *(d.defs) += " <pattern id=\"WMFhbasepattern\" \n";
+ *(d.defs) += " patternUnits=\"userSpaceOnUse\"\n";
+ *(d.defs) += " width=\"6\" \n";
+ *(d.defs) += " height=\"6\" \n";
+ *(d.defs) += " x=\"0\" \n";
+ *(d.defs) += " y=\"0\"> \n";
+ *(d.defs) += " </pattern> \n";
+
+
size_t length;
char *contents;
- if(wmf_readdata(uri, &contents, &length))return(NULL);
-
+ if(wmf_readdata(uri, &contents, &length))return(NULL);
+
// set up the text reassembly system
if(!(d.tri = trinfo_init(NULL)))return(NULL);
(void) trinfo_load_ft_opts(d.tri, 1,
- FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP,
+ FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP,
FT_KERNING_UNSCALED);
-
+
(void) myMetaFileProc(contents,length, &d);
free(contents);
@@ -2973,17 +3148,17 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
delete d.defs;
free_wmf_strings(d.hatches);
free_wmf_strings(d.images);
-
+
if (d.wmf_obj) {
int i;
for (i=0; i<d.n_obj; i++)
delete_object(&d, i);
delete[] d.wmf_obj;
}
-
+
if (d.dc[0].style.stroke_dash.dash)
delete[] d.dc[0].style.stroke_dash.dash;
-
+
for(int i=0; i<=d.level;i++){
if(d.dc[i].font_name)free(d.dc[i].font_name);
}
diff --git a/src/extension/internal/wmf-inout.h b/src/extension/internal/wmf-inout.h
index 613d43c8d..07543e940 100644
--- a/src/extension/internal/wmf-inout.h
+++ b/src/extension/internal/wmf-inout.h
@@ -22,6 +22,11 @@ namespace Inkscape {
namespace Extension {
namespace Internal {
+#define DIRTY_NONE 0x00
+#define DIRTY_TEXT 0x01
+#define DIRTY_FILL 0x02
+#define DIRTY_STROKE 0x04 // not used currently
+
typedef struct {
int type;
int level;
@@ -40,21 +45,24 @@ typedef struct wmf_device_context {
bool stroke_set;
int stroke_mode; // enumeration from drawmode, not used if fill_set is not True
int stroke_idx; // used with DRAW_PATTERN and DRAW_IMAGE to return the appropriate fill
+ int stroke_recidx;// record used to regenerate hatch when it needs to be redone due to bkmode, textmode, etc. change
bool fill_set;
int fill_mode; // enumeration from drawmode, not used if fill_set is not True
int fill_idx; // used with DRAW_PATTERN and DRAW_IMAGE to return the appropriate fill
+ int fill_recidx; // record used to regenerate hatch when it needs to be redone due to bkmode, textmode, etc. change
+ int dirty; // holds the dirty bits for text, stroke, fill
int active_pen; // used when the active object is deleted to set the default values, -1 is none active
int active_brush; // ditto
- int active_font; // ditto
-
+ int active_font; // ditto. also used to hold object number in case font needs to be remade due to textcolor change.
U_POINT16 sizeWnd;
U_POINT16 sizeView;
U_POINT16 winorg;
U_POINT16 vieworg;
double ScaleInX, ScaleInY;
double ScaleOutX, ScaleOutY;
- U_COLORREF textColor;
+ uint16_t bkMode;
U_COLORREF bkColor;
+ U_COLORREF textColor;
uint16_t textAlign;
U_POINT16 cur;
} WMF_DEVICE_CONTEXT, *PWMF_DEVICE_CONTEXT;
diff --git a/src/extension/internal/wmf-print.cpp b/src/extension/internal/wmf-print.cpp
index 8f75f19df..0a0d06ea1 100644
--- a/src/extension/internal/wmf-print.cpp
+++ b/src/extension/internal/wmf-print.cpp
@@ -78,149 +78,137 @@ namespace Internal {
#define PXPERMETER 2835
#define MAXDISP 2.0 // This should be set in the output dialog. This is ok for experimenting, no more than 2 pixel deviation. Not actually used at present
-
enum drawmode {DRAW_PAINT, DRAW_PATTERN, DRAW_IMAGE, DRAW_LINEAR_GRADIENT, DRAW_RADIAL_GRADIENT};
struct FFNEXUS {
- char *fontname; //Font name
- FFNEXUS *next; //link to next nexus, NULL if this is the last
- double f1; //Vertical (rotating) offset factor (* font height)
- double f2; //Vertical (nonrotating) offset factor (* font height)
- double f3; //Horizontal (nonrotating) offset factor (* font height)
- };
+ char *fontname; //Font name
+ FFNEXUS *next; //link to next nexus, NULL if this is the last
+ double f1; //Vertical (rotating) offset factor (* font height)
+ double f2; //Vertical (nonrotating) offset factor (* font height)
+ double f3; //Horizontal (nonrotating) offset factor (* font height)
+};
struct GRADVALUES{
- Geom::Point p1; // center or start
- Geom::Point p2; // xhandle or end
- Geom::Point p3; // yhandle or unused
- double r; // radius or unused
- void *grad; // to access the stops information
- int mode; // DRAW_LINEAR_GRADIENT or DRAW_RADIAL_GRADIENT, if GRADVALUES is valid, else any value
- U_COLORREF bgc; // document background color, this is as good a place as any to keep it
- float rgb[3]; // also background color, but as 0-1 float.
- };
+ Geom::Point p1; // center or start
+ Geom::Point p2; // xhandle or end
+ Geom::Point p3; // yhandle or unused
+ double r; // radius or unused
+ void *grad; // to access the stops information
+ int mode; // DRAW_LINEAR_GRADIENT or DRAW_RADIAL_GRADIENT, if GRADVALUES is valid, else any value
+ U_COLORREF bgc; // document background color, this is as good a place as any to keep it
+ float rgb[3]; // also background color, but as 0-1 float.
+};
/* globals */
-static double PX2WORLD = 1200.0/90.0; // inkscape is 90 dpi, WMF file is 1200
-static bool FixPPTCharPos, FixPPTDashLine, FixPPTGrad2Polys, FixPPTPatternAsHatch;
-static FFNEXUS *wmf_short_fflist = NULL; //only those fonts so far encountered
-static FFNEXUS *wmf_long_fflist = NULL; //all the fonts described in ...\share\extensions\fontfix.conf
-static WMFTRACK *wt = NULL;
-static WMFHANDLES *wht = NULL;
-static GRADVALUES gv;
+static double PX2WORLD = 1200.0/90.0; // inkscape is 90 dpi, WMF file is 1200
+static bool FixPPTCharPos, FixPPTDashLine, FixPPTGrad2Polys, FixPPTPatternAsHatch;
+static FFNEXUS *wmf_short_fflist = NULL; //only those fonts so far encountered
+static FFNEXUS *wmf_long_fflist = NULL; //all the fonts described in ...\share\extensions\fontfix.conf
+static WMFTRACK *wt = NULL;
+static WMFHANDLES *wht = NULL;
+static GRADVALUES gv;
void PrintWmf::read_system_fflist(void){ //this is not called by any other source files
-FFNEXUS *temp=NULL;
-FFNEXUS *ptr=NULL;
-std::fstream fffile;
-std::string instr;
-char fontname[128];
-double f1,f2,f3;
-std::string path_to_ffconf;
-
- if(wmf_long_fflist)return;
- path_to_ffconf=INKSCAPE_EXTENSIONDIR;
+ FFNEXUS *temp=NULL;
+ FFNEXUS *ptr=NULL;
+ std::fstream fffile;
+ std::string instr;
+ char fontname[128];
+ double f1,f2,f3;
+ std::string path_to_ffconf;
+
+ if(wmf_long_fflist)return;
+ char *oldlocale = g_strdup(setlocale(LC_NUMERIC, NULL));
+ setlocale(LC_NUMERIC, "C");
+
+ path_to_ffconf=INKSCAPE_EXTENSIONDIR;
#ifdef WIN32
- path_to_ffconf.append("\\fontfix.conf"); //Windows path syntax
+ path_to_ffconf.append("\\fontfix.conf"); //Windows path syntax
#else
- path_to_ffconf.append("/fontfix.conf"); //Unix/linx path syntax
+ path_to_ffconf.append("/fontfix.conf"); //Unix/linx path syntax
#endif
- //open the input
- fffile.open(path_to_ffconf.c_str(), std::ios::in);
- if(!fffile.is_open()){
- g_error("Unable to open file: %s\n", path_to_ffconf.c_str());
- // throw "boom";
- }
-
- char *oldlocale = g_strdup (setlocale (LC_NUMERIC, NULL));
- setlocale (LC_NUMERIC, "C");
-
- while (std::getline(fffile,instr)){
- if (instr.empty()) {
- continue;
- }
- if(instr[0]=='#'){
- continue;
- }
- // not a comment, get the 4 values from the line
- int elements=sscanf(instr.c_str(),"%6lf %6lf %6lf %127[^\n]",&f1,&f2,&f3, &fontname[0]);
- if(elements!=4){
- setlocale (LC_NUMERIC, oldlocale);
- g_free (oldlocale);
- fffile.close();
- g_error("Expected \"f1 f2 f3 Fontname\" but did not find it in file: %s\n", path_to_ffconf.c_str());
- // throw "boom";
- }
- temp=(FFNEXUS *) calloc(1,sizeof(FFNEXUS)); //This will never be freed
- temp->f1=f1;
- temp->f2=f2;
- temp->f3=f3;
- temp->fontname=strdup(fontname); //This will never be freed
- temp->next=NULL; //just to be explicit, it is already 0
- if(ptr){
- ptr->next=temp;
- ptr=temp;
+ //open the input
+ fffile.open(path_to_ffconf.c_str(), std::ios::in);
+ if(!fffile.is_open()){
+ g_error("Unable to open file: %s\n", path_to_ffconf.c_str());
}
- else {
- wmf_long_fflist=ptr=temp;
+ while (std::getline(fffile,instr)){
+ if(instr[0]=='#')continue;
+ // not a comment, get the 4 values from the line
+ int elements=sscanf(instr.c_str(),"%lf %lf %lf %127[^\n]",&f1,&f2,&f3, &fontname[0]);
+ if(elements!=4){
+ g_error("Expected \"f1 f2 f3 Fontname\" but did not find it in file: %s\n", path_to_ffconf.c_str());
+ }
+ temp=(FFNEXUS *) calloc(1,sizeof(FFNEXUS)); //This will never be freed
+ temp->f1=f1;
+ temp->f2=f2;
+ temp->f3=f3;
+ temp->fontname=strdup(fontname); //This will never be freed
+ temp->next=NULL; //just to be explicit, it is already 0
+ if(ptr){
+ ptr->next=temp;
+ ptr=temp;
+ }
+ else {
+ wmf_long_fflist=ptr=temp;
+ }
}
- }
- setlocale (LC_NUMERIC, oldlocale);
- g_free (oldlocale);
- fffile.close();
+ fffile.close();
+
+ setlocale(LC_NUMERIC, oldlocale);
+ g_free(oldlocale);
}
/* Looks for the fontname in the long list. If it does not find it, it adds the default values
to the short list with this fontname. If it does find it, then it adds the specified values.
*/
void PrintWmf::search_long_fflist(const char *fontname, double *f1, double *f2, double *f3){ //this is not called by any other source files
-FFNEXUS *ptr=NULL;
-FFNEXUS *tmp=wmf_long_fflist;
- if(!wmf_long_fflist){
- g_message("Programming error search_long_fflist called before read_system_fflist\n");
- throw "boom";
- }
- ptr=wmf_long_fflist;
- while(ptr){
- if(!strcmp(ptr->fontname,fontname)){ tmp=ptr; break; }
- ptr=ptr->next;
- }
- //tmp points at either the found name, or the default, the first entry in wmf_long_fflist
- if(!wmf_short_fflist){
- ptr=wmf_short_fflist=(FFNEXUS *) malloc(sizeof(FFNEXUS));
- }
- else {
- ptr=wmf_short_fflist;
- while(ptr->next){ ptr=ptr->next; }
- ptr->next=(FFNEXUS *) malloc(sizeof(FFNEXUS));
- ptr=ptr->next;
- }
- ptr->fontname=strdup(tmp->fontname);
- *f1 = ptr->f1 = tmp->f1;
- *f2 = ptr->f2 = tmp->f2;
- *f3 = ptr->f3 = tmp->f3;
- ptr->next=NULL;
+ FFNEXUS *ptr=NULL;
+ FFNEXUS *tmp=wmf_long_fflist;
+ if(!wmf_long_fflist){
+ g_error("Programming error search_long_fflist called before read_system_fflist\n");
+ }
+ ptr=wmf_long_fflist;
+ while(ptr){
+ if(!strcmp(ptr->fontname,fontname)){ tmp=ptr; break; }
+ ptr=ptr->next;
+ }
+ //tmp points at either the found name, or the default, the first entry in wmf_long_fflist
+ if(!wmf_short_fflist){
+ ptr=wmf_short_fflist=(FFNEXUS *) malloc(sizeof(FFNEXUS));
+ }
+ else {
+ ptr=wmf_short_fflist;
+ while(ptr->next){ ptr=ptr->next; }
+ ptr->next=(FFNEXUS *) malloc(sizeof(FFNEXUS));
+ ptr=ptr->next;
+ }
+ ptr->fontname=strdup(tmp->fontname);
+ *f1 = ptr->f1 = tmp->f1;
+ *f2 = ptr->f2 = tmp->f2;
+ *f3 = ptr->f3 = tmp->f3;
+ ptr->next=NULL;
}
/* Looks for the fontname in the short list. If it does not find it, it looks in the wmf_long_fflist.
Either way it returns the f1, f2, f3 parameters for the font, even if these are for the default.
*/
void PrintWmf::search_short_fflist(const char *fontname, double *f1, double *f2, double *f3){ //this is not called by any other source files
-FFNEXUS *ptr=NULL;
-static FFNEXUS *last=NULL;
- if(!wmf_long_fflist){
- g_message("Programming error search_short_fflist called before read_system_fflist\n");
- throw "boom";
- }
- // This speeds things up a lot - if the same font is called twice in a row, pull it out immediately
- if(last && !strcmp(last->fontname,fontname)){ ptr=last; }
- else { ptr=wmf_short_fflist; } // wmf_short_fflist may still be NULL
- while(ptr){
- if(!strcmp(ptr->fontname,fontname)){ *f1=ptr->f1; *f2=ptr->f2; *f3=ptr->f3; last=ptr; return; }
- ptr=ptr->next;
- }
- //reach this point only if there is no match
- search_long_fflist(fontname, f1, f2, f3);
+ FFNEXUS *ptr=NULL;
+ static FFNEXUS *last=NULL;
+
+ if(!wmf_long_fflist){
+ g_error("Programming error search_short_fflist called before read_system_fflist\n");
+ }
+ // This speeds things up a lot - if the same font is called twice in a row, pull it out immediately
+ if(last && !strcmp(last->fontname,fontname)){ ptr=last; }
+ else { ptr=wmf_short_fflist; } // wmf_short_fflist may still be NULL
+ while(ptr){
+ if(!strcmp(ptr->fontname,fontname)){ *f1=ptr->f1; *f2=ptr->f2; *f3=ptr->f3; last=ptr; return; }
+ ptr=ptr->next;
+ }
+ //reach this point only if there is no match
+ search_long_fflist(fontname, f1, f2, f3);
}
void PrintWmf::smuggle_adxky_out(const char *string, int16_t **adx, double *ky, int *ndx, float scale){
@@ -235,11 +223,11 @@ void PrintWmf::smuggle_adxky_out(const char *string, int16_t **adx, double *ky,
if(!*ndx)return; // this could happen with an empty string
cptr += 7;
ladx = (int16_t *) malloc(*ndx * sizeof(int16_t) );
- if(!ladx)throw "Out of memory";
+ if(!ladx)g_error("Out of memory");
*adx=ladx;
for(i=0; i<*ndx; i++,cptr+=7, ladx++){
- sscanf(cptr,"%7f",&fdx);
- *ladx=(int16_t) round(fdx * scale);
+ sscanf(cptr,"%7f",&fdx);
+ *ladx=(int16_t) round(fdx * scale);
}
cptr++; // skip 2nd fake terminator
sscanf(cptr,"%7f",&fdx);
@@ -247,16 +235,15 @@ void PrintWmf::smuggle_adxky_out(const char *string, int16_t **adx, double *ky,
}
/* convert an 0RGB color to EMF U_COLORREF.
-inverse of sethexcolor() in emf-inout.cpp
+inverse of sethexcolor() in wmf-inout.cpp
*/
U_COLORREF PrintWmf::gethexcolor(uint32_t color){
-
U_COLORREF out;
- out = U_RGB(
- (color >> 16) & 0xFF,
- (color >> 8) & 0xFF,
- (color >> 0) & 0xFF
- );
+ out = U_RGB(
+ (color >> 16) & 0xFF,
+ (color >> 8) & 0xFF,
+ (color >> 0) & 0xFF
+ );
return(out);
}
@@ -279,7 +266,7 @@ uint32_t PrintWmf::transweight(const unsigned int inkweight){
PrintWmf::PrintWmf (void)
{
- // all of the class variables are initialized elsewhere, many in PrintWmf::Begin,
+ // all of the class variables are initialized elsewhere, many in PrintWmf::Begin,
}
@@ -302,13 +289,12 @@ unsigned int PrintWmf::setup (Inkscape::Extension::Print * /*mod*/)
unsigned int PrintWmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
{
-// std::cout << "begin " << std::endl;
- char *rec;
+ char *rec;
+ gchar const *utf8_fn = mod->get_param_string("destination");
- gchar const *utf8_fn = mod->get_param_string("destination");
- FixPPTCharPos = mod->get_param_bool("FixPPTCharPos");
- FixPPTDashLine = mod->get_param_bool("FixPPTDashLine");
- FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys");
+ FixPPTCharPos = mod->get_param_bool("FixPPTCharPos");
+ FixPPTDashLine = mod->get_param_bool("FixPPTDashLine");
+ FixPPTGrad2Polys = mod->get_param_bool("FixPPTGrad2Polys");
FixPPTPatternAsHatch = mod->get_param_bool("FixPPTPatternAsHatch");
(void) wmf_start(utf8_fn, 1000000, 250000, &wt); // Initialize the wt structure
@@ -321,18 +307,18 @@ unsigned int PrintWmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
// initialize a few global variables
hbrush = hpen = 0;
- use_stroke = use_fill = simple_shape = false;
+ use_stroke = use_fill = simple_shape = usebk = false;
Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
if(nv){
- const char *p1 = nv->attribute("pagecolor");
- char *p2;
- uint32_t lc = strtoul( &p1[1], &p2, 16 ); // it looks like "#ABC123"
- if(*p2)lc=0;
- gv.bgc = gethexcolor(lc);
- gv.rgb[0] = (float) U_RGBAGetR(gv.bgc)/255.0;
- gv.rgb[1] = (float) U_RGBAGetG(gv.bgc)/255.0;
- gv.rgb[2] = (float) U_RGBAGetB(gv.bgc)/255.0;
+ const char *p1 = nv->attribute("pagecolor");
+ char *p2;
+ uint32_t lc = strtoul( &p1[1], &p2, 16 ); // it looks like "#ABC123"
+ if(*p2)lc=0;
+ gv.bgc = gethexcolor(lc);
+ gv.rgb[0] = (float) U_RGBAGetR(gv.bgc)/255.0;
+ gv.rgb[1] = (float) U_RGBAGetG(gv.bgc)/255.0;
+ gv.rgb[2] = (float) U_RGBAGetB(gv.bgc)/255.0;
}
bool pageBoundingBox;
@@ -349,67 +335,78 @@ unsigned int PrintWmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
d *= Geom::Scale(IN_PER_PX); // 90 dpi inside inkscape, wmf file will be 1200 dpi
+ /* -1/1200 in next two lines so that WMF read in will write out again at exactly the same size */
+ float dwInchesX = d.width() - 1.0/1200.0;
+ float dwInchesY = d.height() - 1.0/1200.0;
+ int dwPxX = round(dwInchesX * 1200.0);
+ int dwPxY = round(dwInchesY * 1200.0);
+#if 0
float dwInchesX = d.width();
float dwInchesY = d.height();
- int dwPxX = round(d.width() *1200.0);
- int dwPxY = round(d.height()*1200.0);
+ int dwPxX = round(d.width() * 1200.0);
+ int dwPxY = round(d.height() * 1200.0);
+#endif
PU_PAIRF ps = U_PAIRF_set(dwInchesX, dwInchesY);
rec = U_WMRHEADER_set(ps,1200); // Example: drawing is A4 horizontal, 1200 dpi
if(!rec){
- throw "Fatal programming error in PrintWmf::begin at WMRSETMAPMODE";
+ g_error("Fatal programming error in PrintWmf::begin at WMRSETMAPMODE");
}
(void) wmf_header_append((PU_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)){
- throw "Fatal programming error in PrintWmf::begin at WMRSETWINDOWEXT";
+ 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)){
- throw "Fatal programming error in PrintWmf::begin at WMRSETWINDOWORG";
+ 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)){
- throw "Fatal programming error in PrintWmf::begin at WMRSETMAPMODE";
+ g_error("Fatal programming error in PrintWmf::begin at WMRSETMAPMODE");
}
- // bkmode never changes
+ /* 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)){
- throw "Fatal programming error in PrintWmf::begin at U_WMRSETBKMODE";
+ 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)){
- throw "Fatal programming error in PrintWmf::begin at U_WMRSETPOLYFILLMODE";
+ g_error("Fatal programming error in PrintWmf::begin at U_WMRSETPOLYFILLMODE");
}
- // Text alignment never changes
+ // Text alignment: (Never changes)
+ // - (x,y) coordinates received by this filter are those of the point where the text
+ // 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)){
- throw "Fatal programming error in PrintWmf::text at U_WMRSETTEXTALIGN_set";
+ g_error("Fatal programming error in PrintWmf::text 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)){
- throw "Fatal programming error in PrintWmf::text at U_WMRSETTEXTCOLOR_set";
+ g_error("Fatal programming error in PrintWmf::text at U_WMRSETTEXTCOLOR_set");
}
rec = U_WMRSETROP2_set(U_R2_COPYPEN);
if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
- throw "Fatal programming error in PrintWmf::begin at U_WMRSETROP2";
+ 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)){
- throw "Fatal programming error in PrintWmf::begin at wmiterlimit_set";
+ g_error("Fatal programming error in PrintWmf::begin at wmiterlimit_set");
}
@@ -418,14 +415,14 @@ unsigned int PrintWmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
uint32_t Pen;
rec = wcreatepenindirect_set(&Pen, wht, up);
if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
- throw "Fatal programming error in PrintWmf::begin at wcreatepenindirect_set";
+ 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)){
- throw "Fatal programming error in PrintWmf::begin at wcreatepenindirect_set";
+ g_error("Fatal programming error in PrintWmf::begin at wcreatepenindirect_set");
}
destroy_pen(); // make this pen active
@@ -433,92 +430,95 @@ unsigned int PrintWmf::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
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)){
- throw "Fatal programming error in PrintWmf::begin at wcreatebrushindirect_set";
+ g_error("Fatal programming error in PrintWmf::begin at wcreatebrushindirect_set");
}
destroy_brush(); // make this brush active
-// std::cout << "end begin" << std::endl;
-
return 0;
}
unsigned int PrintWmf::finish (Inkscape::Extension::Print * /*mod*/)
{
-// std::cout << "finish " << std::endl;
char *rec;
if (!wt) return 0;
// get rid of null brush
rec = wdeleteobject_set(&hbrush_null, wht);
if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
- throw "Fatal programming error in PrintWmf::finish at wdeleteobject_set null brush";
+ 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)){
- throw "Fatal programming error in PrintWmf::finish at wdeleteobject_set null pen";
+ 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)){
- throw "Fatal programming error in PrintWmf::finish at wdeleteobject_set filler object";
+ 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)){
- throw "Fatal programming error in PrintWmf::finish";
+ g_error("Fatal programming error in PrintWmf::finish");
}
(void) wmf_finish(wt); // Finalize and write out the WMF
wmf_free(&wt); // clean up
wmf_htable_free(&wht); // clean up
-// std::cout << "end finish" << std::endl;
return 0;
}
-unsigned int PrintWmf::comment (Inkscape::Extension::Print * /*module*/,
- const char * /*comment*/)
+unsigned int PrintWmf::comment ( Inkscape::Extension::Print * /*module*/, const char * /*comment*/)
{
-// std::cout << "comment " << std::endl;
if (!wt) return 0;
// earlier versions had flush of fill here, but it never executed and was removed
-// std::cout << "end comment" << std::endl;
return 0;
}
// Extract hatchType, hatchColor from a name like
-// *MFhatch<hatchType>_<hatchColor> (WMF or EMF hatches are the same)
-// Where the first one is a number and the second a color in hex.
-// hatchType and hatchColor have been set with defaults before this is called.
+// *MFhatch<hatchType>_<hatchColor>[_<bkcolor>] (WMF or EMF hatches are the same)
+// Where the first one is a number and the second (and third) a color in hex.
+// hatchType, hatchColor, bkColor have been set with defaults before this is called.
//
-void PrintWmf::hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor){
- int val;
- uint32_t hcolor=0;
- // name should be EMFhatch or WMFhatch but *MFhatch will be accepted
- if(0!=strncmp(&name[1],"MFhatch",7)){ return; } // not anything we can parse
- name+=8; // WMFhatch already detected
- val = 0;
- while(*name && isdigit(*name)){
- val = 10*val + *name - '0';
- name++;
- }
- *hatchType = val;
- if(*name != '_' || val > U_HS_DITHEREDBKCLR){ // wrong syntax, cannot classify
- *hatchType = -1;
- }
- else {
- name++;
- if(1 != sscanf(name,"%X",&hcolor)){ *hatchType = -1; } // again wrong syntax, cannot classify
- *hatchColor = gethexcolor(hcolor);
- }
- if(*hatchType > U_HS_SOLIDCLR)*hatchType = U_HS_SOLIDCLR;
+void PrintWmf::hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor){
+ int val;
+ uint32_t hcolor=0;
+ uint32_t bcolor=0;
+
+ // name should be EMFhatch or WMFhatch but *MFhatch will be accepted
+ if(0!=strncmp(&name[1],"MFhatch",7)){ return; } // not anything we can parse
+ name += 8; // WMFhatch already detected
+ val = 0;
+ while(*name && isdigit(*name)){
+ val = 10*val + *name - '0';
+ name++;
+ }
+ *hatchType = val;
+ if(*name != '_' || val > U_HS_DITHEREDBKCLR){ // wrong syntax, cannot classify
+ *hatchType = -1;
+ }
+ else {
+ name++;
+ if(2 != sscanf(name,"%X_%X", &hcolor, &bcolor)){ // not a pattern with background
+ if(1 != sscanf(name,"%X", &hcolor)){ *hatchType = -1; } // not a pattern, cannot classify
+ *hatchColor = gethexcolor(hcolor);
+ }
+ else {
+ *hatchColor = gethexcolor(hcolor);
+ *bkColor = gethexcolor(bcolor);
+ usebk = true;
+ }
+ }
+ /* Everything > U_HS_SOLIDCLR is solid, just specify the color in the brush rather than messing around with background or textcolor */
+ if(*hatchType > U_HS_SOLIDCLR)*hatchType = U_HS_SOLIDCLR;
}
//
@@ -528,124 +528,124 @@ void PrintWmf::hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor
// otherwise hatchType is set to -1 and hatchColor is not defined.
//
-void PrintWmf::brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor){
- if(depth==0){
- *epixbuf = NULL;
- *hatchType = -1;
- *hatchColor = U_RGB(0,0,0);
- }
- depth++;
- // first look along the pattern chain, if there is one
- if(SP_IS_PATTERN(parent)){
- for (SPPattern *pat_i = SP_PATTERN(parent); pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) {
- if(SP_IS_IMAGE(pat_i)){
- *epixbuf = ((SPImage *)pat_i)->pixbuf;
- return;
- }
- char temp[32]; // large enough
- temp[31]='\0';
- strncpy(temp,pat_i->getAttribute("id"),31); // Some names may be longer than [EW]MFhatch#_######
- hatch_classify(temp,hatchType,hatchColor);
- if(*hatchType != -1)return;
-
- // still looking? Look at this pattern's children, if there are any
- SPObject *child = pat_i->firstChild();
- while(child && !(*epixbuf) && (*hatchType == -1)){
- brush_classify(child, depth, epixbuf, hatchType, hatchColor);
+void PrintWmf::brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor){
+ if(depth==0){
+ *epixbuf = NULL;
+ *hatchType = -1;
+ *hatchColor = U_RGB(0,0,0);
+ *bkColor = U_RGB(255,255,255);
+ }
+ depth++;
+ // first look along the pattern chain, if there is one
+ if(SP_IS_PATTERN(parent)){
+ for (SPPattern *pat_i = SP_PATTERN(parent); pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) {
+ if(SP_IS_IMAGE(pat_i)){
+ *epixbuf = ((SPImage *)pat_i)->pixbuf;
+ return;
+ }
+ char temp[32]; // large enough
+ temp[31]='\0';
+ strncpy(temp,pat_i->getAttribute("id"),31); // Some names may be longer than [EW]MFhatch#_######
+ hatch_classify(temp, hatchType, hatchColor, bkColor);
+ if(*hatchType != -1)return;
+
+ // still looking? Look at this pattern's children, if there are any
+ SPObject *child = pat_i->firstChild();
+ while(child && !(*epixbuf) && (*hatchType == -1)){
+ brush_classify(child, depth, epixbuf, hatchType, hatchColor, bkColor);
+ child = child->getNext();
+ }
+ }
+ }
+ else if(SP_IS_IMAGE(parent)){
+ *epixbuf = ((SPImage *)parent)->pixbuf;
+ return;
+ }
+ else { // some inkscape rearrangements pass through nodes between pattern and image which are not classified as either.
+ SPObject *child = parent->firstChild();
+ while(child && !(*epixbuf) && (*hatchType == -1)){
+ brush_classify(child, depth, epixbuf, hatchType, hatchColor, bkColor);
child = child->getNext();
- }
- }
- }
- else if(SP_IS_IMAGE(parent)){
- *epixbuf = ((SPImage *)parent)->pixbuf;
- return;
- }
- else { // some inkscape rearrangements pass through nodes between pattern and image which are not classified as either.
- SPObject *child = parent->firstChild();
- while(child && !(*epixbuf) && (*hatchType == -1)){
- brush_classify(child, depth, epixbuf, hatchType, hatchColor);
- child = child->getNext();
- }
- }
+ }
+ }
}
//swap R/B in 4 byte pixel
void PrintWmf::swapRBinRGBA(char *px, int pixels){
- char tmp;
- for(int i=0;i<pixels*4;px+=4,i+=4){
- tmp=px[2];
- px[2]=px[0];
- px[0]=tmp;
- }
+ char tmp;
+ for(int i=0;i<pixels*4;px+=4,i+=4){
+ tmp=px[2];
+ px[2]=px[0];
+ px[0]=tmp;
+ }
}
/* opacity weighting of two colors as float. v1 is the color, op is its opacity, v2 is the background color */
inline float opweight(float v1, float v2, float op){
- return v1*op + v2*(1.0-op);
+ return v1*op + v2*(1.0-op);
}
U_COLORREF PrintWmf::avg_stop_color(SPGradient *gr){
- U_COLORREF cr;
- int last = gr->vector.stops.size() -1;
- if(last>=1){
- float rgbs[3];
- float rgbe[3];
- float ops,ope;
-
- ops = gr->vector.stops[0 ].opacity;
- ope = gr->vector.stops[last].opacity;
- sp_color_get_rgb_floatv(&gr->vector.stops[0 ].color, rgbs);
- sp_color_get_rgb_floatv(&gr->vector.stops[last].color, rgbe);
-
- /* Replace opacity at start & stop with that fraction background color, then average those two for final color. */
- cr = U_RGB(
- 255*(( opweight(rgbs[0],gv.rgb[0],ops) + opweight(rgbe[0],gv.rgb[0],ope) )/2.0),
- 255*(( opweight(rgbs[1],gv.rgb[1],ops) + opweight(rgbe[1],gv.rgb[1],ope) )/2.0),
- 255*(( opweight(rgbs[2],gv.rgb[2],ops) + opweight(rgbe[2],gv.rgb[2],ope) )/2.0)
- );
- }
- else {
- cr = U_RGB(0, 0, 0); // The default fill
- }
- return cr;
+ U_COLORREF cr;
+ int last = gr->vector.stops.size() -1;
+ if(last>=1){
+ float rgbs[3];
+ float rgbe[3];
+ float ops,ope;
+
+ ops = gr->vector.stops[0 ].opacity;
+ ope = gr->vector.stops[last].opacity;
+ sp_color_get_rgb_floatv(&gr->vector.stops[0 ].color, rgbs);
+ sp_color_get_rgb_floatv(&gr->vector.stops[last].color, rgbe);
+
+ /* Replace opacity at start & stop with that fraction background color, then average those two for final color. */
+ cr = U_RGB(
+ 255*(( opweight(rgbs[0],gv.rgb[0],ops) + opweight(rgbe[0],gv.rgb[0],ope) )/2.0),
+ 255*(( opweight(rgbs[1],gv.rgb[1],ops) + opweight(rgbe[1],gv.rgb[1],ope) )/2.0),
+ 255*(( opweight(rgbs[2],gv.rgb[2],ops) + opweight(rgbe[2],gv.rgb[2],ope) )/2.0)
+ );
+ }
+ else {
+ cr = U_RGB(0, 0, 0); // The default fill
+ }
+ return cr;
}
int PrintWmf::hold_gradient(void *gr, int mode){
- gv.mode = mode;
- gv.grad = gr;
- if(mode==DRAW_RADIAL_GRADIENT){
- SPRadialGradient *rg = (SPRadialGradient *) gr;
- gv.r = rg->r.computed; // radius, but of what???
- gv.p1 = Geom::Point(rg->cx.computed, rg->cy.computed); // center
- gv.p2 = Geom::Point(gv.r, 0) + gv.p1; // xhandle
- gv.p3 = Geom::Point(0, -gv.r) + gv.p1; // yhandle
- if (rg->gradientTransform_set) {
- gv.p1 = gv.p1 * rg->gradientTransform;
- gv.p2 = gv.p2 * rg->gradientTransform;
- gv.p3 = gv.p3 * rg->gradientTransform;
- }
- }
- else if(mode==DRAW_LINEAR_GRADIENT){
- SPLinearGradient *lg = (SPLinearGradient *) gr;
- gv.r = 0; // unused
- gv.p1 = Geom::Point (lg->x1.computed, lg->y1.computed); // start
- gv.p2 = Geom::Point (lg->x2.computed, lg->y2.computed); // end
- gv.p3 = Geom::Point (0, 0); // unused
- if (lg->gradientTransform_set) {
- gv.p1 = gv.p1 * lg->gradientTransform;
- gv.p2 = gv.p2 * lg->gradientTransform;
- }
- }
- else {
- throw "Fatal programming error, hold_gradient() in wmf-print.cpp called with invalid draw mode";
- }
- return 1;
+ gv.mode = mode;
+ gv.grad = gr;
+ if(mode==DRAW_RADIAL_GRADIENT){
+ SPRadialGradient *rg = (SPRadialGradient *) gr;
+ gv.r = rg->r.computed; // radius, but of what???
+ gv.p1 = Geom::Point(rg->cx.computed, rg->cy.computed); // center
+ gv.p2 = Geom::Point(gv.r, 0) + gv.p1; // xhandle
+ gv.p3 = Geom::Point(0, -gv.r) + gv.p1; // yhandle
+ if (rg->gradientTransform_set) {
+ gv.p1 = gv.p1 * rg->gradientTransform;
+ gv.p2 = gv.p2 * rg->gradientTransform;
+ gv.p3 = gv.p3 * rg->gradientTransform;
+ }
+ }
+ else if(mode==DRAW_LINEAR_GRADIENT){
+ SPLinearGradient *lg = (SPLinearGradient *) gr;
+ gv.r = 0; // unused
+ gv.p1 = Geom::Point (lg->x1.computed, lg->y1.computed); // start
+ gv.p2 = Geom::Point (lg->x2.computed, lg->y2.computed); // end
+ gv.p3 = Geom::Point (0, 0); // unused
+ if (lg->gradientTransform_set) {
+ gv.p1 = gv.p1 * lg->gradientTransform;
+ gv.p2 = gv.p2 * lg->gradientTransform;
+ }
+ }
+ else {
+ g_error("Fatal programming error, hold_gradient() in wmf-print.cpp called with invalid draw mode");
+ }
+ return 1;
}
// 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)
{
-// std::cout << "create_brush " << std::endl;
float rgb[3];
char *rec;
U_WLOGBRUSH lb;
@@ -655,6 +655,7 @@ int PrintWmf::create_brush(SPStyle const *style, PU_COLORREF fcolor)
uint32_t brushStyle;
int hatchType;
U_COLORREF hatchColor;
+ U_COLORREF bkColor;
uint32_t width = 0; // quiets a harmless compiler warning, initialization not otherwise required.
uint32_t height = 0;
@@ -665,157 +666,164 @@ int PrintWmf::create_brush(SPStyle const *style, PU_COLORREF fcolor)
fill_mode = DRAW_PAINT;
brushStyle = U_BS_SOLID;
hatchType = U_HS_SOLIDCLR;
+ bkColor = U_RGB(0, 0, 0);
if(fcolor){ hatchColor = *fcolor; }
else { hatchColor = U_RGB(0, 0, 0); }
if (!fcolor && style) {
if(style->fill.isColor()){
- fill_mode = DRAW_PAINT;
- float opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value);
- if (opacity <= 0.0)opacity = 0.0; // basically the same as no fill
+ fill_mode = DRAW_PAINT;
+ float opacity = SP_SCALE24_TO_FLOAT(style->fill_opacity.value);
+ if (opacity <= 0.0)opacity = 0.0; // basically the same as no fill
- sp_color_get_rgb_floatv( &style->fill.value.color, rgb );
- hatchColor = U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]);
+ sp_color_get_rgb_floatv( &style->fill.value.color, rgb );
+ hatchColor = U_RGB(255*rgb[0], 255*rgb[1], 255*rgb[2]);
- fmode = style->fill_rule.computed == 0 ? U_WINDING : (style->fill_rule.computed == 2 ? U_ALTERNATE : U_ALTERNATE);
+ fmode = style->fill_rule.computed == 0 ? U_WINDING : (style->fill_rule.computed == 2 ? U_ALTERNATE : U_ALTERNATE);
}
else if(SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style))){ // must be paint-server
- SPPaintServer *paintserver = style->fill.value.href->getObject();
- SPPattern *pat = SP_PATTERN (paintserver);
- double dwidth = pattern_width(pat);
- double dheight = pattern_height(pat);
- width = dwidth;
- height = dheight;
- brush_classify(pat,0,&pixbuf,&hatchType,&hatchColor);
- if(pixbuf){ fill_mode = DRAW_IMAGE; }
- else { // pattern
- fill_mode = DRAW_PATTERN;
- if(hatchType == -1){ // Not a standard hatch, so force it to something
- hatchType = U_HS_CROSS;
- hatchColor = U_RGB(0xFF,0xC3,0xC3);
- }
- }
- if(FixPPTPatternAsHatch){
- if(hatchType == -1){ // image or unclassified
- fill_mode = DRAW_PATTERN;
- hatchType = U_HS_DIAGCROSS;
- hatchColor = U_RGB(0xFF,0xC3,0xC3);
- }
- }
- brushStyle = U_BS_HATCHED;
+ SPPaintServer *paintserver = style->fill.value.href->getObject();
+ SPPattern *pat = SP_PATTERN (paintserver);
+ double dwidth = pattern_width(pat);
+ double dheight = pattern_height(pat);
+ width = dwidth;
+ height = dheight;
+ brush_classify(pat,0,&pixbuf,&hatchType,&hatchColor,&bkColor);
+ if(pixbuf){ fill_mode = DRAW_IMAGE; }
+ else { // pattern
+ fill_mode = DRAW_PATTERN;
+ if(hatchType == -1){ // Not a standard hatch, so force it to something
+ hatchType = U_HS_CROSS;
+ hatchColor = U_RGB(0xFF,0xC3,0xC3);
+ }
+ }
+ if(FixPPTPatternAsHatch){
+ if(hatchType == -1){ // image or unclassified
+ fill_mode = DRAW_PATTERN;
+ hatchType = U_HS_DIAGCROSS;
+ hatchColor = U_RGB(0xFF,0xC3,0xC3);
+ }
+ }
+ brushStyle = U_BS_HATCHED;
}
else if(SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style))){ // must be a gradient
- // currently we do not do anything with gradients, the code below just sets the color to the average of the stops
- SPPaintServer *paintserver = style->fill.value.href->getObject();
- SPLinearGradient *lg = NULL;
- SPRadialGradient *rg = NULL;
-
- if (SP_IS_LINEARGRADIENT (paintserver)) {
- lg = SP_LINEARGRADIENT(paintserver);
- SP_GRADIENT(lg)->ensureVector(); // when exporting from commandline, vector is not built
- fill_mode = DRAW_LINEAR_GRADIENT;
- }
- else if (SP_IS_RADIALGRADIENT (paintserver)) {
- rg = SP_RADIALGRADIENT(paintserver);
- SP_GRADIENT(rg)->ensureVector(); // when exporting from commandline, vector is not built
- fill_mode = DRAW_RADIAL_GRADIENT;
- }
- else {
- // default fill
- }
-
- if(rg){
- if(FixPPTGrad2Polys){ return hold_gradient(rg, fill_mode); }
- else { hatchColor = avg_stop_color(rg); }
- }
- else if(lg){
- if(FixPPTGrad2Polys){ return hold_gradient(lg, fill_mode); }
- else { hatchColor = avg_stop_color(lg); }
- }
+ // currently we do not do anything with gradients, the code below just sets the color to the average of the stops
+ SPPaintServer *paintserver = style->fill.value.href->getObject();
+ SPLinearGradient *lg = NULL;
+ SPRadialGradient *rg = NULL;
+
+ if (SP_IS_LINEARGRADIENT (paintserver)) {
+ lg = SP_LINEARGRADIENT(paintserver);
+ SP_GRADIENT(lg)->ensureVector(); // when exporting from commandline, vector is not built
+ fill_mode = DRAW_LINEAR_GRADIENT;
+ }
+ else if (SP_IS_RADIALGRADIENT (paintserver)) {
+ rg = SP_RADIALGRADIENT(paintserver);
+ SP_GRADIENT(rg)->ensureVector(); // when exporting from commandline, vector is not built
+ fill_mode = DRAW_RADIAL_GRADIENT;
+ }
+ else {
+ // default fill
+ }
+
+ if(rg){
+ if(FixPPTGrad2Polys){ return hold_gradient(rg, fill_mode); }
+ else { hatchColor = avg_stop_color(rg); }
+ }
+ else if(lg){
+ if(FixPPTGrad2Polys){ return hold_gradient(lg, fill_mode); }
+ else { hatchColor = avg_stop_color(lg); }
+ }
}
}
else { // if (!style)
- // default fill
+ // default fill
}
- lb = U_WLOGBRUSH_set(brushStyle, hatchColor, hatchType);
-
switch(fill_mode){
- case DRAW_LINEAR_GRADIENT: // fill with average color unless gradients are converted to slices
- case DRAW_RADIAL_GRADIENT: // ditto
- case DRAW_PAINT:
- case DRAW_PATTERN:
- rec = wcreatebrushindirect_set(&brush, wht, lb);
- if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
- throw "Fatal programming error in PrintWmf::create_brush at createbrushindirect_set";
- }
- break;
- case DRAW_IMAGE:
- char *px;
- char *rgba_px;
- uint32_t cbPx;
- uint32_t colortype;
- PU_RGBQUAD ct;
- int numCt;
- U_BITMAPINFOHEADER Bmih;
- PU_BITMAPINFO Bmi;
- rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // 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);
- // Not sure why the next swap is needed because the preceding does it, and the code is identical
- // to that in stretchdibits_set, which does not need this.
- swapRBinRGBA(px, width*height);
- 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)){
- throw "Fatal programming error in PrintWmf::create_brush at createdibpatternbrushpt_set";
- }
- free(px);
- free(Bmi); // ct will be NULL because of colortype
- break;
+ case DRAW_LINEAR_GRADIENT: // fill with average color unless gradients are converted to slices
+ case DRAW_RADIAL_GRADIENT: // ditto
+ case DRAW_PAINT:
+ case DRAW_PATTERN:
+ // 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)){
+ 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)){
+ 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)){
+ g_error("Fatal programming error in PrintWmf::create_brush at createbrushindirect_set");
+ }
+ break;
+ case DRAW_IMAGE:
+ char *px;
+ char *rgba_px;
+ uint32_t cbPx;
+ uint32_t colortype;
+ PU_RGBQUAD ct;
+ int numCt;
+ U_BITMAPINFOHEADER Bmih;
+ PU_BITMAPINFO Bmi;
+ rgba_px = (char *) gdk_pixbuf_get_pixels(pixbuf); // 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);
+ // Not sure why the next swap is needed because the preceding does it, and the code is identical
+ // to that in stretchdibits_set, which does not need this.
+ swapRBinRGBA(px, width*height);
+ 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)){
+ g_error("Fatal programming error in PrintWmf::create_brush at createdibpatternbrushpt_set");
+ }
+ free(px);
+ free(Bmi); // ct will be NULL because of colortype
+ break;
}
+
hbrush = brush; // need this later for destroy_brush
rec = wselectobject_set(brush, wht);
if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
- throw "Fatal programming error in PrintWmf::create_brush at wselectobject_set";
+ 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)){
- throw "Fatal programming error in PrintWmf::create_brush at U_WMRSETPOLYFILLMODE_set";
- }
+ hpolyfillmode=fmode;
+ rec = U_WMRSETPOLYFILLMODE_set(fmode);
+ if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
+ g_error("Fatal programming error in PrintWmf::create_brush at U_WMRSETPOLYFILLMODE_set");
+ }
}
-// std::cout << "end create_brush " << std::endl;
+
return 0;
}
void PrintWmf::destroy_brush()
{
-// std::cout << "destroy_brush " << std::endl;
char *rec;
// 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)){
- throw "Fatal programming error in PrintWmf::destroy_brush";
- }
- hbrush = 0;
+ rec = wdeleteobject_set(&hbrush, wht);
+ if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
+ g_error("Fatal programming error in PrintWmf::destroy_brush");
+ }
+ hbrush = 0;
}
// (re)select the null brush
rec = wselectobject_set(hbrush_null, wht);
if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
- throw "Fatal programming error in PrintWmf::destroy_brush";
- }
-
-// std::cout << "end destroy_brush" << std::endl;
+ g_error("Fatal programming error in PrintWmf::destroy_brush");
+ }
}
@@ -827,7 +835,6 @@ int PrintWmf::create_pen(SPStyle const *style, const Geom::Affine &transform)
U_COLORREF penColor;
U_PEN up;
int modstyle;
-// std::cout << "create_pen " << std::endl;
if (!wt) return 0;
@@ -860,23 +867,24 @@ int PrintWmf::create_pen(SPStyle const *style, const Geom::Affine &transform)
// most WMF readers will ignore linecap and linejoin, but set them anyway. Inkscape itself can read them back in.
- if (style->stroke_linecap.computed == 0) { modstyle |= U_PS_ENDCAP_FLAT; }
- else if (style->stroke_linecap.computed == 1) { modstyle |= U_PS_ENDCAP_ROUND; }
- else { modstyle |= U_PS_ENDCAP_SQUARE; }
+ if ( style->stroke_linecap.computed == 0) { modstyle |= U_PS_ENDCAP_FLAT; }
+ else if (style->stroke_linecap.computed == 1) { modstyle |= U_PS_ENDCAP_ROUND; }
+ else { modstyle |= U_PS_ENDCAP_SQUARE; }
if (style->stroke_linejoin.computed == 0) {
- float miterlimit = style->stroke_miterlimit.value; // This is a ratio.
- if (miterlimit < 1)miterlimit = 1;
-
- // most WMF readers will ignore miterlimit, but set it anyway. Inkscape itself can read it back in
- 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)){
- throw "Fatal programming error in PrintWmf::create_pen at wmiterlimit_set";
- }
- }
- modstyle |= U_PS_JOIN_MITER; }
+ float miterlimit = style->stroke_miterlimit.value; // This is a ratio.
+ if (miterlimit < 1)miterlimit = 1;
+
+ // most WMF readers will ignore miterlimit, but set it anyway. Inkscape itself can read it back in
+ 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)){
+ g_error("Fatal programming error in PrintWmf::create_pen at wmiterlimit_set");
+ }
+ }
+ modstyle |= U_PS_JOIN_MITER;
+ }
else if (style->stroke_linejoin.computed == 1) { modstyle |= U_PS_JOIN_ROUND; }
else { modstyle |= U_PS_JOIN_BEVEL; }
@@ -884,7 +892,7 @@ int PrintWmf::create_pen(SPStyle const *style, const Geom::Affine &transform)
style->stroke_dash.dash )
{
if(!FixPPTDashLine){ // if this is set code elsewhere will break dots/dashes into many smaller lines.
- penstyle = U_PS_DASH;// userstyle not supported apparently, for now map all Inkscape dot/dash to just dash
+ penstyle = U_PS_DASH;// userstyle not supported apparently, for now map all Inkscape dot/dash to just dash
}
}
@@ -893,47 +901,43 @@ 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)){
- throw "Fatal programming error in PrintWmf::create_pen at wcreatepenindirect_set";
+ 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)){
- throw "Fatal programming error in PrintWmf::create_pen at wselectobject_set";
+ g_error("Fatal programming error in PrintWmf::create_pen at wselectobject_set");
}
hpen = pen; // need this later for destroy_pen
return 0;
-// std::cout << "end create_pen" << std::endl;
}
// delete the defined pen object
void PrintWmf::destroy_pen()
{
-// std::cout << "destroy_pen hpen: " << hpen<< std::endl;
char *rec = NULL;
// 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)){
- throw "Fatal programming error in PrintWmf::destroy_pen";
- }
- hpen = 0;
+ rec = wdeleteobject_set(&hpen, wht);
+ if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
+ g_error("Fatal programming error in PrintWmf::destroy_pen");
+ }
+ hpen = 0;
}
// (re)select the null pen
rec = wselectobject_set(hpen_null, wht);
if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
- throw "Fatal programming error in PrintWmf::destroy_pen";
+ g_error("Fatal programming error in PrintWmf::destroy_pen");
}
-// std::cout << "end destroy_pen " << std::endl;
}
unsigned int PrintWmf::bind(Inkscape::Extension::Print * /*mod*/, Geom::Affine const &transform, float /*opacity*/)
{
-// std::cout << "bind " << std::endl;
if (!m_tr_stack.empty()) {
Geom::Affine tr_top = m_tr_stack.top();
m_tr_stack.push(transform * tr_top);
@@ -941,15 +945,12 @@ unsigned int PrintWmf::bind(Inkscape::Extension::Print * /*mod*/, Geom::Affine c
m_tr_stack.push(transform);
}
-// std::cout << "end bind" << std::endl;
return 1;
}
unsigned int PrintWmf::release(Inkscape::Extension::Print * /*mod*/)
{
-// std::cout << "release " << std::endl;
m_tr_stack.pop();
-// std::cout << "end release" << std::endl;
return 1;
}
@@ -982,24 +983,24 @@ U_COLORREF PrintWmf::weight_colors(U_COLORREF c1, U_COLORREF c2, double t){
/* convert from center ellipse to SVGEllipticalArc ellipse
- From:
- http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
- A point (x,y) on the arc can be found by:
+ From:
+ http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
+ A point (x,y) on the arc can be found by:
- {x,y} = {cx,cy} + {cosF,-sinF,sinF,cosF} x {rxcosT,rysinT}
+ {x,y} = {cx,cy} + {cosF,-sinF,sinF,cosF} x {rxcosT,rysinT}
- where
- {cx,cy} is the center of the ellipse
- F is the rotation angle of the X axis of the ellipse from the true X axis
- T is the rotation angle around the ellipse
- {,,,} is the rotation matrix
- rx,ry are the radii of the ellipse's axes
+ where
+ {cx,cy} is the center of the ellipse
+ F is the rotation angle of the X axis of the ellipse from the true X axis
+ T is the rotation angle around the ellipse
+ {,,,} is the rotation matrix
+ rx,ry are the radii of the ellipse's axes
- For SVG parameterization need two points.
- Arbitrarily we can use T=0 and T=pi
- Since the sweep is 180 the flags are always 0:
+ For SVG parameterization need two points.
+ Arbitrarily we can use T=0 and T=pi
+ Since the sweep is 180 the flags are always 0:
- F is in RADIANS, but the SVGEllipticalArc needs degrees!
+ F is in RADIANS, but the SVGEllipticalArc needs degrees!
*/
Geom::PathVector PrintWmf::center_ellipse_as_SVG_PathV(Geom::Point ctr, double rx, double ry, double F){
@@ -1042,8 +1043,9 @@ Geom::PathVector PrintWmf::center_elliptical_ring_as_SVG_PathV(Geom::Point ctr,
char text[512];
sprintf(text," M %f,%f A %f %f %f 0 1 %f %f A %f %f %f 0 1 %f %f z M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z",
- x11,y11, rx1,ry1,degrot,x12,y12, rx1,ry1,degrot,x11,y11,
- x21,y21, rx2,ry2,degrot,x22,y22, rx2,ry2,degrot,x21,y21);
+ x11,y11, rx1,ry1,degrot,x12,y12, rx1,ry1,degrot,x11,y11,
+ x21,y21, rx2,ry2,degrot,x22,y22, rx2,ry2,degrot,x21,y21
+ );
std::vector<Geom::Path> outres = Geom::parse_svg_path(text);
return outres;
@@ -1063,7 +1065,7 @@ Geom::PathVector PrintWmf::center_elliptical_hole_as_SVG_PathV(Geom::Point ctr,
char text[256];
sprintf(text," M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z M 50000,50000 50000,-50000 -50000,-50000 -50000,50000 z",
- x1,y1, rx,ry,F*360./(2.*M_PI),x2,y2, rx,ry,F*360./(2.*M_PI),x1,y1);
+ x1,y1, rx,ry,F*360./(2.*M_PI),x2,y2, rx,ry,F*360./(2.*M_PI),x1,y1);
std::vector<Geom::Path> outres = Geom::parse_svg_path(text);
return outres;
}
@@ -1086,26 +1088,22 @@ Geom::PathVector PrintWmf::rect_cutter(Geom::Point ctr, Geom::Point pos, Geom::P
return outres;
}
-/* Convert from SPWindRule to livarot's FillRule
- This is similar to what sp_selected_path_boolop() does
+/* Convert from SPWindRule to livarot's FillRule
+ This is similar to what sp_selected_path_boolop() does
*/
FillRule PrintWmf::SPWR_to_LVFR(SPWindRule wr){
FillRule fr;
- if(wr == SP_WIND_RULE_EVENODD){
- fr = fill_oddEven;
- }
- else {
- fr = fill_nonZero;
- }
+ if(wr == SP_WIND_RULE_EVENODD){ fr = fill_oddEven; }
+ else { fr = fill_nonZero; }
return fr;
}
-unsigned int PrintWmf::fill(Inkscape::Extension::Print * /*mod*/,
- Geom::PathVector const &pathv, Geom::Affine const & /*transform*/, SPStyle const *style,
- Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/)
+unsigned int PrintWmf::fill(
+ Inkscape::Extension::Print * /*mod*/,
+ Geom::PathVector const &pathv, Geom::Affine const & /*transform*/, SPStyle const *style,
+ Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/)
{
-// std::cout << "fill " << std::endl;
using Geom::X;
using Geom::Y;
@@ -1117,233 +1115,238 @@ unsigned int PrintWmf::fill(Inkscape::Extension::Print * /*mod*/,
fill_transform = tf;
if (create_brush(style, NULL)){
- /*
- Handle gradients. Uses modified livarot as 2geom boolops is currently broken.
- Can handle gradients with multiple stops.
-
- The overlap is needed to avoid antialiasing artifacts when edges are not strictly aligned on pixel boundaries.
- There is an inevitable loss of accuracy saving through an WMF file because of the integer coordinate system.
- Keep the overlap quite large so that loss of accuracy does not remove an overlap.
- */
- destroy_pen(); //this sets the NULL_PEN, otherwise gradient slices may display with boundaries, see longer explanation below
- Geom::Path cutter;
- float rgb[3];
- U_COLORREF wc,c1,c2;
- FillRule frb = SPWR_to_LVFR( (SPWindRule) style->fill_rule.computed);
- double doff,doff_base,doff_range;
- double divisions= 128.0;
- int nstops;
- int istop = 1;
- float opa; // opacity at stop
-
- 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;
- 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;
- c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa );
-
- doff = 0.0;
- doff_base = 0.0;
- doff_range = tg->vector.stops[1].offset; // next or last stop
-
- if(gv.mode==DRAW_RADIAL_GRADIENT){
- Geom::Point xv = gv.p2 - gv.p1; // X' vector
- Geom::Point yv = gv.p3 - gv.p1; // Y' vector
- Geom::Point xuv = Geom::unit_vector(xv); // X' unit vector
- double rx = hypot(xv[X],xv[Y]);
- double ry = hypot(yv[X],yv[Y]);
- double range = fmax(rx,ry); // 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;
-
- /* radial gradient might stop part way through the shape, fill with outer color from there to "infinity".
- Do this first so that outer colored ring will overlay it.
- */
- pathvc = center_elliptical_hole_as_SVG_PathV(gv.p1, rx*(1.0 - overlap/range), ry*(1.0 - overlap/range), asin(xuv[Y]));
- pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_oddEven, frb);
- wc = weight_opacity(c2);
- (void) create_brush(style, &wc);
- print_pathv(pathvr, fill_transform);
-
- 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;
- wc = weight_colors(c1, c2, (doff - doff_base)/(doff_range-doff_base) );
- (void) create_brush(style, &wc);
-
- pathvc = center_elliptical_ring_as_SVG_PathV(gv.p1, rx*start/range, ry*start/range, rx*stop/range, ry*stop/range, asin(xuv[Y]));
-
- 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){
- istop++;
- if(istop >= nstops)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 );
- }
- }
-
- }
- 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);
-
- 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 - doff_base){
- istop++;
- if(istop >= nstops)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 );
- }
- }
- }
- else {
- throw "Fatal programming error in PrintWmf::fill, invalid gradient type detected";
- }
- use_fill = false; // gradients handled, be sure stroke does not use stroke and fill
+ /*
+ Handle gradients. Uses modified livarot as 2geom boolops is currently broken.
+ Can handle gradients with multiple stops.
+
+ The overlap is needed to avoid antialiasing artifacts when edges are not strictly aligned on pixel boundaries.
+ There is an inevitable loss of accuracy saving through an WMF file because of the integer coordinate system.
+ Keep the overlap quite large so that loss of accuracy does not remove an overlap.
+ */
+ destroy_pen(); //this sets the NULL_PEN, otherwise gradient slices may display with boundaries, see longer explanation below
+ Geom::Path cutter;
+ float rgb[3];
+ U_COLORREF wc,c1,c2;
+ FillRule frb = SPWR_to_LVFR( (SPWindRule) style->fill_rule.computed);
+ double doff,doff_base,doff_range;
+ double divisions= 128.0;
+ int nstops;
+ int istop = 1;
+ float opa; // opacity at stop
+
+ 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;
+ 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;
+ c2 = U_RGBA( 255*rgb[0], 255*rgb[1], 255*rgb[2], 255*opa );
+
+ doff = 0.0;
+ doff_base = 0.0;
+ doff_range = tg->vector.stops[1].offset; // next or last stop
+
+ if(gv.mode==DRAW_RADIAL_GRADIENT){
+ Geom::Point xv = gv.p2 - gv.p1; // X' vector
+ Geom::Point yv = gv.p3 - gv.p1; // Y' vector
+ Geom::Point xuv = Geom::unit_vector(xv); // X' unit vector
+ double rx = hypot(xv[X],xv[Y]);
+ double ry = hypot(yv[X],yv[Y]);
+ double range = fmax(rx,ry); // 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;
+
+ /* radial gradient might stop part way through the shape, fill with outer color from there to "infinity".
+ Do this first so that outer colored ring will overlay it.
+ */
+ pathvc = center_elliptical_hole_as_SVG_PathV(gv.p1, rx*(1.0 - overlap/range), ry*(1.0 - overlap/range), asin(xuv[Y]));
+ pathvr = sp_pathvector_boolop(pathvc, pathv, bool_op_inters, (FillRule) fill_oddEven, frb);
+ wc = weight_opacity(c2);
+ (void) create_brush(style, &wc);
+ print_pathv(pathvr, fill_transform);
+
+ 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;
+ wc = weight_colors(c1, c2, (doff - doff_base)/(doff_range-doff_base) );
+ (void) create_brush(style, &wc);
+
+ pathvc = center_elliptical_ring_as_SVG_PathV(gv.p1, rx*start/range, ry*start/range, rx*stop/range, ry*stop/range, asin(xuv[Y]));
+
+ 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){
+ istop++;
+ if(istop >= nstops)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 );
+ }
+ }
+ }
+ 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);
+
+ 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 - doff_base){
+ istop++;
+ if(istop >= nstops)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 );
+ }
+ }
+ }
+ else {
+ g_error("Fatal programming error in PrintWmf::fill, invalid gradient type detected");
+ }
+ use_fill = false; // gradients handled, be sure stroke does not use stroke and fill
}
else {
- /*
- Inkscape was not calling create_pen for objects with no border.
- This was because it never called stroke() (next method).
- PPT, and presumably others, pick whatever they want for the border if it is not specified, so no border can
- become a visible border.
- To avoid this force the pen to NULL_PEN if we can determine that no pen will be needed after the fill.
- */
- if (style->stroke.noneSet || style->stroke_width.computed == 0.0){
- destroy_pen(); //this sets the NULL_PEN
- }
-
- /* postpone fill in case stroke also required AND all stroke paths closed
- Dashes converted to line segments will "open" a closed path.
- */
- bool all_closed = true;
- for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit){
- for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit){
- if (pit->end_default() != pit->end_closed()) { all_closed=false; }
- }
- }
- if (
+ /*
+ Inkscape was not calling create_pen for objects with no border.
+ This was because it never called stroke() (next method).
+ PPT, and presumably others, pick whatever they want for the border if it is not specified, so no border can
+ become a visible border.
+ To avoid this force the pen to NULL_PEN if we can determine that no pen will be needed after the fill.
+ */
+ if (style->stroke.noneSet || style->stroke_width.computed == 0.0){
+ destroy_pen(); //this sets the NULL_PEN
+ }
+
+ /* postpone fill in case stroke also required AND all stroke paths closed
+ Dashes converted to line segments will "open" a closed path.
+ */
+ bool all_closed = true;
+ for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit){
+ for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit){
+ if (pit->end_default() != pit->end_closed()) { all_closed=false; }
+ }
+ }
+ if (
(style->stroke.noneSet || style->stroke_width.computed == 0.0) ||
(style->stroke_dash.n_dash && style->stroke_dash.dash && FixPPTDashLine) ||
!all_closed
- )
- {
- print_pathv(pathv, fill_transform); // do any fills. side effect: clears fill_pathv
- use_fill = false;
- }
+ ){
+ print_pathv(pathv, fill_transform); // do any fills. side effect: clears fill_pathv
+ use_fill = false;
+ }
}
-// std::cout << "end fill" << std::endl;
return 0;
}
-unsigned int PrintWmf::stroke (Inkscape::Extension::Print * /*mod*/,
- Geom::PathVector const &pathv, const Geom::Affine &/*transform*/, const SPStyle *style,
- Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/)
+unsigned int PrintWmf::stroke (
+ Inkscape::Extension::Print * /*mod*/,
+ Geom::PathVector const &pathv, const Geom::Affine &/*transform*/, const SPStyle *style,
+ Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/)
{
-// std::cout << "stroke " << std::endl;
+ char *rec = NULL;
Geom::Affine tf = m_tr_stack.top();
use_stroke = true;
// use_fill was set in ::fill, if it is needed, if not, the null brush is used, it should be already set
+
if (create_pen(style, tf))return 0;
if (style->stroke_dash.n_dash && style->stroke_dash.dash && FixPPTDashLine ){
- // convert the path, gets its complete length, and then make a new path with parameter length instead of t
- Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw; // pathv-> sbasis
- Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw2; // sbasis using arc length parameter
- Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw3; // new (discontinuous) path, composed of dots/dashes
- Geom::Piecewise<Geom::D2<Geom::SBasis> > first_frag; // first fragment, will be appended at end
- int n_dash = style->stroke_dash.n_dash;
- int i=0; //dash index
- double tlength; // length of tmp_pathpw
- double slength=0.0; // start of gragment
- double elength; // end of gragment
- for (unsigned int i=0; i < pathv.size(); i++) {
- tmp_pathpw.concat(pathv[i].toPwSb());
- }
- tlength = length(tmp_pathpw,0.1);
- tmp_pathpw2 = arc_length_parametrization(tmp_pathpw);
-
- // go around the dash array repeatedly until the entire path is consumed (but not beyond).
- while(slength < tlength){
- elength = slength + style->stroke_dash.dash[i++];
- if(elength > tlength)elength = tlength;
- Geom::Piecewise<Geom::D2<Geom::SBasis> > fragment(portion(tmp_pathpw2, slength, elength));
- if(slength){ tmp_pathpw3.concat(fragment); }
- else { first_frag = fragment; }
- slength = elength;
- slength += style->stroke_dash.dash[i++]; // the gap
- if(i>=n_dash)i=0;
- }
- tmp_pathpw3.concat(first_frag); // may merge line around start point
- Geom::PathVector out_pathv = Geom::path_from_piecewise(tmp_pathpw3, 0.01);
- print_pathv(out_pathv, tf);
+ // convert the path, gets its complete length, and then make a new path with parameter length instead of t
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw; // pathv-> sbasis
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw2; // sbasis using arc length parameter
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > tmp_pathpw3; // new (discontinuous) path, composed of dots/dashes
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > first_frag; // first fragment, will be appended at end
+ int n_dash = style->stroke_dash.n_dash;
+ int i=0; //dash index
+ double tlength; // length of tmp_pathpw
+ double slength=0.0; // start of gragment
+ double elength; // end of gragment
+ for (unsigned int i=0; i < pathv.size(); i++) {
+ tmp_pathpw.concat(pathv[i].toPwSb());
+ }
+ tlength = length(tmp_pathpw,0.1);
+ tmp_pathpw2 = arc_length_parametrization(tmp_pathpw);
+
+ // go around the dash array repeatedly until the entire path is consumed (but not beyond).
+ while(slength < tlength){
+ elength = slength + style->stroke_dash.dash[i++];
+ if(elength > tlength)elength = tlength;
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > fragment(portion(tmp_pathpw2, slength, elength));
+ if(slength){ tmp_pathpw3.concat(fragment); }
+ else { first_frag = fragment; }
+ slength = elength;
+ slength += style->stroke_dash.dash[i++]; // the gap
+ if(i>=n_dash)i=0;
+ }
+ tmp_pathpw3.concat(first_frag); // may merge line around start point
+ Geom::PathVector out_pathv = Geom::path_from_piecewise(tmp_pathpw3, 0.01);
+ print_pathv(out_pathv, tf);
}
else {
- print_pathv(pathv, tf);
+ print_pathv(pathv, tf);
}
use_stroke = false;
use_fill = false;
+ 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)){
+ g_error("Fatal programming error in PrintWmf::stroke at U_WMRSETBKMODE_set");
+ }
+ }
-// std::cout << "end stroke " << std::endl;
return 0;
}
@@ -1353,7 +1356,6 @@ unsigned int PrintWmf::stroke (Inkscape::Extension::Print * /*mod*/,
// For other paths it sets a few flags and returns.
bool PrintWmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Affine &transform)
{
-// std::cout << "print_simple_shape " << std::endl <<std::flush;
Geom::PathVector pv = pathv_to_linear( pathv * transform, MAXDISP );
@@ -1388,9 +1390,8 @@ bool PrintWmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff
U_POINT16 *lpPoints = new U_POINT16[moves + lines + curves*3];
int i = 0;
- /**
- * For all Subpaths in the <path>
- */
+ /** For all Subpaths in the <path> */
+
for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit)
{
using Geom::X;
@@ -1408,9 +1409,8 @@ bool PrintWmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff
lpPoints[i].y = y0;
i = i + 1;
- /**
- * For all segments in the subpath
- */
+ /** For all segments in the subpath */
+
for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit)
{
if ( is_straight_curve(*cit) )
@@ -1502,11 +1502,11 @@ bool PrintWmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff
if (polygon) {
if (rectangle){
- U_RECT16 rcl = U_RECT16_set((U_POINT16) {lpPoints[0].x, lpPoints[0].y}, (U_POINT16) {lpPoints[2].x, lpPoints[2].y});
- rec = U_WMRRECTANGLE_set(rcl);
+ U_RECT16 rcl = U_RECT16_set((U_POINT16) {lpPoints[0].x, lpPoints[0].y}, (U_POINT16) {lpPoints[2].x, lpPoints[2].y});
+ rec = U_WMRRECTANGLE_set(rcl);
}
else {
- rec = U_WMRPOLYGON_set(nodes, lpPoints);
+ rec = U_WMRPOLYGON_set(nodes, lpPoints);
}
}
else if (ellipse) {
@@ -1514,7 +1514,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)){
- throw "Fatal programming error in PrintWmf::print_simple_shape at retangle/ellipse/polygon";
+ g_error("Fatal programming error in PrintWmf::print_simple_shape at retangle/ellipse/polygon");
}
done = true;
@@ -1523,93 +1523,89 @@ bool PrintWmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff
delete[] lpPoints;
-// std::cout << "end simple_shape " << std::endl;
return done;
}
/** Some parts based on win32.cpp by Lauris Kaplinski <lauris@kaplinski.com>. Was a part of Inkscape
- in the past (or will be in the future?) Not in current trunk. (4/19/2012)
+ in the past (or will be in the future?) Not in current trunk. (4/19/2012)
- Limitations of this code:
- 1. Images lose their rotation, one corner stays in the same place.
- 2. Transparency is lost on export. (A limitation of the WMF format.)
- 3. Probably messes up if row stride != w*4
- 4. There is still a small memory leak somewhere, possibly in a pixbuf created in a routine
- that calls this one and passes px, but never removes the rest of the pixbuf. The first time
- this is called it leaked 5M (in one test) and each subsequent call leaked around 200K more.
- If this routine is reduced to
- if(1)return(0);
- and called for a single 1280 x 1024 image then the program leaks 11M per call, or roughly the
- size of two bitmaps.
+ Limitations of this code:
+ 1. Images lose their rotation, one corner stays in the same place.
+ 2. Transparency is lost on export. (A limitation of the WMF format.)
+ 3. Probably messes up if row stride != w*4
+ 4. There is still a small memory leak somewhere, possibly in a pixbuf created in a routine
+ that calls this one and passes px, but never removes the rest of the pixbuf. The first time
+ this is called it leaked 5M (in one test) and each subsequent call leaked around 200K more.
+ If this routine is reduced to
+ if(1)return(0);
+ and called for a single 1280 x 1024 image then the program leaks 11M per call, or roughly the
+ size of two bitmaps.
*/
-unsigned int PrintWmf::image(Inkscape::Extension::Print * /* module */, /** not used */
- unsigned char *rgba_px, /** array of pixel values, Gdk::Pixbuf bitmap format */
- unsigned int w, /** width of bitmap */
- unsigned int h, /** height of bitmap */
- unsigned int rs, /** row stride (normally w*4) */
- Geom::Affine const &tf_ignore, /** WRONG affine transform, use the one from m_tr_stack */
- SPStyle const *style) /** provides indirect link to image object */
+unsigned int PrintWmf::image(
+ Inkscape::Extension::Print * /* module */, /** not used */
+ unsigned char *rgba_px, /** array of pixel values, Gdk::Pixbuf bitmap format */
+ unsigned int w, /** width of bitmap */
+ unsigned int h, /** height of bitmap */
+ unsigned int rs, /** row stride (normally w*4) */
+ Geom::Affine const &tf_ignore, /** WRONG affine transform, use the one from m_tr_stack */
+ SPStyle const *style) /** provides indirect link to image object */
{
-// std::cout << "image " << std::endl;
- double x1,y1,dw,dh;
- char *rec = NULL;
- Geom::Affine tf = m_tr_stack.top();
-
- rec = U_WMRSETSTRETCHBLTMODE_set(U_COLORONCOLOR);
- if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
- throw "Fatal programming error in PrintWmf::image at EMRHEADER";
- }
-
- x1= atof(style->object->getAttribute("x"));
- y1= atof(style->object->getAttribute("y"));
- dw= atof(style->object->getAttribute("width"));
- dh= atof(style->object->getAttribute("height"));
- Geom::Point pLL(x1,y1);
- Geom::Point pLL2 = pLL * tf; //location of LL corner in Inkscape coordinates
-
- char *px;
- uint32_t cbPx;
- uint32_t colortype;
- PU_RGBQUAD ct;
- int numCt;
- U_BITMAPINFOHEADER Bmih;
- PU_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);
- Bmi = bitmapinfo_set(Bmih, ct);
-
- U_POINT16 Dest = point16_set(round(pLL2[Geom::X] * PX2WORLD), round(pLL2[Geom::Y] * PX2WORLD));
- U_POINT16 cDest = point16_set(round(dw * PX2WORLD), round(dh * PX2WORLD));
- U_POINT16 Src = point16_set(0,0);
- U_POINT16 cSrc = point16_set(w,h);
- rec = U_WMRSTRETCHDIB_set(
- Dest, //! Destination UL corner in logical units
- cDest, //! Destination W & H in logical units
- Src, //! Source UL corner in logical units
- cSrc, //! Source W & H in logical units
- U_DIB_RGB_COLORS, //! DIBColors Enumeration
- U_SRCCOPY, //! RasterOPeration Enumeration
- Bmi, //! (Optional) bitmapbuffer (U_BITMAPINFO section)
- h*rs, //! size in bytes of px
- px //! (Optional) bitmapbuffer (U_BITMAPINFO section)
- );
- if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
- throw "Fatal programming error in PrintWmf::image at U_WMRSTRETCHDIB_set";
- }
- free(px);
- free(Bmi);
- if(numCt)free(ct);
-
-// std::cout << "end image" << std::endl;
- return 0;
+ double x1,y1,dw,dh;
+ char *rec = NULL;
+ Geom::Affine tf = m_tr_stack.top();
+
+ rec = U_WMRSETSTRETCHBLTMODE_set(U_COLORONCOLOR);
+ if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
+ g_error("Fatal programming error in PrintWmf::image at EMRHEADER");
+ }
+
+ x1= atof(style->object->getAttribute("x"));
+ y1= atof(style->object->getAttribute("y"));
+ dw= atof(style->object->getAttribute("width"));
+ dh= atof(style->object->getAttribute("height"));
+ Geom::Point pLL(x1,y1);
+ Geom::Point pLL2 = pLL * tf; //location of LL corner in Inkscape coordinates
+
+ char *px;
+ uint32_t cbPx;
+ uint32_t colortype;
+ PU_RGBQUAD ct;
+ int numCt;
+ U_BITMAPINFOHEADER Bmih;
+ PU_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);
+ Bmi = bitmapinfo_set(Bmih, ct);
+
+ U_POINT16 Dest = point16_set(round(pLL2[Geom::X] * PX2WORLD), round(pLL2[Geom::Y] * PX2WORLD));
+ U_POINT16 cDest = point16_set(round(dw * PX2WORLD), round(dh * PX2WORLD));
+ U_POINT16 Src = point16_set(0,0);
+ U_POINT16 cSrc = point16_set(w,h);
+ rec = U_WMRSTRETCHDIB_set(
+ Dest, //! Destination UL corner in logical units
+ cDest, //! Destination W & H in logical units
+ Src, //! Source UL corner in logical units
+ cSrc, //! Source W & H in logical units
+ U_DIB_RGB_COLORS, //! DIBColors Enumeration
+ U_SRCCOPY, //! RasterOPeration Enumeration
+ Bmi, //! (Optional) bitmapbuffer (U_BITMAPINFO section)
+ h*rs, //! size in bytes of px
+ px //! (Optional) bitmapbuffer (U_BITMAPINFO section)
+ );
+ if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
+ g_error("Fatal programming error in PrintWmf::image at U_WMRSTRETCHDIB_set");
+ }
+ free(px);
+ free(Bmi);
+ if(numCt)free(ct);
+ return 0;
}
// may also be called with a simple_shape or an empty path, whereupon it just returns without doing anything
unsigned int PrintWmf::print_pathv(Geom::PathVector const &pathv, const Geom::Affine &transform)
{
-// std::cout << "print_pathv " << std::endl << std::flush;
char *rec = NULL;
PU_POINT16 pt16hold, pt16ptr;
uint16_t *n16hold;
@@ -1617,106 +1613,106 @@ unsigned int PrintWmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af
simple_shape = print_simple_shape(pathv, transform);
if (!simple_shape && !pathv.empty()){
- // WMF does not have beziers, need to convert to ONLY linears with something like this:
- Geom::PathVector pv = pathv_to_linear( pathv * transform, MAXDISP );
-
- /**
- * For all Subpaths in the <path>
- */
-
- /* If the path consists entirely of closed subpaths use polypolygon, for all paths. Otherwise use
- polygon or polyline separately on each path. The former allows path delimited donuts and the like, which
- cannot be represented in WMF with polygon or polyline because there is no external way to combine paths
- as there is in EMF or SVG */
- int nPolys=0;
- int totPoints = 0;
- for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit)
- {
- totPoints += 1 + pit->size_default(); // big array, will hold all points, for all polygons. Size_default ignores first point in each path.
- if (pit->end_default() == pit->end_closed()) { nPolys++; }
- else { nPolys=0; break; }
- }
-
- if(nPolys){ // a single polypolygon
- pt16hold = pt16ptr = (PU_POINT16) malloc(totPoints * sizeof(U_POINT16));
- if(!pt16ptr)return(false);
-
- n16hold = n16ptr = (uint16_t *) malloc(nPolys * sizeof(uint16_t));
- if(!n16ptr){ free(pt16hold); return(false); }
-
- for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit)
- {
- using Geom::X;
- using Geom::Y;
+ // WMF does not have beziers, need to convert to ONLY linears with something like this:
+ Geom::PathVector pv = pathv_to_linear( pathv * transform, MAXDISP );
+
+ /** For all Subpaths in the <path> */
+
+ /* If the path consists entirely of closed subpaths use polypolygon, for all paths. Otherwise use
+ polygon or polyline separately on each path. The former allows path delimited donuts and the like, which
+ cannot be represented in WMF with polygon or polyline because there is no external way to combine paths
+ as there is in EMF or SVG.
+ For polygons specify the last point the same as the first. The WMF/EMF manuals say that the
+ reading program SHOULD close the path, which allows a conforming program not to, potentially rendering
+ a closed path as an open one. */
+ int nPolys=0;
+ int totPoints = 0;
+ for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit)
+ {
+ totPoints += 1 + pit->size_default(); // big array, will hold all points, for all polygons. Size_default ignores first point in each path.
+ if (pit->end_default() == pit->end_closed()) { nPolys++; }
+ else { nPolys=0; break; }
+ }
-
- *n16ptr++ = 1 + pit->size_default(); // points in the subpath
- /**
- * For each segment in the subpath
- */
- Geom::Point p1 = pit->initialPoint(); // This point is special, it isn't in the interator
-
- p1[X] = (p1[X] * PX2WORLD);
- p1[Y] = (p1[Y] * PX2WORLD);
- *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y]));
-
- for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_default(); ++cit)
- {
- Geom::Point p1 = cit->finalPoint();
-
- p1[X] = (p1[X] * PX2WORLD);
- p1[Y] = (p1[Y] * PX2WORLD);
- *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y]));
- }
-
- }
- rec = U_WMRPOLYPOLYGON_set(nPolys, n16hold,pt16hold);
- if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
- throw "Fatal programming error in PrintWmf::print_pathv at U_WMRPOLYPOLYGON_set";
- }
- free(pt16hold);
- free(n16hold);
- }
- else { // one or more polyline or polygons (but not all polygons, that would be the preceding case)
- for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit)
- {
- using Geom::X;
- using Geom::Y;
-
- /* Figure out how many points there are, make an array big enough to hold them, and store
- all the points. This is the same for open or closed path. Note that size_default() ignores
- the first point, for some reason.
- */
- int nPoints = 1 + pit->size_default();
- pt16hold = pt16ptr = (PU_POINT16) malloc(nPoints * sizeof(U_POINT16));
- if(!pt16ptr)break;
-
- /**
- * For each segment in the subpath
- */
- Geom::Point p1 = pit->initialPoint(); // This point is special, it isn't in the interator
-
- p1[X] = (p1[X] * PX2WORLD);
- p1[Y] = (p1[Y] * PX2WORLD);
- *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y]));
-
- for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_default(); ++cit)
- {
- Geom::Point p1 = cit->finalPoint();
-
- p1[X] = (p1[X] * PX2WORLD);
- p1[Y] = (p1[Y] * PX2WORLD);
- *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y]));
- }
-
- if (pit->end_default() == pit->end_closed()) { rec = U_WMRPOLYGON_set(nPoints, pt16hold); }
- else { rec = U_WMRPOLYLINE_set(nPoints, pt16hold); }
- if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
- throw "Fatal programming error in PrintWmf::print_pathv at U_WMRPOLYGON/POLYLINE_set";
- }
- free(pt16hold);
- }
- }
+ if(nPolys){ // a single polypolygon
+ pt16hold = pt16ptr = (PU_POINT16) malloc(totPoints * sizeof(U_POINT16));
+ if(!pt16ptr)return(false);
+
+ n16hold = n16ptr = (uint16_t *) malloc(nPolys * sizeof(uint16_t));
+ if(!n16ptr){ free(pt16hold); return(false); }
+
+ for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit)
+ {
+ using Geom::X;
+ using Geom::Y;
+
+
+ *n16ptr++ = 1 + pit->size_default(); // points in the subpath
+
+ /** For each segment in the subpath */
+
+ Geom::Point p1 = pit->initialPoint(); // This point is special, it isn't in the interator
+
+ p1[X] = (p1[X] * PX2WORLD);
+ p1[Y] = (p1[Y] * PX2WORLD);
+ *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y]));
+
+ for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_default(); ++cit)
+ {
+ Geom::Point p1 = cit->finalPoint();
+
+ p1[X] = (p1[X] * PX2WORLD);
+ p1[Y] = (p1[Y] * PX2WORLD);
+ *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y]));
+ }
+
+ }
+ rec = U_WMRPOLYPOLYGON_set(nPolys, n16hold,pt16hold);
+ if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
+ g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRPOLYPOLYGON_set");
+ }
+ free(pt16hold);
+ free(n16hold);
+ }
+ else { // one or more polyline or polygons (but not all polygons, that would be the preceding case)
+ for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit)
+ {
+ using Geom::X;
+ using Geom::Y;
+
+ /* Figure out how many points there are, make an array big enough to hold them, and store
+ all the points. This is the same for open or closed path. Note that size_default() ignores
+ the first point, for some reason.
+ */
+ int nPoints = 1 + pit->size_default();
+ pt16hold = pt16ptr = (PU_POINT16) malloc(nPoints * sizeof(U_POINT16));
+ if(!pt16ptr)break;
+
+ /** For each segment in the subpath */
+
+ Geom::Point p1 = pit->initialPoint(); // This point is special, it isn't in the interator
+
+ p1[X] = (p1[X] * PX2WORLD);
+ p1[Y] = (p1[Y] * PX2WORLD);
+ *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y]));
+
+ for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_default(); ++cit)
+ {
+ Geom::Point p1 = cit->finalPoint();
+
+ p1[X] = (p1[X] * PX2WORLD);
+ p1[Y] = (p1[Y] * PX2WORLD);
+ *pt16ptr++ = point16_set((int32_t) round(p1[X]), (int32_t) round(p1[Y]));
+ }
+
+ if (pit->end_default() == pit->end_closed()) { rec = U_WMRPOLYGON_set(nPoints, pt16hold); }
+ else { rec = U_WMRPOLYLINE_set(nPoints, pt16hold); }
+ if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
+ g_error("Fatal programming error in PrintWmf::print_pathv at U_WMRPOLYGON/POLYLINE_set");
+ }
+ free(pt16hold);
+ }
+ }
}
// WMF has no fill or stroke commands, the draw does it with active pen/brush
@@ -1724,7 +1720,6 @@ unsigned int PrintWmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af
// clean out brush and pen, but only after all parts of the draw complete
if (use_fill){ destroy_brush(); }
if (use_stroke){ destroy_pen(); }
-// std::cout << "end pathv" << std::endl;
return TRUE;
}
@@ -1738,7 +1733,6 @@ bool PrintWmf::textToPath(Inkscape::Extension::Print * ext)
unsigned int PrintWmf::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom::Point const &p,
SPStyle const *const style)
{
-// std::cout << "text " << std::endl;
if (!wt) return 0;
char *rec = NULL;
@@ -1773,35 +1767,36 @@ unsigned int PrintWmf::text(Inkscape::Extension::Print * /*mod*/, char const *te
//Some not funky ones: Symbol and Verdana.
//Without a huge table we cannot catch them all, so just the most common problem ones.
if(FixPPTCharPos){
- switch(newfont){
- case CVTSYM:
- search_short_fflist("Convert To Symbol", &f1, &f2, &f3);
- break;
- case CVTZDG:
- search_short_fflist("Convert To Zapf Dingbats", &f1, &f2, &f3);
- break;
- case CVTWDG:
- search_short_fflist("Convert To Wingdings", &f1, &f2, &f3);
- break;
- default: //also CVTNON
- search_short_fflist(style->text->font_family.value, &f1, &f2, &f3);
- break;
- }
- if(f2 || f3){
- int irem = ((int) round(rot)) % 900 ;
- if(irem <=9 && irem >= -9){
- fix90n=1; //assume vertical
- rot = (double) (((int) round(rot)) - irem);
- rotb = rot*M_PI/1800.0;
- if( abs(rot) == 900.0 ){ fix90n = 2; }
+ switch(newfont){
+ case CVTSYM:
+ search_short_fflist("Convert To Symbol", &f1, &f2, &f3);
+ break;
+ case CVTZDG:
+ search_short_fflist("Convert To Zapf Dingbats", &f1, &f2, &f3);
+ break;
+ case CVTWDG:
+ search_short_fflist("Convert To Wingdings", &f1, &f2, &f3);
+ break;
+ default: //also CVTNON
+ search_short_fflist(style->text->font_family.value, &f1, &f2, &f3);
+ break;
+ }
+ if(f2 || f3){
+ int irem = ((int) round(rot)) % 900 ;
+ if(irem <=9 && irem >= -9){
+ fix90n=1; //assume vertical
+ rot = (double) (((int) round(rot)) - irem);
+ rotb = rot*M_PI/1800.0;
+ if( abs(rot) == 900.0 ){ fix90n = 2; }
+ }
}
- }
}
- /* Note that text font sizes are stored into the WMF as fairly small integers and that limits their precision.
- The WMF output files produced here have been designed so that the integer valued pt sizes
- land right on an integer value in the WMF file, so those are exact. However, something like 18.1 pt will be
- somewhat off, so that when it is read back in it becomes 18.11 pt. (For instance.)
+ /*
+ Note that text font sizes are stored into the WMF as fairly small integers and that limits their precision.
+ The WMF output files produced here have been designed so that the integer valued pt sizes
+ land right on an integer value in the WMF file, so those are exact. However, something like 18.1 pt will be
+ somewhat off, so that when it is read back in it becomes 18.11 pt. (For instance.)
*/
int textheight = round(-style->font_size.computed * PX2WORLD * std::min(tf.expansionX(),tf.expansionY()));
if (!hfont) {
@@ -1809,12 +1804,8 @@ unsigned int PrintWmf::text(Inkscape::Extension::Print * /*mod*/, char const *te
// Get font face name. Use changed font name if unicode mapped to one
// of the special fonts.
char *facename;
- if(!newfont){
- facename = U_Utf8ToLatin1(style->text->font_family.value, 0, NULL);
- }
- else {
- facename = U_Utf8ToLatin1(FontName(newfont), 0, NULL);
- }
+ if(!newfont){ facename = U_Utf8ToLatin1(style->text->font_family.value, 0, NULL); }
+ else { facename = U_Utf8ToLatin1(FontName(newfont), 0, NULL); }
// Scale the text to the minimum stretch. (It tends to stay within bounding rectangles even if
// it was streteched asymmetrically.) Few applications support text from WMF which is scaled
@@ -1839,25 +1830,25 @@ unsigned int PrintWmf::text(Inkscape::Extension::Print * /*mod*/, char const *te
rec = wcreatefontindirect_set( &hfont, wht, puf);
if(!rec || wmf_append((PU_METARECORD)rec, wt, U_REC_FREE)){
- throw "Fatal programming error in PrintWmf::text at wcreatefontindirect_set";
+ 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)){
- throw "Fatal programming error in PrintWmf::text at wselectobject_set";
+ g_error("Fatal programming error in PrintWmf::text at wselectobject_set");
}
float rgb[3];
sp_color_get_rgb_floatv( &style->fill.value.color, rgb );
// only change the text color when it needs to be changed
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)){
- throw "Fatal programming error in PrintWmf::text at U_WMRSETTEXTCOLOR_set";
- }
+ 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)){
+ g_error("Fatal programming error in PrintWmf::text at U_WMRSETTEXTCOLOR_set");
+ }
}
@@ -1881,20 +1872,20 @@ unsigned int PrintWmf::text(Inkscape::Extension::Print * /*mod*/, char const *te
//Conditionally handle compensation for PPT WMF import bug (affects PPT 2003-2010, at least)
if(FixPPTCharPos){
- if(fix90n==1){ //vertical
- dx= 0.0;
- dy= f3 * style->font_size.computed * std::cos( rotb );
- }
- else if(fix90n==2){ //horizontal
- dx= f2 * style->font_size.computed * std::sin( rotb );
- dy= 0.0;
- }
- else {
- dx= f1 * style->font_size.computed * std::sin( rotb );
- dy= f1 * style->font_size.computed * std::cos( rotb );
- }
- p2[Geom::X] += dx;
- p2[Geom::Y] += dy;
+ if(fix90n==1){ //vertical
+ dx= 0.0;
+ dy= f3 * style->font_size.computed * std::cos( rotb );
+ }
+ else if(fix90n==2){ //horizontal
+ dx= f2 * style->font_size.computed * std::sin( rotb );
+ dy= 0.0;
+ }
+ else {
+ dx= f1 * style->font_size.computed * std::sin( rotb );
+ dy= f1 * style->font_size.computed * std::cos( rotb );
+ }
+ p2[Geom::X] += dx;
+ p2[Geom::Y] += dy;
}
p2[Geom::X] = (p2[Geom::X] * PX2WORLD);
@@ -1915,21 +1906,19 @@ 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)){
- throw "Fatal programming error in PrintWmf::text at U_WMREXTTEXTOUTW_set";
+ 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)){
- throw "Fatal programming error in PrintWmf::text at wdeleteobject_set";
+ g_error("Fatal programming error in PrintWmf::text at wdeleteobject_set");
}
-// std::cout << "end text" << std::endl;
return 0;
}
void PrintWmf::init (void)
{
-// std::cout << "init " << std::endl;
read_system_fflist();
/* WMF print */
diff --git a/src/extension/internal/wmf-print.h b/src/extension/internal/wmf-print.h
index 0262a2990..02749c9de 100644
--- a/src/extension/internal/wmf-print.h
+++ b/src/extension/internal/wmf-print.h
@@ -39,8 +39,9 @@ class PrintWmf : public Inkscape::Extension::Implementation::Implementation
U_RECTL rc;
uint32_t hbrush, hpen, hpenOld, hbrush_null, hpen_null;
- uint32_t hmiterlimit, hpolyfillmode; // used to minimize redundant records that set these
- float htextcolor_rgb[3]; // used to minimize redundant records that set these
+ uint32_t hmiterlimit; // used to minimize redundant records that set this
+ uint32_t hpolyfillmode; // used to minimize redundant records that set this
+ float htextcolor_rgb[3]; // used to minimize redundant records that set this
std::stack<Geom::Affine> m_tr_stack;
Geom::PathVector fill_pathv;
@@ -48,6 +49,7 @@ class PrintWmf : public Inkscape::Extension::Implementation::Implementation
bool use_stroke;
bool use_fill;
bool simple_shape;
+ bool usebk;
unsigned int print_pathv (Geom::PathVector const &pathv, const Geom::Affine &transform);
bool print_simple_shape (Geom::PathVector const &pathv, const Geom::Affine &transform);
@@ -101,8 +103,8 @@ protected:
int create_pen(SPStyle const *style, const Geom::Affine &transform);
void destroy_pen();
- void hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor);
- void brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor);
+ void hatch_classify(char *name, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor);
+ void brush_classify(SPObject *parent, int depth, GdkPixbuf **epixbuf, int *hatchType, U_COLORREF *hatchColor, U_COLORREF *bkColor);
void swapRBinRGBA(char *px, int pixels);
U_COLORREF avg_stop_color(SPGradient *gr);