emf-inout.cpp revision 034d7ccaa6acbcd03e37974a2d164706862c32a2
/** @file
* @brief Windows-only Enhanced Metafile input and output.
*/
/* Authors:
* Ulf Erikson <ulferikson@users.sf.net>
* Jon A. Cruz <jon@joncruz.org>
* David Mathog
* Abhishek Sharma
*
* Copyright (C) 2006-2008 Authors
*
* Released under GNU GPL, read the file 'COPYING' for more information
*
* References:
* - How to Create & Play Enhanced Metafiles in Win32
* - INFO: Windows Metafile Functions & Aldus Placeable Metafiles
* - Metafile Functions
* - Metafile Structures
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
//#include <png.h> //This must precede text_reassemble.h or it blows up in pngconf.h when compiling
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <libuemf/symbol_convert.h>
#include "sp-root.h" // even though it is included indirectly by wmf-inout.h
#include "sp-path.h"
#include "print.h"
#include "display/drawing-item.h"
#include "clear-n_.h"
#include "util/units.h" // even though it is included indirectly by wmf-inout.h
#include "inkscape.h" // even though it is included indirectly by wmf-inout.h
#include "emf-print.h"
#include "emf-inout.h"
#define PRINT_EMF "org.inkscape.print.emf"
#ifndef U_PS_JOIN_MASK
#endif
namespace Inkscape {
namespace Extension {
namespace Internal {
{
return;
}
{
return;
}
bool
{
return FALSE;
return TRUE;
}
void
{
unsigned int ret;
doc->ensureUpToDate();
/* Start */
/* fixme: This has to go into module constructor somehow */
/* Create new arena */
/* Print document */
if (ret) {
}
/* Release arena */
/* end */
return;
}
void
{
return;
// reserve FixPPT2 for opacity bug. Currently EMF does not export opacity values
bool new_FixPPTLinGrad = mod->get_param_bool("FixPPTLinGrad"); // allow native rectangular linear gradient
bool new_FixPPTPatternAsHatch = mod->get_param_bool("FixPPTPatternAsHatch"); // force all patterns as standard EMF hatch
TableGen( //possibly regenerate the unicode-convert tables
);
ext->set_param_bool("FixPPTCharPos",new_FixPPTCharPos); // Remember to add any new ones to PrintEmf::init or a mysterious failure will result!
return;
}
/* given the transformation matrix from worldTransform return the scale in the matrix part. Assumes that the
matrix is not used to skew, invert, or make another distorting transformation. */
double scale =
if(scale <= 0.0)scale=1.0; /* something is dreadfully wrong with the matrix, but do not crash over it */
return(scale);
}
/* given the transformation matrix from worldTransform 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)
*/
double scale = current_scale(d);
cxform << "\"matrix(";
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;
}
else {
cxform << "0,0";
}
cxform << ")\"";
}
/* given the transformation matrix from worldTransform return the rotation angle in radians.
counter clocwise from the x axis. */
}
/* Add another 100 blank slots to the hatches array.
*/
}
/* See if the pattern name is already in the list. If it is return its position (1->n, not 1-n-1)
*/
int i;
}
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>.
This is also used to add the path part of the hatches, which they reference with a xlink:href
*/
char tmpcolor[8];
char bkcolor[8];
switch(hatchType){
case U_HS_SOLIDTEXTCLR:
case U_HS_DITHEREDTEXTCLR:
break;
case U_HS_SOLIDBKCLR:
case U_HS_DITHEREDBKCLR:
break;
default:
break;
}
/* 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.*/
d->defs += "\n";
switch(hatchType){
case U_HS_HORIZONTAL:
d->defs += " <path id=\"";
d->defs += "\" d=\"M 0 0 6 0\" style=\"fill:none;stroke:#";
d->defs += "\" />\n";
break;
case U_HS_VERTICAL:
d->defs += " <path id=\"";
d->defs += "\" d=\"M 0 0 0 6\" style=\"fill:none;stroke:#";
d->defs += "\" />\n";
break;
case U_HS_FDIAGONAL:
d->defs += " <line id=\"sub";
d->defs += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
d->defs += "\"/>\n";
break;
case U_HS_BDIAGONAL:
d->defs += " <line id=\"sub";
d->defs += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
d->defs += "\"/>\n";
break;
case U_HS_CROSS:
d->defs += " <path id=\"";
d->defs += "\" d=\"M 0 0 6 0 M 0 0 0 6\" style=\"fill:none;stroke:#";
d->defs += "\" />\n";
break;
case U_HS_DIAGCROSS:
d->defs += " <line id=\"subfd";
d->defs += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
d->defs += "\"/>\n";
d->defs += " <line id=\"subbd";
d->defs += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
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 += "\" d=\"M 0 0 6 0 6 6 0 6 z\" style=\"fill:#";
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 += "\" />\n";
break;
case U_HS_FDIAGONAL:
case U_HS_BDIAGONAL:
refpath += " <use xlink:href=\"#sub";
refpath += "\" />\n";
refpath += " <use xlink:href=\"#sub";
refpath += "\" transform=\"translate(6,0)\" />\n";
refpath += " <use xlink:href=\"#sub";
refpath += "\" transform=\"translate(-6,0)\" />\n";
break;
case U_HS_DIAGCROSS:
refpath += " <use xlink:href=\"#subfd";
refpath += "\" />\n";
refpath += " <use xlink:href=\"#subfd";
refpath += "\" transform=\"translate(6,0)\"/>\n";
refpath += " <use xlink:href=\"#subfd";
refpath += "\" transform=\"translate(-6,0)\"/>\n";
refpath += " <use xlink:href=\"#subbd";
refpath += "\" />\n";
refpath += " <use xlink:href=\"#subbd";
refpath += "\" transform=\"translate(6,0)\"/>\n";
refpath += " <use xlink:href=\"#subbd";
refpath += "\" transform=\"translate(-6,0)\"/>\n";
break;
}
if(!idx){ // add it if not already present
d->defs += "\n";
d->defs += " <pattern id=\"";
d->defs += "\" xlink:href=\"#EMFhbasepattern\">\n";
d->defs += " </pattern>\n";
}
}
else { // bkMode==U_OPAQUE
/* Set up an object in the defs for this background, if there is not one already there */
d->defs += "\n";
d->defs += " <rect id=\"";
d->defs += "\" x=\"0\" y=\"0\" width=\"6\" height=\"6\" fill=\"#";
d->defs += "\" />\n";
}
// this is the pattern, its name will show up in Inkscape's pattern selector
if(!idx){ // add it if not already present
d->defs += "\n";
d->defs += " <pattern id=\"";
d->defs += "\" xlink:href=\"#EMFhbasepattern\">\n";
d->defs += " <use xlink:href=\"#";
d->defs += "\" />\n";
d->defs += " </pattern>\n";
}
}
return(idx-1);
}
/* Add another 100 blank slots to the images array.
*/
}
/* See if the image string is already in the list. If it is return its position (1->n, not 1-n-1)
*/
int i;
}
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>.
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 width, height, colortype, numCt, invert; // if needed these values will be set in get_DIB_params
// next call returns pointers and values, but allocates no memory
if(numCt==2){
}
else { // This record is invalid, nothing more to do here, let caller handle it
return(U_EMR_INVALID);
}
}
if(!DIB_to_RGBA(
px, // DIB pixel array
ct, // DIB color table
numCt, // DIB color table number of entries
&rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free.
width, // Width of pixel array in record
height, // Height of pixel array in record
colortype, // DIB BitCount Enumeration
numCt, // Color table used if not 0
invert // If DIB rows are in opposite order from RGBA rows
)){
toPNG( // Get the image from the RGBA px into mempng
&mempng,
);
}
}
}
}
}
else { // unknown or unsupported image type or failed conversion, insert the common bad image picture
width = 3;
height = 4;
}
if(!idx){ // add it if not already present - we looked at the actual data for comparison
d->defs += "\n";
d->defs += " <image id=\"";
d->defs += "\"\n ";
d->defs += "\n";
d->defs += base64String;
d->defs += "\"\n";
d->defs += " preserveAspectRatio=\"none\"\n";
d->defs += " />\n";
d->defs += "\n";
d->defs += " <pattern id=\"";
d->defs += "_ref\"\n ";
d->defs += "\n patternUnits=\"userSpaceOnUse\"";
d->defs += " >\n";
d->defs += " <use id=\"";
d->defs += "_ign\" ";
d->defs += " xlink:href=\"#";
d->defs += "\" />\n";
d->defs += " ";
d->defs += " </pattern>\n";
}
/* 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 */
if(!idx){
d->defs += "\n";
d->defs += " <pattern\n";
d->defs += " id=\"";
d->defs += "_ref\"\n";
d->defs += " xlink:href=\"#";
d->defs += "_ref\"\n";
d->defs += " patternTransform=";
d->defs += " />\n";
}
}
return(idx-1);
}
/* Add another 100 blank slots to the gradients array.
*/
}
/* See if the gradient name is already in the list. If it is return its position (1->n, not 1-n-1)
*/
int i;
}
return(0);
}
return(uc);
}
/* (Conditionally) add a gradient. If a matching gradient already exists nothing happens. If one
does not exist it is added to the gradients list and also entered into <defs>.
Only call this with H or V gradient, not a triangle.
*/
uint32_t Emf::add_gradient(PEMF_CALLBACK_DATA d, uint32_t gradientType, U_TRIVERTEX tv1, U_TRIVERTEX tv2){
char tmpcolor1[8];
char tmpcolor2[8];
char gradc;
switch(gradientType){
case U_GRADIENT_FILL_RECT_H:
gradc='H';
x2="100";
y2="0";
break;
case U_GRADIENT_FILL_RECT_V:
gradc='V';
x2="0";
y2="100";
break;
default: // this should never happen, but fill these in to avoid compiler warnings
gradc='!';
x2="0";
y2="0";
break;
}
/* Even though the gradient was defined as Horizontal or Vertical if the rectangle is rotated it needs to
be at some other alignment, and that needs gradienttransform. Set the name using the same sort of hack
as for add_image.
*/
if(!idx){ // gradient does not yet exist
stmp << " <linearGradient id=\"";
stmp << "\" x1=\"";
stmp << "\" y1=\"";
stmp << "\" x2=\"";
stmp << "\" y2=\"";
}
else { // LL corner
stmp << "\" y2=\"";
}
stmp << "\" gradientTransform=\"(1,0,0,1,0,0)\"";
stmp << " gradientUnits=\"userSpaceOnUse\"\n";
stmp << ">\n";
stmp << " <stop offset=\"0\" style=\"stop-color:#";
stmp << ";stop-opacity:1\" />\n";
stmp << " <stop offset=\"1\" style=\"stop-color:#";
stmp << ";stop-opacity:1\" />\n";
stmp << " </linearGradient>\n";
}
return(idx-1);
}
/* Add another 100 blank slots to the clips array.
*/
}
/* See if the pattern name is already in the list. If it is return its position (1->n, not 1-n-1)
*/
int i;
}
return(0);
}
/* (Conditionally) add a clip.
If a matching clip already exists nothing happens
If one does exist it is added to the clips list, entered into <defs>.
*/
combined_vect = sp_pathvector_boolop(new_vect, old_vect, (bool_op) op , (FillRule) fill_oddEven, (FillRule) fill_oddEven);
}
else {
}
if(!idx){ // add clip if not already present
tmp_clippath << "\n<clipPath";
tmp_clippath << "\n\tclipPathUnits=\"userSpaceOnUse\" ";
tmp_clippath << " >";
tmp_clippath << "\n\t<path d=\"";
tmp_clippath << combined;
tmp_clippath << "\"";
tmp_clippath << "\n\t/>";
tmp_clippath << "\n</clipPath>";
}
else {
}
}
void
{
// SVGOStringStream tmp_id;
char tmp[1024] = {0};
float fill_rgb[3];
float stroke_rgb[3];
// 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: // invert pattern
break;
case U_SRCINVERT: // treat all of these as black
case U_DSTINVERT:
case U_BLACKNESS:
case U_SRCERASE:
case U_NOTSRCCOPY:
break;
case U_SRCCOPY: // treat all of these as white
case U_NOTSRCERASE:
case U_WHITENESS:
break;
case U_SRCPAINT: // use the existing color
case U_SRCAND:
case U_MERGECOPY:
case U_MERGEPAINT:
case U_PATPAINT:
case U_PATCOPY:
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
// have no way of knowing what color is already on the screen. For those just pass the
// pen color through.
switch(d->dwRop2){
case U_R2_BLACK:
break;
case U_R2_NOTMERGEPEN:
case U_R2_MASKNOTPEN:
break;
case U_R2_NOTCOPYPEN:
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:
break;
default:
break;
}
// tmp_id << "\n\tid=\"" << (d->id++) << "\"";
// d->outsvg += tmp_id.str().c_str();
d->outsvg += "\n\tstyle=\"";
tmp_style << "fill:none;";
} else {
// both of these use the url(#) method
case DRAW_PATTERN:
break;
case DRAW_IMAGE:
break;
case DRAW_LINEAR_GRADIENT:
case DRAW_PAINT:
default: // <-- this should never happen, but just in case...
tmp, 1023,
"fill:#%02x%02x%02x;",
SP_COLOR_F_TO_U(fill_rgb[0]),
);
break;
}
tmp, 1023,
"fill-rule:%s;",
);
tmp_style << "fill-opacity:1;";
// 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(
(
(
(fill_rgb[0]==stroke_rgb[0]) &&
)
)
){
}
}
tmp_style << "stroke:none;";
} else {
// both of these use the url(#) method
case DRAW_PATTERN:
break;
case DRAW_IMAGE:
break;
case DRAW_LINEAR_GRADIENT:
case DRAW_PAINT:
default: // <-- this should never happen, but just in case...
tmp, 1023,
"stroke:#%02x%02x%02x;",
);
break;
}
tmp_style << "stroke-width:" <<
tmp_style << "stroke-linecap:" <<
(
"unknown"
) << ";";
tmp_style << "stroke-linejoin:" <<
(
"unknown"
) << ";";
// Set miter limit if known, even if it is not needed immediately (not miter)
tmp_style << "stroke-miterlimit:" <<
{
tmp_style << "stroke-dasharray:";
if (i)
tmp_style << ",";
}
tmp_style << ";";
tmp_style << "stroke-dashoffset:0;";
} else {
tmp_style << "stroke-dasharray:none;";
}
tmp_style << "stroke-opacity:1;";
}
tmp_style << "\" ";
}
double
{
double tmp;
tmp = ((((double) (px - d->dc[d->level].winorg.x))*scale) + d->dc[d->level].vieworg.x) * d->D2PscaleX;
tmp -= d->ulCornerOutX; //The EMF boundary rectangle can be anywhere, place its upper left corner in the Inkscape upper left corner
return(tmp);
}
double
{
double tmp;
tmp = ((((double) (py - d->dc[d->level].winorg.y))*scale) * d->E2IdirY + d->dc[d->level].vieworg.y) * d->D2PscaleY;
tmp -= d->ulCornerOutY; //The EMF boundary rectangle can be anywhere, place its upper left corner in the Inkscape upper left corner
return(tmp);
}
double
{
double wpx = px * d->dc[d->level].worldTransform.eM11 + py * d->dc[d->level].worldTransform.eM21 + d->dc[d->level].worldTransform.eDx;
double x = _pix_x_to_point(d, wpx);
return x;
}
double
{
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;
}
double
{
double ppx = fabs(px * (d->dc[d->level].ScaleInX ? d->dc[d->level].ScaleInX : 1.0) * d->D2PscaleX * current_scale(d));
return ppx;
}
/* returns "x,y" (without the quotes) in inkscape coordinates for a pair of EMF x,y coordinates
*/
cxform << pix_to_x_point(d,x,y);
cxform << ",";
cxform << pix_to_y_point(d,x,y);
}
void
{
}
if (!pEmr){ return; }
case U_PS_DASH:
case U_PS_DOT:
case U_PS_DASHDOT:
case U_PS_DASHDOTDOT:
{
if (!d->dc[d->level].style.stroke_dasharray.values.empty() && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dasharray.values!=d->dc[d->level-1].style.stroke_dasharray.values)))
}
}
if (penstyle==U_PS_DASHDOTDOT) {
}
break;
}
case U_PS_SOLID:
default:
{
break;
}
}
case U_PS_ENDCAP_FLAT:
}
case U_PS_JOIN_ROUND:
}
} 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;
}
double r, g, b;
}
void
{
if (!pEmr)
return;
case U_PS_USERSTYLE:
{
if (!d->dc[d->level].style.stroke_dasharray.values.empty() && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dasharray.values!=d->dc[d->level-1].style.stroke_dasharray.values)))
// Doing it this way typically results in a pattern that is tiny, better to assume the array
// double dash_length = pix_to_abs_size( d, pEmr->elp.elpStyleEntry[i] );
}
} else {
}
break;
}
case U_PS_DASH:
case U_PS_DOT:
case U_PS_DASHDOT:
case U_PS_DASHDOTDOT:
{
if (!d->dc[d->level].style.stroke_dasharray.values.empty() && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dasharray.values!=d->dc[d->level-1].style.stroke_dasharray.values)))
}
}
if (penstyle==U_PS_DASHDOTDOT) {
}
break;
}
case U_PS_SOLID:
/* includes these for now, some should maybe not be in here
case U_PS_NULL:
case U_PS_INSIDEFRAME:
case U_PS_ALTERNATE:
case U_PS_STYLE_MASK:
*/
default:
{
break;
}
}
case U_PS_ENDCAP_ROUND:
{
break;
}
case U_PS_ENDCAP_SQUARE:
{
break;
}
case U_PS_ENDCAP_FLAT:
default:
{
break;
}
}
case U_PS_JOIN_BEVEL:
{
break;
}
case U_PS_JOIN_MITER:
{
break;
}
case U_PS_JOIN_ROUND:
default:
{
break;
}
}
if (pEmr->elp.elpPenStyle == U_PS_NULL) { // draw nothing, but fill out all the values with something
double r, g, b;
}
else {
} 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;
}
double r, g, b;
}
d->dc[d->level].stroke_recidx = index; // used if the hatch needs to be redone due to bkMode, textmode, etc. changes
}
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);
}
else { // U_BS_PATTERN and anything strange that falls in, stroke is solid textColor
double r, g, b;
}
}
}
void
{
if(iType == U_EMR_CREATEBRUSHINDIRECT){
double r, g, b;
}
d->dc[d->level].fill_recidx = index; // used if the hatch needs to be redone due to bkMode, textmode, etc. changes
}
}
tidx = add_image(d, (void *) pEmr, pEmr->cbBits, pEmr->cbBmi, pEmr->iUsage, pEmr->offBits, pEmr->offBmi);
double r, g, b;
}
else {
}
}
}
}
void
{
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
*/
/* 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. */
d->dc[d->level].style.font_style.value = (pEmr->elfw.elfLogFont.lfItalic ? SP_CSS_FONT_STYLE_ITALIC : SP_CSS_FONT_STYLE_NORMAL);
// malformed EMF with empty filename may exist, ignore font change if encountered
if(ctmp){
if(*ctmp){
}
else { // Malformed EMF might specify an empty font name
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 = round((double)((pEmr->elfw.elfLogFont.lfEscapement + 3600) % 3600)) / 10.0; // use baseline_shift instead of text_transform to avoid overflow
}
void
{
// We are keeping a copy of the EMR rather than just a structure. Currently that is not necessary as the entire
// EMF is read in at once and is stored in a big malloc. However, in past versions it was handled
// reord by record, and we might need to do that again at some point in the future if we start running into EMF
// files too big to fit into memory.
}
}
void
{
delete_object(d, index);
}
}
/* Identify probable Adobe Illustrator produced EMF files, which do strange things with the scaling.
The few so far observed all had this format.
*/
int ret=0;
char *ptr;
if(pEmr->nDescription)string = U_Utf16leToUtf8((uint16_t *)((char *) pEmr + pEmr->offDescription), pEmr->nDescription, NULL);
if(string){
}
return(ret);
}
/**
\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
*/
if(!res)throw "Inkscape fatal memory allocation error - cannot continue";
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
*/
tmp_image << "\n\t <image\n";
uint32_t width, height, colortype, numCt, invert; // if needed these values will be set in get_DIB_params
// next call returns pointers and values, but allocates no memory
}
if(!DIB_to_RGBA(
px, // DIB pixel array
ct, // DIB color table
numCt, // DIB color table number of entries
&rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free.
width, // Width of pixel array
height, // Height of pixel array
colortype, // DIB BitCount Enumeration
numCt, // Color table used if not 0
invert // If DIB rows are in opposite order from RGBA rows
)){
sub_px = RGBA_to_RGBA( // returns either a subset (side effect: frees rgba_px) or NULL (for subset == entire image)
rgba_px, // full pixel array from DIB
width, // Width of pixel array
height, // Height of pixel array
);
toPNG( // Get the image from the RGBA px into mempng
&mempng,
);
}
}
}
}
}
}
else { // unknown or unsupported image type or failed conversion, insert the common bad image picture
}
tmp_image << " preserveAspectRatio=\"none\"\n";
tmp_image << "/> \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
*/
//THis was a callback, just build it into a normal function
{
int OK =1;
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
/* initialize the tsp for text reassembly */
tsp.x = 0.0;
tsp.y = 0.0;
tsp.boff = 0.0; /* offset to baseline from LL corner of bounding rectangle, changes with fs and taln*/
while(OK){
// Uncomment the following to track down toxic records
// std::cout << "record type: " << lpEMFR->iType << " name " << U_emr_names(lpEMFR->iType) << " length: " << lpEMFR->nSize << " offset: " << off <<std::endl;
/* 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;
// 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 != U_EMR_INVALID) && (emr_mask & U_DRAW_TEXT) && d->tri->dirty)){
TR_layout_analyze(d->tri);
TR_layout_2_svg(d->tri);
}
// 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); }
}
/* 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.
*/
}
}
}
// 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)
<< " 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(
(
(
(
((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 path" << *(d->path) << std::endl;
d->outsvg += " <path "; // this is the ONLY place <path should be used!!! One exception, gradientfill.
if(d->drawtype){ // explicit draw type EMR record
output_style(d, d->drawtype);
}
}
else {
}
d->outsvg += "\n\t";
d->outsvg += "\n\td=\""; // this is the ONLY place d=" should be used!!!! One exception, gradientfill.
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;
{
case U_EMR_HEADER:
{
dbg_str << "<!-- U_EMR_HEADER -->\n";
d->outdef += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
if (d->pDesc) {
d->outdef += "<!-- ";
d->outdef += " -->\n";
}
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";
/* inclusive-inclusive, so the size is 1 more than the difference */
/*
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)){
}
/* 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...
*/
}
// Upper left corner, from header rclBounds, in device units, usually both 0, but not always
tmp_outdef <<
// d->defs holds any defines which are read in.
// Init the new emf_obj list elements to null, provided the
// dynamic allocation succeeded.
{
for( int i=0; i < d->n_obj; ++i )
} //if
} else {
}
break;
}
case U_EMR_POLYBEZIER:
{
dbg_str << "<!-- U_EMR_POLYBEZIER -->\n";
uint32_t i,j;
break;
tmp_str <<
"\n\tM " <<
tmp_str << "\n\tC ";
}
}
break;
}
case U_EMR_POLYGON:
{
dbg_str << "<!-- U_EMR_POLYGON -->\n";
uint32_t i;
break;
tmp_str <<
"\n\tM " <<
tmp_str <<
"\n\tL " <<
}
tmp_path << " z";
break;
}
case U_EMR_POLYLINE:
{
dbg_str << "<!-- U_EMR_POLYLINE -->\n";
uint32_t i;
break;
tmp_str <<
"\n\tM " <<
tmp_str <<
"\n\tL " <<
}
break;
}
case U_EMR_POLYBEZIERTO:
{
dbg_str << "<!-- U_EMR_POLYBEZIERTO -->\n";
uint32_t i,j;
tmp_path << "\n\tC ";
tmp_path <<
}
}
break;
}
case U_EMR_POLYLINETO:
{
dbg_str << "<!-- U_EMR_POLYLINETO -->\n";
uint32_t i;
tmp_path <<
"\n\tL " <<
}
break;
}
case U_EMR_POLYPOLYLINE:
case U_EMR_POLYPOLYGON:
{
dbg_str << "<!-- U_EMR_POLYPOLYLINE -->\n";
dbg_str << "<!-- U_EMR_POLYPOLYGON -->\n";
unsigned int n, i, j;
i = 0;
i++;
i++;
}
tmp_str << " z";
tmp_str << " \n";
}
break;
}
case U_EMR_SETWINDOWEXTEX:
{
dbg_str << "<!-- U_EMR_SETWINDOWEXTEX -->\n";
}
}
}
/* scales logical to EMF pixels, transfer a negative sign on Y, if any */
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;
d->E2IdirY = -1.0;
}
}
else {
}
break;
}
case U_EMR_SETWINDOWORGEX:
{
dbg_str << "<!-- U_EMR_SETWINDOWORGEX -->\n";
break;
}
case U_EMR_SETVIEWPORTEXTEX:
{
dbg_str << "<!-- U_EMR_SETVIEWPORTEXTEX -->\n";
}
}
}
/* scales logical to EMF pixels, transfer a negative sign on Y, if any */
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;
d->E2IdirY = -1.0;
}
}
else {
}
break;
}
case U_EMR_SETVIEWPORTORGEX:
{
dbg_str << "<!-- U_EMR_SETVIEWPORTORGEX -->\n";
break;
}
case U_EMR_EOF:
{
dbg_str << "<!-- U_EMR_EOF -->\n";
tmp_outsvg << "</svg>\n";
OK=0;
break;
}
case U_EMR_SETMAPMODE:
{
dbg_str << "<!-- U_EMR_SETMAPMODE -->\n";
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_EMR_SETPOLYFILLMODE:
{
dbg_str << "<!-- U_EMR_SETPOLYFILLMODE -->\n";
break;
}
case U_EMR_SETROP2:
{
dbg_str << "<!-- U_EMR_SETROP2 -->\n";
break;
}
case U_EMR_SETSTRETCHBLTMODE:
{
dbg_str << "<!-- U_EMR_SETSTRETCHBLTMODE -->\n";
break;
}
case U_EMR_SETTEXTALIGN:
{
dbg_str << "<!-- U_EMR_SETTEXTALIGN -->\n";
break;
}
case U_EMR_SETCOLORADJUSTMENT:
dbg_str << "<!-- U_EMR_SETCOLORADJUSTMENT -->\n";
break;
case U_EMR_SETTEXTCOLOR:
{
dbg_str << "<!-- U_EMR_SETTEXTCOLOR -->\n";
}
// not text_dirty, because multicolored complex text is supported in libTERE
break;
}
case U_EMR_SETBKCOLOR:
{
dbg_str << "<!-- U_EMR_SETBKCOLOR -->\n";
}
break;
}
case U_EMR_OFFSETCLIPRGN:
{
dbg_str << "<!-- U_EMR_OFFSETCLIPRGN -->\n";
double ox = pix_to_x_point(d, off.x, off.y) - pix_to_x_point(d, 0, 0); // take into account all active transforms
}
break;
}
case U_EMR_MOVETOEX:
{
dbg_str << "<!-- U_EMR_MOVETOEX -->\n";
tmp_path <<
break;
}
case U_EMR_EXCLUDECLIPRECT:
{
dbg_str << "<!-- U_EMR_EXCLUDECLIPRECT -->\n";
//outer rect, clockwise
tmp_path << "z ";
//inner rect, counterclockwise (sign of Y is reversed)
tmp_path << "z";
d->path = "";
d->drawtype = 0;
break;
}
case U_EMR_INTERSECTCLIPRECT:
{
dbg_str << "<!-- U_EMR_INTERSECTCLIPRECT -->\n";
tmp_path << "z";
d->path = "";
d->drawtype = 0;
break;
}
case U_EMR_SAVEDC:
dbg_str << "<!-- U_EMR_SAVEDC -->\n";
if (d->level < EMF_MAX_DC) {
d->dc[d->level + 1].font_name = strdup(d->dc[d->level].font_name); // or memory access problems because font name pointer duplicated
}
}
break;
case U_EMR_RESTOREDC:
{
dbg_str << "<!-- U_EMR_RESTOREDC -->\n";
}
else {
}
if (!d->dc[old_level].style.stroke_dasharray.values.empty() && (old_level==0 || (old_level>0 && d->dc[old_level].style.stroke_dasharray.values!=d->dc[old_level-1].style.stroke_dasharray.values))){
}
}
old_level--;
}
break;
}
case U_EMR_SETWORLDTRANSFORM:
{
dbg_str << "<!-- U_EMR_SETWORLDTRANSFORM -->\n";
break;
}
{
dbg_str << "<!-- U_EMR_MODIFYWORLDTRANSFORM -->\n";
{
case U_MWT_IDENTITY:
break;
case U_MWT_LEFTMULTIPLY:
{
// d->dc[d->level].worldTransform = pEmr->xform * worldTransform;
float a13 = 0.0;
float a23 = 0.0;
float a33 = 1.0;
//float b13 = 0.0;
//float b23 = 0.0;
//float b33 = 1.0;
//float c13 = a11*b13 + a12*b23 + a13*b33;;
//float c23 = a21*b13 + a22*b23 + a23*b33;;
//float c33 = a31*b13 + a32*b23 + a33*b33;;
break;
}
case U_MWT_RIGHTMULTIPLY:
{
// d->dc[d->level].worldTransform = worldTransform * pEmr->xform;
float a13 = 0.0;
float a23 = 0.0;
float a33 = 1.0;
//float b13 = 0.0;
//float b23 = 0.0;
//float b33 = 1.0;
//float c13 = a11*b13 + a12*b23 + a13*b33;;
//float c23 = a21*b13 + a22*b23 + a23*b33;;
//float c33 = a31*b13 + a32*b23 + a33*b33;;
break;
}
// case MWT_SET:
default:
break;
}
break;
}
case U_EMR_SELECTOBJECT:
{
dbg_str << "<!-- U_EMR_SELECTOBJECT -->\n";
if (index & U_STOCK_OBJECT) {
switch (index) {
case U_NULL_BRUSH:
break;
case U_BLACK_BRUSH:
case U_DKGRAY_BRUSH:
case U_GRAY_BRUSH:
case U_LTGRAY_BRUSH:
case U_WHITE_BRUSH:
{
float val = 0;
switch (index) {
case U_BLACK_BRUSH:
break;
case U_DKGRAY_BRUSH:
break;
case U_GRAY_BRUSH:
break;
case U_LTGRAY_BRUSH:
break;
case U_WHITE_BRUSH:
break;
}
break;
}
case U_NULL_PEN:
break;
case U_BLACK_PEN:
case U_WHITE_PEN:
{
break;
}
}
} else {
{
case U_EMR_CREATEPEN:
select_pen(d, index);
break;
case U_EMR_CREATEMONOBRUSH:
select_brush(d, index);
break;
case U_EMR_EXTCREATEPEN:
select_extpen(d, index);
break;
select_font(d, index);
break;
}
}
}
break;
}
case U_EMR_CREATEPEN:
{
dbg_str << "<!-- U_EMR_CREATEPEN -->\n";
break;
}
{
dbg_str << "<!-- U_EMR_CREATEBRUSHINDIRECT -->\n";
break;
}
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";
break;
case U_EMR_ELLIPSE:
{
dbg_str << "<!-- U_EMR_ELLIPSE -->\n";
double cx = pix_to_x_point( d, (rclBox.left + rclBox.right)/2.0, (rclBox.bottom + rclBox.top)/2.0 );
double cy = pix_to_y_point( d, (rclBox.left + rclBox.right)/2.0, (rclBox.bottom + rclBox.top)/2.0 );
d->outsvg += " <ellipse ";
d->outsvg += "\n\t";
d->outsvg += "/> \n";
d->path = "";
break;
}
case U_EMR_RECTANGLE:
{
dbg_str << "<!-- U_EMR_RECTANGLE -->\n";
tmp_rectangle << "\n\tz";
break;
}
case U_EMR_ROUNDRECT:
{
dbg_str << "<!-- U_EMR_ROUNDRECT -->\n";
double f1 = 1.0 - f;
tmp_rectangle << "\n"
<< " M "
<< "\n";
tmp_rectangle << " C "
<< " "
<< " "
<< "\n";
tmp_rectangle << " L "
<< "\n";
tmp_rectangle << " C "
<< " "
<< " "
<< "\n";
tmp_rectangle << " L "
<< "\n";
tmp_rectangle << " C "
<< " "
<< " "
<< "\n";
tmp_rectangle << " L "
<< "\n";
tmp_rectangle << " C "
<< " "
<< " "
<< "\n";
tmp_rectangle << " z\n";
break;
}
case U_EMR_ARC:
{
dbg_str << "<!-- U_EMR_ARC -->\n";
int f1;
if(!stat){
tmp_path << " ";
tmp_path << " ";
}
else {
dbg_str << "<!-- ARC record is invalid -->\n";
}
break;
}
case U_EMR_CHORD:
{
dbg_str << "<!-- U_EMR_CHORD -->\n";
int f1;
tmp_path << " ";
tmp_path << " ";
tmp_path << " z ";
}
else {
dbg_str << "<!-- CHORD record is invalid -->\n";
}
break;
}
case U_EMR_PIE:
{
dbg_str << "<!-- U_EMR_PIE -->\n";
int f1;
tmp_path << " ";
tmp_path << " ";
tmp_path << " z ";
}
else {
dbg_str << "<!-- PIE record is invalid -->\n";
}
break;
}
case U_EMR_LINETO:
{
dbg_str << "<!-- U_EMR_LINETO -->\n";
tmp_path <<
break;
}
case U_EMR_ARCTO:
{
dbg_str << "<!-- U_EMR_ARCTO -->\n";
int f1;
// draw a line from current position to start, arc from there
tmp_path << " ";
tmp_path << " ";
}
else {
dbg_str << "<!-- ARCTO record is invalid -->\n";
}
break;
}
case U_EMR_SETARCDIRECTION:
{
dbg_str << "<!-- U_EMR_SETARCDIRECTION -->\n";
}
break;
}
case U_EMR_SETMITERLIMIT:
{
dbg_str << "<!-- U_EMR_SETMITERLIMIT -->\n";
//The function takes a float but saves a 32 bit int in the U_EMR_SETMITERLIMIT record.
break;
}
case U_EMR_BEGINPATH:
{
dbg_str << "<!-- U_EMR_BEGINPATH -->\n";
// The next line should never be needed, should have been handled before main switch
// qualifier added because EMF's encountered where moveto preceded beginpath followed by lineto
if(d->mask & U_DRAW_VISIBLE){
d->path = "";
}
break;
}
case U_EMR_ENDPATH:
{
dbg_str << "<!-- U_EMR_ENDPATH -->\n";
d->mask &= (0xFFFFFFFF - U_DRAW_ONLYTO); // clear the OnlyTo bit (it might not have been set), prevents any further path extension
break;
}
case U_EMR_CLOSEFIGURE:
{
dbg_str << "<!-- U_EMR_CLOSEFIGURE -->\n";
// EMF may contain multiple closefigures on one path
tmp_path << "\n\tz";
d->mask |= U_DRAW_CLOSED;
break;
}
case U_EMR_FILLPATH:
{
dbg_str << "<!-- U_EMR_FILLPATH -->\n";
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->drawtype = U_EMR_FILLPATH;
}
break;
}
case U_EMR_STROKEANDFILLPATH:
{
dbg_str << "<!-- U_EMR_STROKEANDFILLPATH -->\n";
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;
}
}
break;
}
case U_EMR_STROKEPATH:
{
dbg_str << "<!-- U_EMR_STROKEPATH -->\n";
d->drawtype = U_EMR_STROKEPATH;
}
break;
}
case U_EMR_SELECTCLIPPATH:
{
dbg_str << "<!-- U_EMR_SELECTCLIPPATH -->\n";
d->path = "";
d->drawtype = 0;
break;
}
case U_EMR_ABORTPATH:
{
dbg_str << "<!-- U_EMR_ABORTPATH -->\n";
d->path = "";
d->drawtype = 0;
break;
}
case U_EMR_COMMENT:
{
dbg_str << "<!-- U_EMR_COMMENT -->\n";
if ( *szTxt) {
}
szTxt++;
}
}
tmp_outsvg << " <!-- \"";
tmp_outsvg << "\" -->\n";
}
break;
}
case U_EMR_EXTSELECTCLIPRGN:
{
dbg_str << "<!-- U_EMR_EXTSELECTCLIPRGN -->\n";
// the only mode we implement - this clears the clipping region
}
break;
}
case U_EMR_BITBLT:
{
dbg_str << "<!-- U_EMR_BITBLT -->\n";
// Treat all nonImage bitblts as a rectangular write. Definitely not correct, but at
// least it leaves objects where the operations should have been.
// should be an application of a DIBPATTERNBRUSHPT, use a solid color instead
if(pEmr->dwRop == U_NOOP)break; /* GDI applications apparently often end with this as a sort of flush(), nothing should be drawn */
tmp_rectangle << "\n\tz";
d->mask |= U_DRAW_CLOSED; // Bitblit is not really open or closed, but we need it to fill, and this is the flag for that
}
else {
//source position within the bitmap, in pixels
int sw = 0; // extract all of the image
int sh = 0;
}
break;
}
case U_EMR_STRETCHBLT:
{
dbg_str << "<!-- U_EMR_STRETCHBLT -->\n";
// Always grab image, ignore modes.
//source position within the bitmap, in pixels
}
break;
}
case U_EMR_MASKBLT:
{
dbg_str << "<!-- U_EMR_MASKBLT -->\n";
// Always grab image, ignore masks and modes.
int sw = 0; // extract all of the image
int sh = 0;
}
break;
}
case U_EMR_STRETCHDIBITS:
{
// Some applications use multiple EMF operations, including multiple STRETCHDIBITS to create
// images with transparent regions. PowerPoint does this with rotated images, for instance.
// Parsing all of that to derive a single resultant image object is left for a later version
// of this code. In the meantime, every STRETCHDIBITS goes directly to an image. The Inkscape
// user can sort out transparency later using Gimp, if need be.
dbg_str << "<!-- U_EMR_STRETCHDIBITS -->\n";
break;
}
{
dbg_str << "<!-- U_EMR_EXTCREATEFONTINDIRECTW -->\n";
break;
}
case U_EMR_EXTTEXTOUTA:
case U_EMR_EXTTEXTOUTW:
case U_EMR_SMALLTEXTOUT:
{
dbg_str << "<!-- U_EMR_EXTTEXTOUTA/W -->\n";
int roff = sizeof(U_EMRSMALLTEXTOUT); //offset to the start of the variable fields, only used with U_EMR_SMALLTEXTOUT
int cChars;
}
else {
cChars = 0;
}
}
/* Rotation issues are handled entirely in libTERE now */
/* 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!
*/
if(!dup_wt)dup_wt = U_Latin1ToUtf32le((char *) pEmr + pEmr->emrtext.offString, pEmr->emrtext.nChars, NULL);
}
dup_wt = U_Utf16leToUtf32le((uint16_t *)((char *) pEmr + pEmr->emrtext.offString), pEmr->emrtext.nChars, NULL);
}
else { // U_EMR_SMALLTEXTOUT
}
else {
}
}
msdepua(dup_wt); //convert everything in Microsoft's private use area. For Symbol, Wingdings, Dingbats
}
char *ansi_text;
// 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 (ansi_text) {
tsp.y = y*0.8;
case SP_CSS_FONT_STYLE_ITALIC:
default:
case SP_CSS_FONT_STYLE_NORMAL:
}
}
// EMF only supports two types of text decoration
// EMF textalignment is a bit strange: 0x6 is center, 0x2 is right, 0x0 is left, the value 0x4 is also drawn left
ALIRIGHT);
ALITOP));
// language direction can be encoded two ways, U_TA_RTLREADING is preferred
if( (fOptions & U_ETO_RTLREADING) || (d->dc[d->level].textAlign & U_TA_RTLREADING) ){ tsp.ldir = LDIR_RL; }
tsp.ori = d->dc[d->level].style.baseline_shift.value; // For now orientation is always the same as escapement
tsp.string = (uint8_t *) U_strdup(escaped_text); // this will be free'd much later at a trinfo_clear().
// when font name includes narrow it may not be set to "condensed". Narrow fonts do not work well anyway though
// as the metrics from fontconfig may not match, or the font may not be present.
TR_layout_analyze(d->tri);
TR_layout_2_svg(d->tri);
}
}
break;
}
case U_EMR_POLYBEZIER16:
{
dbg_str << "<!-- U_EMR_POLYBEZIER16 -->\n";
uint32_t i,j;
break;
tmp_str << "\n\tC ";
}
}
break;
}
case U_EMR_POLYGON16:
{
dbg_str << "<!-- U_EMR_POLYGON16 -->\n";
unsigned int i;
unsigned int first = 0;
// skip the first point?
}
tmp_path << "\n\tz";
d->mask |= U_DRAW_CLOSED;
break;
}
case U_EMR_POLYLINE16:
{
dbg_str << "<!-- U_EMR_POLYLINE16 -->\n";
uint32_t i;
break;
}
break;
}
case U_EMR_POLYBEZIERTO16:
{
dbg_str << "<!-- U_EMR_POLYBEZIERTO16 -->\n";
uint32_t i,j;
tmp_path << "\n\tC ";
}
}
break;
}
case U_EMR_POLYLINETO16:
{
dbg_str << "<!-- U_EMR_POLYLINETO16 -->\n";
uint32_t i;
}
break;
}
case U_EMR_POLYPOLYLINE16:
case U_EMR_POLYPOLYGON16:
{
dbg_str << "<!-- U_EMR_POLYPOLYLINE16 -->\n";
dbg_str << "<!-- U_EMR_POLYPOLYGON16 -->\n";
unsigned int n, i, j;
i = 0;
i++;
i++;
}
tmp_str << " z";
tmp_str << " \n";
}
break;
}
case U_EMR_CREATEMONOBRUSH:
{
dbg_str << "<!-- U_EMR_CREATEDIBPATTERNBRUSHPT -->\n";
break;
}
{
dbg_str << "<!-- U_EMR_CREATEDIBPATTERNBRUSHPT -->\n";
break;
}
case U_EMR_EXTCREATEPEN:
{
dbg_str << "<!-- U_EMR_EXTCREATEPEN -->\n";
break;
}
case U_EMR_SETICMMODE:
{
dbg_str << "<!-- U_EMR_SETICMMODE -->\n";
break;
}
// U_EMR_SMALLTEXTOUT is handled with U_EMR_EXTTEXTOUTA/W above
case U_EMR_GRADIENTFILL:
{
/* Gradient fill is doable for rectangles because those correspond to linear gradients. However,
the general case for the triangle fill, with a different color in each corner of the triangle,
has no SVG equivalent and cannot be easily emulated with SVG gradients. So the linear gradient
is implemented, and the triangle fill just paints with the color of the first corner.
This record can hold a series of gradients so we are forced to add path elements directly here,
it cannot wait for the top of the main loop. Any existing path is erased.
*/
dbg_str << "<!-- U_EMR_GRADIENTFILL -->\n";
){
int i,fill_idx;
U_GRADIENT4 *rcs = (U_GRADIENT4 *)(((char *)lpEMFR) + sizeof(U_EMRGRADIENTFILL) + sizeof(U_TRIVERTEX)*nV);
for(i=0;i<nG;i++){
tmp_rectangle << "\n<path d=\"";
tmp_rectangle << "\n\tM " << pix_to_xy( d, tv[rcs[i].UpperLeft ].x , tv[rcs[i].UpperLeft ].y ) << " ";
tmp_rectangle << "\n\tL " << pix_to_xy( d, tv[rcs[i].LowerRight].x , tv[rcs[i].UpperLeft ].y ) << " ";
tmp_rectangle << "\n\tL " << pix_to_xy( d, tv[rcs[i].LowerRight].x , tv[rcs[i].LowerRight].y ) << " ";
tmp_rectangle << "\n\tL " << pix_to_xy( d, tv[rcs[i].UpperLeft ].x , tv[rcs[i].LowerRight].y ) << " ";
tmp_rectangle << "\n\tz\"";
tmp_rectangle << "\n\tstyle=\"stroke:none;fill:url(#";
tmp_rectangle << ");\"\n/>\n";
}
}
char tmpcolor[8];
int i;
U_GRADIENT3 *tris = (U_GRADIENT3 *)(((char *)lpEMFR) + sizeof(U_EMRGRADIENTFILL) + sizeof(U_TRIVERTEX)*nV);
for(i=0;i<nG;i++){
tmp_triangle << "\n<path d=\"";
tmp_triangle << "\n\tz\"";
tmp_triangle << "\n\tstyle=\"stroke:none;fill:#";
tmp_triangle << tmpcolor;
tmp_triangle << ";\"\n/>\n";
}
}
d->path = "";
// if it is anything else the record is bogus, so ignore it
break;
}
default:
dbg_str << "<!-- U_EMR_??? -->\n";
break;
} //end of switch
// When testing, uncomment the following to place a comment for each processed EMR record in the SVG
// d->outsvg += dbg_str.str().c_str();
} //end of while
// When testing, uncomment the following to show the final SVG derived from the EMF
// 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;
}
}
}
{
return 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";
char *contents;
// set up the text reassembly system
// std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl;
SPDocument *doc = SPDocument::createNewDocFromMem(d.outsvg.c_str(), strlen(d.outsvg.c_str()), TRUE);
if (d.emf_obj) {
int i;
for (i=0; i<d.n_obj; i++)
delete_object(&d, i);
delete[] d.emf_obj;
}
for(int i=0; i<=d.level;i++){
}
return doc;
}
void
{
/* EMF in */
"<id>org.inkscape.input.emf</id>\n"
"<input>\n"
"<extension>.emf</extension>\n"
"<output_extension>org.inkscape.output.emf</output_extension>\n"
"</input>\n"
"</inkscape-extension>", new Emf());
/* EMF out */
"<id>org.inkscape.output.emf</id>\n"
"<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">true</param>\n"
"<param name=\"TnrToSymbol\" gui-text=\"" N_("Map Unicode to Symbol font") "\" type=\"boolean\">true</param>\n"
"<param name=\"TnrToWingdings\" gui-text=\"" N_("Map Unicode to Wingdings") "\" type=\"boolean\">true</param>\n"
"<param name=\"TnrToZapfDingbats\" gui-text=\"" N_("Map Unicode to Zapf Dingbats") "\" type=\"boolean\">true</param>\n"
"<param name=\"UsePUA\" gui-text=\"" N_("Use MS Unicode PUA (0xF020-0xF0FF) for converted characters") "\" type=\"boolean\">false</param>\n"
"<param name=\"FixPPTCharPos\" gui-text=\"" N_("Compensate for PPT font bug") "\" type=\"boolean\">false</param>\n"
"<param name=\"FixPPTDashLine\" gui-text=\"" N_("Convert dashed/dotted lines to single lines") "\" type=\"boolean\">false</param>\n"
"<param name=\"FixPPTGrad2Polys\" gui-text=\"" N_("Convert gradients to colored polygon series") "\" type=\"boolean\">false</param>\n"
"<param name=\"FixPPTLinGrad\" gui-text=\"" N_("Use native rectangular linear gradients") "\" type=\"boolean\">false</param>\n"
"<param name=\"FixPPTPatternAsHatch\" gui-text=\"" N_("Map all fill patterns to standard EMF hatches") "\" type=\"boolean\">false</param>\n"
"<param name=\"FixImageRot\" gui-text=\"" N_("Ignore image rotations") "\" type=\"boolean\">false</param>\n"
"<output>\n"
"<extension>.emf</extension>\n"
"</output>\n"
"</inkscape-extension>", new Emf());
return;
}
} } } /* namespace Inkscape, Extension, Implementation */
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :