Code

Added tiling pattern support
authormiklosh <miklosh@users.sourceforge.net>
Mon, 23 Jul 2007 18:02:43 +0000 (18:02 +0000)
committermiklosh <miklosh@users.sourceforge.net>
Mon, 23 Jul 2007 18:02:43 +0000 (18:02 +0000)
src/extension/internal/pdfinput/pdf-input.cpp
src/extension/internal/pdfinput/pdf-parser.cpp
src/extension/internal/pdfinput/pdf-parser.h
src/extension/internal/pdfinput/svg-builder.cpp
src/extension/internal/pdfinput/svg-builder.h

index 2fe6c73d31122b76fe6e8624ee0956026e0129a6..9adf1958f99b74bd1e4700c711f601331cd326cc 100644 (file)
@@ -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());
 
index c76b4927b73058bc2ae1d07e85a14565a73c107b..0e614206f5e85b55c9d02b0e118302d132d5e6d3 100644 (file)
@@ -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();
index 394c9ca830e092fabb84b95c750fee089efdf202..5747dcc9a0acd95b6974f726790096fd480d7c8f 100644 (file)
@@ -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.
index fc013674be3c5a534688c0eba9e024c441ff968e..7ca8eb0fef5b6a466f270a4bf6d10cacd4e50295 100644 (file)
@@ -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;
 }
 
 /**
index 8145a45224a99c460de6c2c67cddc8ec9beecb46..8888989e95a0ce85ccd0df38d2955a5ee42a7436 100644 (file)
@@ -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)