diff --git a/src/extension/internal/pdfinput/svg-builder.cpp b/src/extension/internal/pdfinput/svg-builder.cpp
index 14f9c610280b5b911a9ff53be29ce58a05c41b5c..5a3015aef60ba07ace31c00030ecb870752459cf 100644 (file)
#include "unit-constants.h"
#include "io/stringstream.h"
#include "io/base64stream.h"
-#include "libnr/nr-matrix-ops.h"
+#include "display/nr-filter-utils.h"
#include "libnr/nr-macros.h"
#include "libnrtype/font-instance.h"
_container = _root = _doc->rroot;
_root->setAttribute("xml:space", "preserve");
_init();
+
+ // Set default preference settings
+ _preferences = _xml_doc->createElement("svgbuilder:prefs");
+ _preferences->setAttribute("embedImages", "1");
}
SvgBuilder::SvgBuilder(SvgBuilder *parent, Inkscape::XML::Node *root) {
_docname = parent->_docname;
_xref = parent->_xref;
_xml_doc = parent->_xml_doc;
+ _preferences = parent->_preferences;
_container = this->_root = root;
_init();
}
static gchar tmp[1023] = {0};
snprintf(tmp, 1023,
"#%02x%02x%02x",
- CLAMP(SP_COLOR_F_TO_U(r), 0, 255),
- CLAMP(SP_COLOR_F_TO_U(g), 0, 255),
- CLAMP(SP_COLOR_F_TO_U(b), 0, 255));
+ NR::clamp(SP_COLOR_F_TO_U(r)),
+ NR::clamp(SP_COLOR_F_TO_U(g)),
+ NR::clamp(SP_COLOR_F_TO_U(b)));
return (gchar *)&tmp;
}
}
static void svgSetTransform(Inkscape::XML::Node *node, double c0, double c1,
- double c2, double c3, double c4, double c5) {
- NR::Matrix matrix(c0, c1, c2, c3, c4, c5);
+ double c2, double c3, double c4, double c5) {
+ Geom::Matrix matrix(c0, c1, c2, c3, c4, c5);
gchar *transform_text = sp_svg_transform_write(matrix);
node->setAttribute("transform", transform_text);
g_free(transform_text);
}
-static void svgSetTransform(Inkscape::XML::Node *node, double *transform) {
- svgSetTransform(node, transform[0], transform[1], transform[2], transform[3],
- transform[4], transform[5]);
-}
-
/**
* \brief Generates a SVG path string from poppler's data structure
*/
@@ -468,6 +468,27 @@ void SvgBuilder::addShadedFill(GfxShading *shading, double *matrix, GfxPath *pat
_container->appendChild(path_node);
Inkscape::GC::release(path_node);
+
+ // Remove the clipping path emitted before the 'sh' operator
+ int up_walk = 0;
+ Inkscape::XML::Node *node = _container->parent();
+ while( node && node->childCount() == 1 && up_walk < 3 ) {
+ gchar const *clip_path_url = node->attribute("clip-path");
+ if (clip_path_url) {
+ // Obtain clipping path's id from the URL
+ gchar clip_path_id[32];
+ strncpy(clip_path_id, clip_path_url + 5, strlen(clip_path_url) - 6);
+ SPObject *clip_obj = _doc->getObjectById(clip_path_id);
+ if (clip_obj) {
+ clip_obj->deleteObject();
+ node->setAttribute("clip-path", NULL);
+ TRACE(("removed clipping path: %s\n", clip_path_id));
+ }
+ break;
+ }
+ node = node->parent();
+ up_walk++;
+ }
}
/**
* \return true on success; false on invalid transformation
*/
bool SvgBuilder::getTransform(double *transform) {
- NR::Matrix svd;
+ Geom::Matrix svd;
gchar const *tr = _container->attribute("transform");
bool valid = sp_svg_transform_read(tr, &svd);
if (valid) {
void SvgBuilder::setTransform(double c0, double c1, double c2, double c3,
double c4, double c5) {
+ // Avoid transforming a group with an already set clip-path
+ if ( _container->attribute("clip-path") != NULL ) {
+ pushGroup();
+ }
TRACE(("setTransform: %f %f %f %f %f %f\n", c0, c1, c2, c3, c4, c5));
svgSetTransform(_container, c0, c1, c2, c3, c4, c5);
}
-void SvgBuilder::setTransform(double *transform) {
+void SvgBuilder::setTransform(double const *transform) {
setTransform(transform[0], transform[1], transform[2], transform[3],
transform[4], transform[5]);
}
Inkscape::XML::Node *pattern_node = _xml_doc->createElement("svg:pattern");
// Set pattern transform matrix
double *p2u = tiling_pattern->getMatrix();
- NR::Matrix pat_matrix(p2u[0], p2u[1], p2u[2], p2u[3], p2u[4], p2u[5]);
+ Geom::Matrix pat_matrix(p2u[0], p2u[1], p2u[2], p2u[3], p2u[4], p2u[5]);
gchar *transform_text = sp_svg_transform_write(pat_matrix);
pattern_node->setAttribute("patternTransform", transform_text);
g_free(transform_text);
@@ -691,10 +716,10 @@ gchar *SvgBuilder::_createGradient(GfxShading *shading, double *matrix, bool for
gradient->setAttribute("gradientUnits", "userSpaceOnUse");
// If needed, flip the gradient transform around the y axis
if (matrix) {
- NR::Matrix pat_matrix(matrix[0], matrix[1], matrix[2], matrix[3],
+ Geom::Matrix pat_matrix(matrix[0], matrix[1], matrix[2], matrix[3],
matrix[4], matrix[5]);
if ( !for_shading && _is_top_level ) {
- NR::Matrix flip(1.0, 0.0, 0.0, -1.0, 0.0, _height * PT_PER_PX);
+ Geom::Matrix flip(1.0, 0.0, 0.0, -1.0, 0.0, _height * PT_PER_PX);
pat_matrix *= flip;
}
gchar *transform_text = sp_svg_transform_write(pat_matrix);
@@ -733,7 +758,7 @@ void SvgBuilder::_addStopToGradient(Inkscape::XML::Node *gradient, double offset
double gray = (double)color->r / 65535.0;
gray = CLAMP(gray, 0.0, 1.0);
os_opacity << gray;
- color_text = "#ffffff";
+ color_text = (char*) "#ffffff";
} else {
os_opacity << opacity;
color_text = svgConvertGfxRGB(color);
* This array holds info about translating font weight names to more or less CSS equivalents
*/
static char *font_weight_translator[][2] = {
- {"bold", "bold"},
- {"light", "300"},
- {"black", "900"},
- {"heavy", "900"},
- {"ultrabold", "800"},
- {"extrabold", "800"},
- {"demibold", "600"},
- {"semibold", "600"},
- {"medium", "500"},
- {"book", "normal"},
- {"regular", "normal"},
- {"roman", "normal"},
- {"normal", "normal"},
- {"ultralight", "200"},
- {"extralight", "200"},
- {"thin", "100"}
+ {(char*) "bold", (char*) "bold"},
+ {(char*) "light", (char*) "300"},
+ {(char*) "black", (char*) "900"},
+ {(char*) "heavy", (char*) "900"},
+ {(char*) "ultrabold", (char*) "800"},
+ {(char*) "extrabold", (char*) "800"},
+ {(char*) "demibold", (char*) "600"},
+ {(char*) "semibold", (char*) "600"},
+ {(char*) "medium", (char*) "500"},
+ {(char*) "book", (char*) "normal"},
+ {(char*) "regular", (char*) "normal"},
+ {(char*) "roman", (char*) "normal"},
+ {(char*) "normal", (char*) "normal"},
+ {(char*) "ultralight", (char*) "200"},
+ {(char*) "extralight", (char*) "200"},
+ {(char*) "thin", (char*) "100"}
};
/**
} else if (font->getName()) {
_font_specification = font->getName()->getCString();
} else {
- _font_specification = "Arial";
+ _font_specification = (char*) "Arial";
}
// Prune the font name to get the correct font family name
char *css_font_weight = NULL;
if ( font_weight != GfxFont::WeightNotDefined ) {
if ( font_weight == GfxFont::W400 ) {
- css_font_weight = "normal";
+ css_font_weight = (char*) "normal";
} else if ( font_weight == GfxFont::W700 ) {
- css_font_weight = "bold";
+ css_font_weight = (char*) "bold";
} else {
gchar weight_num[4] = "100";
weight_num[0] = (gchar)( '1' + (font_weight - GfxFont::W100) );
}
}
} else {
- css_font_weight = "normal";
+ css_font_weight = (char*) "normal";
}
if (css_font_weight) {
sp_repr_css_set_property(_font_style, "font-weight", css_font_weight);
gchar *stretch_value = NULL;
switch (font_stretch) {
case GfxFont::UltraCondensed:
- stretch_value = "ultra-condensed";
+ stretch_value = (char*) "ultra-condensed";
break;
case GfxFont::ExtraCondensed:
- stretch_value = "extra-condensed";
+ stretch_value = (char*) "extra-condensed";
break;
case GfxFont::Condensed:
- stretch_value = "condensed";
+ stretch_value = (char*) "condensed";
break;
case GfxFont::SemiCondensed:
- stretch_value = "semi-condensed";
+ stretch_value = (char*) "semi-condensed";
break;
case GfxFont::Normal:
- stretch_value = "normal";
+ stretch_value = (char*) "normal";
break;
case GfxFont::SemiExpanded:
- stretch_value = "semi-expanded";
+ stretch_value = (char*) "semi-expanded";
break;
case GfxFont::Expanded:
- stretch_value = "expanded";
+ stretch_value = (char*) "expanded";
break;
case GfxFont::ExtraExpanded:
- stretch_value = "extra-expanded";
+ stretch_value = (char*) "extra-expanded";
break;
case GfxFont::UltraExpanded:
- stretch_value = "ultra-expanded";
+ stretch_value = (char*) "ultra-expanded";
break;
default:
break;
* \brief Updates current text position
*/
void SvgBuilder::updateTextPosition(double tx, double ty) {
- NR::Point new_position(tx, ty);
+ Geom::Point new_position(tx, ty);
_text_position = new_position;
}
max_scale = h_scale;
}
// Calculate new text matrix
- NR::Matrix new_text_matrix(text_matrix[0] * state->getHorizScaling(),
+ Geom::Matrix new_text_matrix(text_matrix[0] * state->getHorizScaling(),
text_matrix[1] * state->getHorizScaling(),
-text_matrix[2], -text_matrix[3],
0.0, 0.0);
Inkscape::XML::Node *text_node = _xml_doc->createElement("svg:text");
// Set text matrix
- NR::Matrix text_transform(_text_matrix);
+ Geom::Matrix text_transform(_text_matrix);
text_transform[4] = first_glyph.position[0];
text_transform[5] = first_glyph.position[1];
gchar *transform = sp_svg_transform_write(text_transform);
bool new_tspan = true;
bool same_coords[2] = {true, true};
- NR::Point last_delta_pos;
+ Geom::Point last_delta_pos;
unsigned int glyphs_in_a_row = 0;
Inkscape::XML::Node *tspan_node = NULL;
Glib::ustring x_coords;
Glib::ustring y_coords;
Glib::ustring text_buffer;
- bool is_vertical = !strcmp(sp_repr_css_property(_font_style, "writing-mode", "lr"), "tb"); // FIXME
// Output all buffered glyphs
while (1) {
break;
} else {
tspan_node = _xml_doc->createElement("svg:tspan");
- tspan_node->setAttribute("inkscape:font-specification", glyph.font_specification);
+
+ ///////
+ // Create a font specification string and save the attribute in the style
+ PangoFontDescription *descr = pango_font_description_from_string(glyph.font_specification);
+ Glib::ustring properFontSpec = font_factory::Default()->ConstructFontSpecification(descr);
+ pango_font_description_free(descr);
+ sp_repr_css_set_property(glyph.style, "-inkscape-font-specification", properFontSpec.c_str());
+
// Set style and unref SPCSSAttr if it won't be needed anymore
sp_repr_css_change(tspan_node, glyph.style, "style");
if ( glyph.style_changed && i != _glyphs.begin() ) { // Free previous style
}
}
// Append the coordinates to their respective strings
- NR::Point delta_pos( glyph.text_position - first_glyph.text_position );
+ Geom::Point delta_pos( glyph.text_position - first_glyph.text_position );
delta_pos[1] += glyph.rise;
delta_pos[1] *= -1.0; // flip it
delta_pos *= _font_scaling;
last_delta_pos = delta_pos;
// Append the character to the text buffer
- text_buffer.append((char *)&glyph.code, 1);
+ if (0 != glyph.code[0]) {
+ text_buffer.append((char *)&glyph.code, 1);
+ }
glyphs_in_a_row++;
i++;
bool is_space = ( uLen == 1 && u[0] == 32 );
// Skip beginning space
if ( is_space && _glyphs.size() < 1 ) {
- NR::Point delta(dx, dy);
+ Geom::Point delta(dx, dy);
_text_position += delta;
return;
}
// Allow only one space in a row
if ( is_space && _glyphs[_glyphs.size() - 1].code_size == 1 &&
_glyphs[_glyphs.size() - 1].code[0] == 32 ) {
- NR::Point delta(dx, dy);
+ Geom::Point delta(dx, dy);
_text_position += delta;
return;
}
SvgGlyph new_glyph;
new_glyph.is_space = is_space;
- new_glyph.position = NR::Point( x - originX, y - originY );
+ new_glyph.position = Geom::Point( x - originX, y - originY );
new_glyph.text_position = _text_position;
new_glyph.dx = dx;
new_glyph.dy = dy;
- NR::Point delta(dx, dy);
+ Geom::Point delta(dx, dy);
_text_position += delta;
// Convert the character to UTF-8 since that's our SVG document's encoding
@@ -1329,13 +1362,15 @@ Inkscape::XML::Node *SvgBuilder::_createImage(Stream *str, int width, int height
png_destroy_write_struct(&png_ptr, &info_ptr);
return NULL;
}
-
+ // Decide whether we should embed this image
+ double attr_value = 1.0;
+ sp_repr_get_double(_preferences, "embedImages", &attr_value);
+ bool embed_image = ( attr_value != 0.0 );
// Set read/write functions
Inkscape::IO::StringOutputStream base64_string;
Inkscape::IO::Base64OutputStream base64_stream(base64_string);
- FILE *fp;
- gchar *file_name;
- bool embed_image = true;
+ FILE *fp = NULL;
+ gchar *file_name = NULL;
if (embed_image) {
base64_stream.setColumnWidth(0); // Disable line breaks
png_set_write_fn(png_ptr, &base64_stream, png_write_base64stream, png_flush_base64stream);
@@ -1401,39 +1436,25 @@ Inkscape::XML::Node *SvgBuilder::_createImage(Stream *str, int width, int height
image_stream->reset();
// Convert grayscale values
- unsigned char *buffer = NULL;
- if ( color_map || invert_alpha ) {
- buffer = new unsigned char[width];
- }
- if ( color_map ) {
- for ( int y = 0 ; y < height ; y++ ) {
- unsigned char *row = image_stream->getLine();
+ unsigned char *buffer = new unsigned char[width];
+ int invert_bit = invert_alpha ? 1 : 0;
+ for ( int y = 0 ; y < height ; y++ ) {
+ unsigned char *row = image_stream->getLine();
+ if (color_map) {
color_map->getGrayLine(row, buffer, width);
- if (invert_alpha) {
- unsigned char *buf_ptr = buffer;
- for ( int x = 0 ; x < width ; x++ ) {
- *buf_ptr++ = ~(*buf_ptr);
- }
- }
- png_write_row(png_ptr, (png_bytep)buffer);
- }
- } else {
- for ( int y = 0 ; y < height ; y++ ) {
- unsigned char *row = image_stream->getLine();
- if (invert_alpha) {
- unsigned char *buf_ptr = buffer;
- for ( int x = 0 ; x < width ; x++ ) {
- *buf_ptr++ = ~row[x];
+ } else {
+ unsigned char *buf_ptr = buffer;
+ for ( int x = 0 ; x < width ; x++ ) {
+ if ( row[x] ^ invert_bit ) {
+ *buf_ptr++ = 0;
+ } else {
+ *buf_ptr++ = 255;
}
- png_write_row(png_ptr, (png_bytep)buffer);
- } else {
- png_write_row(png_ptr, (png_bytep)row);
}
}
+ png_write_row(png_ptr, (png_bytep)buffer);
}
- if (buffer) {
- delete buffer;
- }
+ delete buffer;
} else if (color_map) {
image_stream = new ImageStream(str, width,
color_map->getNumPixelComps(),
} else { // Work around for renderer bug when mask isn't defined in pattern
static int mask_count = 0;
Inkscape::XML::Node *defs = _root->firstChild();
- Inkscape::XML::Node *result = NULL;
if ( !( defs && !strcmp(defs->name(), "svg:defs") ) ) {
// Create <defs> node
defs = _xml_doc->createElement("svg:defs");
@@ -1612,7 +1632,7 @@ void SvgBuilder::addMaskedImage(GfxState *state, Stream *str, int width, int hei
mask_image_node->setAttribute("transform", NULL);
mask_node->appendChild(mask_image_node);
// Scale the mask to the size of the image
- NR::Matrix mask_transform((double)width, 0.0, 0.0, (double)height, 0.0, 0.0);
+ Geom::Matrix mask_transform((double)width, 0.0, 0.0, (double)height, 0.0, 0.0);
gchar *transform_text = sp_svg_transform_write(mask_transform);
mask_node->setAttribute("maskTransform", transform_text);
g_free(transform_text);