From dc4f69a188c203f2fdc65f22d0d57904a8c52dd7 Mon Sep 17 00:00:00 2001 From: miklosh Date: Mon, 23 Jul 2007 18:02:43 +0000 Subject: [PATCH] Added tiling pattern support --- src/extension/internal/pdfinput/pdf-input.cpp | 2 +- .../internal/pdfinput/pdf-parser.cpp | 25 +++++++ src/extension/internal/pdfinput/pdf-parser.h | 4 + .../internal/pdfinput/svg-builder.cpp | 75 +++++++++++++++++-- src/extension/internal/pdfinput/svg-builder.h | 9 ++- 5 files changed, 104 insertions(+), 11 deletions(-) diff --git a/src/extension/internal/pdfinput/pdf-input.cpp b/src/extension/internal/pdfinput/pdf-input.cpp index 2fe6c73d3..9adf1958f 100644 --- a/src/extension/internal/pdfinput/pdf-input.cpp +++ b/src/extension/internal/pdfinput/pdf-input.cpp @@ -69,7 +69,7 @@ PdfInput::open(::Inkscape::Extension::Input * mod, const gchar * uri) { sp_document_set_undo_sensitive(doc, false); // No need to undo in this temporary document // Create builder and parser - SvgBuilder *builder = new SvgBuilder(doc); + SvgBuilder *builder = new SvgBuilder(doc, pdf_doc->getXRef()); PdfParser *pdf_parser = new PdfParser(pdf_doc->getXRef(), builder, page_num-1, page->getRotate(), page->getResourceDict(), page->getCropBox()); diff --git a/src/extension/internal/pdfinput/pdf-parser.cpp b/src/extension/internal/pdfinput/pdf-parser.cpp index c76b4927b..0e614206f 100644 --- a/src/extension/internal/pdfinput/pdf-parser.cpp +++ b/src/extension/internal/pdfinput/pdf-parser.cpp @@ -335,6 +335,31 @@ PdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *bui pushOperator("startPage"); } +PdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *builderA, + Dict *resDict, PDFRectangle *box) { + + int i; + + xref = xrefA; + subPage = gTrue; + printCommands = false; + + // start the resource stack + res = new GfxResources(xref, resDict, NULL); + + // initialize + operatorHistory = NULL; + builder = builderA; + state = new GfxState(72, 72, box, 0, gFalse); + fontChanged = gFalse; + clip = clipNone; + ignoreUndef = 0; + for (i = 0; i < 6; ++i) { + baseMatrix[i] = state->getCTM()[i]; + } + formDepth = 0; +} + PdfParser::~PdfParser() { while (state->hasSaves()) { restoreState(); diff --git a/src/extension/internal/pdfinput/pdf-parser.h b/src/extension/internal/pdfinput/pdf-parser.h index 394c9ca83..5747dcc9a 100644 --- a/src/extension/internal/pdfinput/pdf-parser.h +++ b/src/extension/internal/pdfinput/pdf-parser.h @@ -112,6 +112,10 @@ public: PdfParser(XRef *xrefA, SvgBuilder *builderA, int pageNum, int rotate, Dict *resDict, PDFRectangle *cropBox); + // Constructor for a sub-page object. + PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *builderA, + Dict *resDict, PDFRectangle *box); + ~PdfParser(); // Interpret a stream or array of streams. diff --git a/src/extension/internal/pdfinput/svg-builder.cpp b/src/extension/internal/pdfinput/svg-builder.cpp index fc013674b..7ca8eb0fe 100644 --- a/src/extension/internal/pdfinput/svg-builder.cpp +++ b/src/extension/internal/pdfinput/svg-builder.cpp @@ -41,6 +41,7 @@ #include "GfxState.h" #include "GfxFont.h" #include "Stream.h" +#include "Page.h" #include "UnicodeMap.h" #include "GlobalParams.h" @@ -68,8 +69,9 @@ SvgBuilder::SvgBuilder() { _current_state = NULL; } -SvgBuilder::SvgBuilder(SPDocument *document) { +SvgBuilder::SvgBuilder(SPDocument *document, XRef *xref) { _doc = document; + _xref = xref; _xml_doc = sp_document_repr_doc(_doc); _container = _root = _doc->rroot; SvgBuilder(); @@ -77,6 +79,7 @@ SvgBuilder::SvgBuilder(SPDocument *document) { SvgBuilder::SvgBuilder(SvgBuilder *parent, Inkscape::XML::Node *root) { _doc = parent->_doc; + _xref = parent->_xref; _xml_doc = parent->_xml_doc; _container = this->_root = root; SvgBuilder(); @@ -205,7 +208,7 @@ void SvgBuilder::_setStrokeStyle(SPCSSAttr *css, GfxState *state) { // Stroke color/pattern if ( state->getStrokeColorSpace()->getMode() == csPattern ) { - gchar *urltext = _createPattern(state->getStrokePattern()); + gchar *urltext = _createPattern(state->getStrokePattern(), state, true); sp_repr_css_set_property(css, "stroke", urltext); if (urltext) { g_free(urltext); @@ -289,7 +292,7 @@ void SvgBuilder::_setFillStyle(SPCSSAttr *css, GfxState *state, bool even_odd) { // Fill color/pattern if ( state->getFillColorSpace()->getMode() == csPattern ) { - gchar *urltext = _createPattern(state->getFillPattern()); + gchar *urltext = _createPattern(state->getFillPattern(), state); sp_repr_css_set_property(css, "fill", urltext); if (urltext) { g_free(urltext); @@ -444,13 +447,13 @@ bool SvgBuilder::isPatternTypeSupported(GfxPattern *pattern) { * build a tiling pattern. * \return an url pointing to the created pattern */ -gchar *SvgBuilder::_createPattern(GfxPattern *pattern) { +gchar *SvgBuilder::_createPattern(GfxPattern *pattern, GfxState *state, bool is_stroke) { gchar *id = NULL; if ( pattern != NULL ) { if ( pattern->getType() == 2 ) { // Shading pattern id = _createGradient((GfxShadingPattern*)pattern); } else if ( pattern->getType() == 1 ) { // Tiling pattern - id = _createTilingPattern((GfxTilingPattern*)pattern); + id = _createTilingPattern((GfxTilingPattern*)pattern, state, is_stroke); } } else { return NULL; @@ -460,8 +463,66 @@ gchar *SvgBuilder::_createPattern(GfxPattern *pattern) { return urltext; } -gchar *SvgBuilder::_createTilingPattern(GfxTilingPattern *tiling_pattern) { - return NULL; +/** + * \brief Creates a tiling pattern from poppler's data structure + * Creates a sub-page PdfParser and uses it to parse the pattern's content stream. + * \return id of the created pattern + */ +gchar *SvgBuilder::_createTilingPattern(GfxTilingPattern *tiling_pattern, + GfxState *state, bool is_stroke) { + + 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]); + gchar *transform_text = sp_svg_transform_write(pat_matrix); + pattern_node->setAttribute("patternTransform", transform_text); + g_free(transform_text); + pattern_node->setAttribute("patternUnits", "userSpaceOnUse"); + // Set pattern tiling + // FIXME: don't ignore XStep and YStep + double *bbox = tiling_pattern->getBBox(); + sp_repr_set_svg_double(pattern_node, "x", 0.0); + sp_repr_set_svg_double(pattern_node, "y", 0.0); + sp_repr_set_svg_double(pattern_node, "width", bbox[2] - bbox[0]); + sp_repr_set_svg_double(pattern_node, "height", bbox[3] - bbox[1]); + + // Convert BBox for PdfParser + PDFRectangle box; + box.x1 = bbox[0]; + box.y1 = bbox[1]; + box.x2 = bbox[2]; + box.y2 = bbox[3]; + // Create new SvgBuilder and sub-page PdfParser + SvgBuilder *pattern_builder = new SvgBuilder(this, pattern_node); + PdfParser *pdf_parser = new PdfParser(_xref, pattern_builder, tiling_pattern->getResDict(), + &box); + // Get pattern color space + GfxPatternColorSpace *pat_cs = (GfxPatternColorSpace *)( is_stroke ? state->getStrokeColorSpace() + : state->getFillColorSpace() ); + // Set fill/stroke colors if this is an uncolored tiling pattern + GfxColorSpace *cs = NULL; + if ( tiling_pattern->getPaintType() == 2 && ( cs = pat_cs->getUnder() ) ) { + GfxState *pattern_state = pdf_parser->getState(); + pattern_state->setFillColorSpace(cs->copy()); + pattern_state->setFillColor(state->getFillColor()); + pattern_state->setStrokeColorSpace(cs->copy()); + pattern_state->setStrokeColor(state->getFillColor()); + } + + // Generate the SVG pattern + pdf_parser->parse(tiling_pattern->getContentStream()); + + // Cleanup + delete pdf_parser; + delete pattern_builder; + + // Append the pattern to defs + SP_OBJECT_REPR (SP_DOCUMENT_DEFS (_doc))->appendChild(pattern_node); + gchar *id = g_strdup(pattern_node->attribute("id")); + Inkscape::GC::release(pattern_node); + + return id; } /** diff --git a/src/extension/internal/pdfinput/svg-builder.h b/src/extension/internal/pdfinput/svg-builder.h index 8145a4522..8888989e9 100644 --- a/src/extension/internal/pdfinput/svg-builder.h +++ b/src/extension/internal/pdfinput/svg-builder.h @@ -40,6 +40,7 @@ class GfxTilingPattern; class GfxFont; class GfxImageColorMap; class Stream; +class XRef; class SPCSSAttr; @@ -76,7 +77,7 @@ struct SvgGlyph { */ class SvgBuilder { public: - SvgBuilder(SPDocument *document); + SvgBuilder(SPDocument *document, XRef *xref); SvgBuilder(SvgBuilder *parent, Inkscape::XML::Node *root); ~SvgBuilder(); @@ -127,12 +128,13 @@ private: SvgBuilder(); // Pattern creation - gchar *_createPattern(GfxPattern *pattern); + gchar *_createPattern(GfxPattern *pattern, GfxState *state, bool is_stroke=false); gchar *_createGradient(GfxShadingPattern *shading_pattern); bool _addStopsToGradient(Inkscape::XML::Node *gradient, Function *func, double opacity); bool _addSamplesToGradient(Inkscape::XML::Node *gradient, SampledFunction *func, double offset0, double offset1, double opacity); - gchar *_createTilingPattern(GfxTilingPattern *tiling_pattern); + gchar *_createTilingPattern(GfxTilingPattern *tiling_pattern, GfxState *state, + bool is_stroke=false); // Image/mask creation Inkscape::XML::Node *_createImage(Stream *str, int width, int height, GfxImageColorMap *color_map, int *mask_colors, @@ -157,6 +159,7 @@ private: GfxState *_current_state; SPDocument *_doc; + XRef *_xref; // Cross-reference table from the PDF doc we're converting from Inkscape::XML::Document *_xml_doc; Inkscape::XML::Node *_root; // Root node from the point of view of this SvgBuilder Inkscape::XML::Node *_container; // Current container (group/pattern/mask) -- 2.30.2