svg-builder.cpp revision c53f16f52840e8c0f2be9c1cc3af633c0ba1552e
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * Native PDF import using libpoppler.
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * miklos erdelyi
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * Copyright (C) 2007 Authors
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * Released under GNU GPL, read the file 'COPYING' for more information
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen//#define IFTRACE(_code) _code
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * \struct SvgTransparencyGroup
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * \brief Holds information about a PDF transparency group
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * \class SvgBuilder
981b809bc6ed10a21e89444d9447e5475801874fjohanengelenSvgBuilder::SvgBuilder(SPDocument *document, gchar *docname, XRef *xref) {
981b809bc6ed10a21e89444d9447e5475801874fjohanengelenSvgBuilder::SvgBuilder(SvgBuilder *parent, Inkscape::XML::Node *root) {
981b809bc6ed10a21e89444d9447e5475801874fjohanengelenvoid SvgBuilder::setDocumentSize(double width, double height) {
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen sp_repr_set_svg_double(_root, "height", height);
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * \brief Sets groupmode of the current container to 'layer' and sets its label if given
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen _container->setAttribute("inkscape:groupmode", "layer");
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen _container->setAttribute("inkscape:label", layer_name);
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * \brief Sets the current container's opacity
981b809bc6ed10a21e89444d9447e5475801874fjohanengelenvoid SvgBuilder::setGroupOpacity(double opacity) {
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen sp_repr_set_svg_double(_container, "opacity", CLAMP(opacity, 0.0, 1.0));
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen new_state.softmask = _state_stack.back().softmask;
981b809bc6ed10a21e89444d9447e5475801874fjohanengelenInkscape::XML::Node *SvgBuilder::pushNode(const char *name) {
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen Inkscape::XML::Node *node = _xml_doc->createElement(name);
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen _container = _node_stack.back(); // Re-set container
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen TRACE(("popNode() called when stack is empty\n"));
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen Inkscape::XML::Node *saved_container = _container;
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen // Set as a layer if this is a top-level group
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen if ( _container->parent() == _root && _is_top_level ) {
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen gchar *layer_name = g_strdup_printf("%s%d", _docname, layer_count);
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen if (_container != _root) { // Pop if the current container isn't root
981b809bc6ed10a21e89444d9447e5475801874fjohanengelenInkscape::XML::Node *SvgBuilder::getContainer() {
981b809bc6ed10a21e89444d9447e5475801874fjohanengelenstatic gchar *svgConvertRGBToText(double r, double g, double b) {
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen "#%02x%02x%02x",
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen return svgConvertRGBToText(r, g, b);
981b809bc6ed10a21e89444d9447e5475801874fjohanengelenstatic void svgSetTransform(Inkscape::XML::Node *node, double c0, double c1,
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen gchar *transform_text = sp_svg_transform_write(matrix);
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen node->setAttribute("transform", transform_text);
981b809bc6ed10a21e89444d9447e5475801874fjohanengelenstatic void svgSetTransform(Inkscape::XML::Node *node, double *transform) {
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen svgSetTransform(node, transform[0], transform[1], transform[2], transform[3],
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * \brief Generates a SVG path string from poppler's data structure
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen for ( i = 0 ; i < path->getNumSubpaths() ; ++i ) {
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen pathString.moveTo(subpath->getX(0), subpath->getY(0));
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen pathString.curveTo(subpath->getX(j), subpath->getY(j),
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen pathString.lineTo(subpath->getX(j), subpath->getY(j));
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * \brief Sets stroke style from poppler's GfxState data structure
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * Uses the given SPCSSAttr for storing the style properties
981b809bc6ed10a21e89444d9447e5475801874fjohanengelenvoid SvgBuilder::_setStrokeStyle(SPCSSAttr *css, GfxState *state) {
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen // Check line width
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen // Ignore stroke
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen sp_repr_css_set_property(css, "stroke", "none");
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen if ( state->getStrokeColorSpace()->getMode() == csPattern ) {
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen gchar *urltext = _createPattern(state->getStrokePattern(), state, true);
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen sp_repr_css_set_property(css, "stroke", urltext);
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen sp_repr_css_set_property(css, "stroke", svgConvertGfxRGB(&stroke_color));
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen sp_repr_css_set_property(css, "stroke-opacity", os_opacity.str().c_str());
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen // Line width
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen sp_repr_css_set_property(css, "stroke-width", os_width.str().c_str());
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen sp_repr_css_set_property(css, "stroke-linecap", "butt");
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen sp_repr_css_set_property(css, "stroke-linecap", "round");
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen sp_repr_css_set_property(css, "stroke-linecap", "square");
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen // Line join
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen sp_repr_css_set_property(css, "stroke-linejoin", "miter");
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen sp_repr_css_set_property(css, "stroke-linejoin", "round");
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen sp_repr_css_set_property(css, "stroke-linejoin", "bevel");
6492fcbc5fbe9a07962f989247731b6435fd72b9johanengelen // Miterlimit
6492fcbc5fbe9a07962f989247731b6435fd72b9johanengelen sp_repr_css_set_property(css, "stroke-miterlimit", os_ml.str().c_str());
6492fcbc5fbe9a07962f989247731b6435fd72b9johanengelen // Line dash
6492fcbc5fbe9a07962f989247731b6435fd72b9johanengelen state->getLineDash(&dash_pattern, &dash_length, &dash_start);
6492fcbc5fbe9a07962f989247731b6435fd72b9johanengelen for ( int i = 0 ; i < dash_length ; i++ ) {
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen sp_repr_css_set_property(css, "stroke-dasharray", os_array.str().c_str());
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen sp_repr_css_set_property(css, "stroke-dashoffset", os_offset.str().c_str());
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen sp_repr_css_set_property(css, "stroke-dasharray", "none");
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen sp_repr_css_set_property(css, "stroke-dashoffset", NULL);
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * \brief Sets fill style from poppler's GfxState data structure
if (urltext) {
if (fill) {
if (stroke) {
return css;
bool even_odd) {
if (id) {
if (even_odd) {
pushGroup();
if (even_odd) {
if (valid) {
return NULL;
return urltext;
&box);
delete pdf_parser;
delete pattern_builder;
return id;
int num_funcs;
return NULL;
if (matrix) {
return NULL;
return id;
for ( int i = 0 ; i < num_funcs ; i++ ) {
bool is_continuation = false;
is_continuation = true;
if ( !is_continuation ) {
if (_in_text_object) {
_invalidated_style = true;
_need_font_update = false;
if (_font_style) {
if (plus_sign) {
style_delim[0] = 0;
} else if (font_style) {
} else if (font_style) {
for ( int i = 0 ; i < num_translations ; i++ ) {
if (css_font_weight) {
if (font_style_lowercase) {
switch (font_stretch) {
double max_scale;
_invalidated_style = true;
_flushText();
bool new_tspan = true;
unsigned int glyphs_in_a_row = 0;
new_tspan = true;
new_tspan = true;
if (tspan_node) {
glyphs_in_a_row = 0;
new_tspan = false;
if ( glyphs_in_a_row > 0 ) {
if (_need_font_update) {
delete enc;
int code_size = 0;
for ( int i = 0 ; i < uLen ; i++ ) {
code_size += u_map->mapUnicode(u[i], (char *)&new_glyph.code[code_size], sizeof(new_glyph.code) - code_size);
_invalidated_style = false;
_in_text_object = true;
_flushText();
_in_text_object = false;
for ( unsigned i = 0 ; i < length ; i++ ) {
return NULL;
return NULL;
return NULL;
bool embed_image = true;
if (embed_image) {
static int counter = 0;
return NULL;
if (alpha_only) {
if (alpha_only) {
if (color_map) {
if ( color_map ) {
for ( int y = 0 ; y < height ; y++ ) {
if (invert_alpha) {
for ( int x = 0 ; x < width ; x++ ) {
for ( int y = 0 ; y < height ; y++ ) {
if (invert_alpha) {
for ( int x = 0 ; x < width ; x++ ) {
if (buffer) {
delete buffer;
} else if (color_map) {
if (mask_colors) {
for ( int y = 0 ; y < height ; y++ ) {
for ( int x = 0 ; x < width ; x++ ) {
dest++;
for ( int i = 0 ; i < height ; i++ ) {
delete buffer;
if (!embed_image) {
return NULL;
delete image_stream;
if (_is_top_level) {
if (embed_image) {
return image_node;
if (_is_top_level) {
static int mask_count = 0;
if (image_node) {
bool invert) {
if (mask_image_node) {
bool invert_mask) {
if (mask_image_node) {
if (image_node) {
if (mask_image_node) {
if (image_node) {
bool for_softmask) {
popNode();
delete transpGroup;
pushGroup();
delete transpGroup;
popGroup();