FabioOn Sunday, April 07, 2013 08:10:32 PM  D'Urso wrote:
> Modified patches attached. They are not final yet: I still have to update
> the documentation in the second-to-last patch.

Final patches attached. Adam, can you have a look at 0006 and check if the 
documentation on FixedRotation is clear enough?

Differences from initial patches:

0001 (core: Support for rendering annotations with flagNoRotate)
   The counter-rotation now does *not* depend on the rendering context.
   NoRotate annotations are always positioned as if rendering rotation was
   zero.

0002 (poppler_qt4viewer: Add combobox to select rotation) and
0003 (pdftops: Added "-rasterize" flag to force rasterization)
   These two patches have not changed. I had posted them because they were
   useful to test context-dependent rotations, but I've removed such
   rotations, therefore feel free to drop them if you wish.

0004 (core: Remove geometry-related arguments from annotation
constructors) and 0005 (qt4: FixedRotation annotations' coordinate
conversion)
   No changes

0006 (qt4: Some documentation about annotations)
   I've partly rewritten the doc section about FixedRotation annotations

0007 (qt4: Free some temporary memory in
 TextAnnotationPrivate::createNativeAnnot)
   No changes

Fabio
>From 95b75c38536c4ed82b4699ee73e7fae229a10edd Mon Sep 17 00:00:00 2001
From: Fabio D'Urso <[email protected]>
Date: Fri, 15 Feb 2013 14:47:12 +0100
Subject: [PATCH 1/7] core: Support for rendering annotations with flagNoRotate

Gfx::drawAnnot now makes a counter-rotation if flagNoRotate is set
---
 poppler/Annot.cc | 55 ++++++++++++++++++++++++++++++++++++-------------------
 poppler/Annot.h  |  3 ++-
 poppler/Gfx.cc   | 41 +++++++++++++++++++++++++++++++++++++----
 poppler/Gfx.h    |  3 ++-
 4 files changed, 77 insertions(+), 25 deletions(-)

diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 2713fde..0e3f726 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -24,7 +24,7 @@
 // Copyright (C) 2008 Hugo Mercier <[email protected]>
 // Copyright (C) 2009 Ilya Gorenbein <[email protected]>
 // Copyright (C) 2011, 2013 José Aliste <[email protected]>
-// Copyright (C) 2012 Fabio D'Urso <[email protected]>
+// Copyright (C) 2012, 2013 Fabio D'Urso <[email protected]>
 // Copyright (C) 2012, 2013 Thomas Freitag <[email protected]>
 // Copyright (C) 2012 Tobias Koenig <[email protected]>
 //
@@ -1773,6 +1773,18 @@ GBool Annot::isVisible(GBool printing) {
   return gTrue;
 }
 
+int Annot::getRotation() const
+{
+  Page *pageobj = doc->getPage(page);
+  assert(pageobj != NULL);
+
+  if (flags & flagNoRotate) {
+    return (360 - pageobj->getRotate()) % 360;
+  } else {
+    return 0;
+  }
+}
+
 void Annot::draw(Gfx *gfx, GBool printing) {
   Object obj;
 
@@ -1783,7 +1795,7 @@ void Annot::draw(Gfx *gfx, GBool printing) {
   // draw the appearance stream
   appearance.fetch(gfx->getXRef(), &obj);
   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
-      rect->x1, rect->y1, rect->x2, rect->y2);
+      rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   obj.free();
 }
 
@@ -2450,10 +2462,11 @@ void AnnotText::draw(Gfx *gfx, GBool printing) {
   if (appearBBox) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    appearBBox->getPageXMin(), appearBBox->getPageYMin(),
-                   appearBBox->getPageXMax(), appearBBox->getPageYMax());
+                   appearBBox->getPageXMax(), appearBBox->getPageYMax(),
+                   getRotation());
   } else {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
-                   rect->x1, rect->y1, rect->x2, rect->y2);
+                   rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   }
   obj.free();
 }
@@ -2548,7 +2561,7 @@ void AnnotLink::draw(Gfx *gfx, GBool printing) {
   // draw the appearance stream
   appearance.fetch(gfx->getXRef(), &obj);
   gfx->drawAnnot(&obj, border, color,
-		 rect->x1, rect->y1, rect->x2, rect->y2);
+		 rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   obj.free();
 }
 
@@ -2982,7 +2995,7 @@ void AnnotFreeText::draw(Gfx *gfx, GBool printing) {
   // draw the appearance stream
   appearance.fetch(gfx->getXRef(), &obj);
   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
-                 rect->x1, rect->y1, rect->x2, rect->y2);
+                 rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   obj.free();
 }
 
@@ -3457,10 +3470,11 @@ void AnnotLine::draw(Gfx *gfx, GBool printing) {
   if (appearBBox) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    appearBBox->getPageXMin(), appearBBox->getPageYMin(),
-                   appearBBox->getPageXMax(), appearBBox->getPageYMax());
+                   appearBBox->getPageXMax(), appearBBox->getPageYMax(),
+                   getRotation());
   } else {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
-                   rect->x1, rect->y1, rect->x2, rect->y2);
+                   rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   }
   obj.free();
 }
@@ -3771,10 +3785,11 @@ void AnnotTextMarkup::draw(Gfx *gfx, GBool printing) {
   if (appearBBox) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    appearBBox->getPageXMin(), appearBBox->getPageYMin(),
-                   appearBBox->getPageXMax(), appearBBox->getPageYMax());
+                   appearBBox->getPageXMax(), appearBBox->getPageYMax(),
+                   getRotation());
   } else {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
-                   rect->x1, rect->y1, rect->x2, rect->y2);
+                   rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   }
   obj.free();
 }
@@ -5038,7 +5053,7 @@ void AnnotWidget::draw(Gfx *gfx, GBool printing) {
     delete dict;
   }
   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
-		 rect->x1, rect->y1, rect->x2, rect->y2);
+		 rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   if (addDingbatsResource) {
     gfx->popResources();
   }
@@ -5194,7 +5209,7 @@ void AnnotMovie::draw(Gfx *gfx, GBool printing) {
   // draw the appearance stream
   appearance.fetch(gfx->getXRef(), &obj);
   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
-		 rect->x1, rect->y1, rect->x2, rect->y2);
+		 rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   obj.free();
 }
 
@@ -5537,7 +5552,7 @@ void AnnotGeometry::draw(Gfx *gfx, GBool printing) {
   // draw the appearance stream
   appearance.fetch(gfx->getXRef(), &obj);
   gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
-		 rect->x1, rect->y1, rect->x2, rect->y2);
+		 rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   obj.free();
 }
 
@@ -5824,10 +5839,11 @@ void AnnotPolygon::draw(Gfx *gfx, GBool printing) {
   if (appearBBox) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    appearBBox->getPageXMin(), appearBBox->getPageYMin(),
-                   appearBBox->getPageXMax(), appearBBox->getPageYMax());
+                   appearBBox->getPageXMax(), appearBBox->getPageYMax(),
+                   getRotation());
   } else {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
-                   rect->x1, rect->y1, rect->x2, rect->y2);
+                   rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   }
   obj.free();
 }
@@ -6037,10 +6053,11 @@ void AnnotInk::draw(Gfx *gfx, GBool printing) {
   if (appearBBox) {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
                    appearBBox->getPageXMin(), appearBBox->getPageYMin(),
-                   appearBBox->getPageXMax(), appearBBox->getPageYMax());
+                   appearBBox->getPageXMax(), appearBBox->getPageYMax(),
+                   getRotation());
   } else {
     gfx->drawAnnot(&obj, (AnnotBorder *)NULL, color,
-                   rect->x1, rect->y1, rect->x2, rect->y2);
+                   rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   }
   obj.free();
 }
@@ -6257,7 +6274,7 @@ void AnnotFileAttachment::draw(Gfx *gfx, GBool printing) {
   // draw the appearance stream
   appearance.fetch(gfx->getXRef(), &obj);
   gfx->drawAnnot(&obj, border, color,
-		 rect->x1, rect->y1, rect->x2, rect->y2);
+		 rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   obj.free();
 }
 
@@ -6419,7 +6436,7 @@ void AnnotSound::draw(Gfx *gfx, GBool printing) {
   // draw the appearance stream
   appearance.fetch(gfx->getXRef(), &obj);
   gfx->drawAnnot(&obj, border, color,
-		 rect->x1, rect->y1, rect->x2, rect->y2);
+		 rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
   obj.free();
 }
 
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 7be2114..ca94429 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -22,7 +22,7 @@
 // Copyright (C) 2008 Pino Toscano <[email protected]>
 // Copyright (C) 2008 Tomas Are Haavet <[email protected]>
 // Copyright (C) 2009-2011, 2013 Albert Astals Cid <[email protected]>
-// Copyright (C) 2012 Fabio D'Urso <[email protected]>
+// Copyright (C) 2012, 2013 Fabio D'Urso <[email protected]>
 // Copyright (C) 2012 Tobias Koenig <[email protected]>
 // Copyright (C) 2013 Thomas Freitag <[email protected]>
 //
@@ -624,6 +624,7 @@ protected:
   void createResourcesDict(const char *formName, Object *formStream, const char *stateName,
 			   double opacity, const char *blendMode, Object *resDict);
   GBool isVisible(GBool printing);
+  int getRotation() const;
 
   // Updates the field key of the annotation dictionary
   // and sets M to the current time
diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index b15ee5f..9195e48 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -35,7 +35,7 @@
 // Copyright (C) 2010 Christian Feuersänger <[email protected]>
 // Copyright (C) 2011 Axel Strübing <[email protected]>
 // Copyright (C) 2012 Even Rouault <[email protected]>
-// Copyright (C) 2012 Fabio D'Urso <[email protected]>
+// Copyright (C) 2012, 2013 Fabio D'Urso <[email protected]>
 // Copyright (C) 2012 Lu Wang <[email protected]>
 //
 // To see a description of the changes please see the Changelog file that
@@ -62,6 +62,7 @@
 #include "Object.h"
 #include "PDFDoc.h"
 #include "Array.h"
+#include "Annot.h"
 #include "Dict.h"
 #include "Stream.h"
 #include "Lexer.h"
@@ -5122,8 +5123,20 @@ void Gfx::opMarkPoint(Object args[], int numArgs) {
 // misc
 //------------------------------------------------------------------------
 
+struct GfxStackStateSaver {
+  GfxStackStateSaver(Gfx *gfx) : gfx(gfx) {
+    gfx->saveState();
+  }
+
+  ~GfxStackStateSaver() {
+    gfx->restoreState();
+  }
+
+  Gfx * const gfx;
+};
+
 void Gfx::drawAnnot(Object *str, AnnotBorder *border, AnnotColor *aColor,
-		    double xMin, double yMin, double xMax, double yMax) {
+		    double xMin, double yMin, double xMax, double yMax, int rotate) {
   Dict *dict, *resDict;
   Object matrixObj, bboxObj, resObj, obj1;
   double formXMin, formYMin, formXMax, formYMax;
@@ -5144,6 +5157,28 @@ void Gfx::drawAnnot(Object *str, AnnotBorder *border, AnnotColor *aColor,
     return;
   }
 
+  // saves gfx state and automatically restores it on return
+  GfxStackStateSaver stackStateSaver(this);
+
+  // Rotation around the topleft corner (for the NoRotate flag)
+  if (rotate != 0) {
+    const double angle_rad = rotate * M_PI / 180;
+    const double c = cos(angle_rad);
+    const double s = sin(angle_rad);
+
+    // (xMin, yMax) is the pivot
+    const double unrotateMTX[6] = {
+        +c, -s,
+        +s, +c,
+        -c*xMin - s*yMax + xMin, -c*yMax + s*xMin + yMax
+    };
+
+    state->concatCTM(unrotateMTX[0], unrotateMTX[1], unrotateMTX[2],
+                     unrotateMTX[3], unrotateMTX[4], unrotateMTX[5]);
+    out->updateCTM(state, unrotateMTX[0], unrotateMTX[1], unrotateMTX[2],
+                          unrotateMTX[3], unrotateMTX[4], unrotateMTX[5]);
+  }
+
   // draw the appearance stream (if there is one)
   if (str->isStream()) {
 
@@ -5267,7 +5302,6 @@ void Gfx::drawAnnot(Object *str, AnnotBorder *border, AnnotColor *aColor,
 
   // draw the border
   if (border && border->getWidth() > 0) {
-    saveState();
     if (state->getStrokeColorSpace()->getMode() != csDeviceRGB) {
       state->setStrokePattern(NULL);
       state->setStrokeColorSpace(new GfxDeviceRGBColorSpace());
@@ -5306,7 +5340,6 @@ void Gfx::drawAnnot(Object *str, AnnotBorder *border, AnnotColor *aColor,
       state->closePath();
     }
     out->stroke(state);
-    restoreState();
   }
 }
 
diff --git a/poppler/Gfx.h b/poppler/Gfx.h
index e7e9ab8..366c5e5 100644
--- a/poppler/Gfx.h
+++ b/poppler/Gfx.h
@@ -21,6 +21,7 @@
 // Copyright (C) 2009, 2010, 2012, 2013 Thomas Freitag <[email protected]>
 // Copyright (C) 2010 David Benjamin <[email protected]>
 // Copyright (C) 2010 Christian Feuersänger <[email protected]>
+// Copyright (C) 2013 Fabio D'Urso <[email protected]>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -166,7 +167,7 @@ public:
   // Display an annotation, given its appearance (a Form XObject),
   // border style, and bounding box (in default user space).
   void drawAnnot(Object *str, AnnotBorder *border, AnnotColor *aColor,
-		 double xMin, double yMin, double xMax, double yMax);
+		 double xMin, double yMin, double xMax, double yMax, int rotate);
 
   // Save graphics state.
   void saveState();
-- 
1.8.1.4
>From 43f265797cca506d6841eecf94852f710b2574bd Mon Sep 17 00:00:00 2001
From: Fabio D'Urso <[email protected]>
Date: Fri, 15 Feb 2013 12:24:18 +0100
Subject: [PATCH 2/7] poppler_qt4viewer: Add combobox to select rotation

---
 qt4/demos/navigationtoolbar.cpp | 15 +++++++++++++++
 qt4/demos/navigationtoolbar.h   |  4 ++++
 qt4/demos/pageview.cpp          | 24 +++++++++++++++++++++++-
 qt4/demos/pageview.h            |  3 +++
 qt4/demos/viewer.cpp            |  2 ++
 5 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/qt4/demos/navigationtoolbar.cpp b/qt4/demos/navigationtoolbar.cpp
index e9ebafa..79dd418 100644
--- a/qt4/demos/navigationtoolbar.cpp
+++ b/qt4/demos/navigationtoolbar.cpp
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2008-2009, Pino Toscano <[email protected]>
+ * Copyright (C) 2013, Fabio D'Urso <[email protected]>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -54,6 +55,15 @@ NavigationToolBar::NavigationToolBar(QWidget *parent)
     connect(m_zoomCombo, SIGNAL(currentIndexChanged(QString)), this, SLOT(slotZoomComboChanged(QString)));
     addWidget(m_zoomCombo);
 
+    m_rotationCombo = new QComboBox(this);
+    // NOTE: \302\260 = degree symbol
+    m_rotationCombo->addItem(trUtf8("0\302\260"));
+    m_rotationCombo->addItem(trUtf8("90\302\260"));
+    m_rotationCombo->addItem(trUtf8("180\302\260"));
+    m_rotationCombo->addItem(trUtf8("270\302\260"));
+    connect(m_rotationCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(slotRotationComboChanged(int)));
+    addWidget(m_rotationCombo);
+
     documentClosed();
 }
 
@@ -126,4 +136,9 @@ void NavigationToolBar::slotZoomComboChanged(const QString &_text)
     }
 }
 
+void NavigationToolBar::slotRotationComboChanged(int idx)
+{
+    emit rotationChanged(idx * 90);
+}
+
 #include "navigationtoolbar.moc"
diff --git a/qt4/demos/navigationtoolbar.h b/qt4/demos/navigationtoolbar.h
index 3469f01..d7dbd5d 100644
--- a/qt4/demos/navigationtoolbar.h
+++ b/qt4/demos/navigationtoolbar.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2008-2009, Pino Toscano <[email protected]>
+ * Copyright (C) 2013, Fabio D'Urso <[email protected]>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -40,6 +41,7 @@ public:
 
 Q_SIGNALS:
     void zoomChanged(qreal value);
+    void rotationChanged(int rotation);
 
 private Q_SLOTS:
     void slotGoFirst();
@@ -48,6 +50,7 @@ private Q_SLOTS:
     void slotGoLast();
     void slotComboActivated(int index);
     void slotZoomComboChanged(const QString &text);
+    void slotRotationComboChanged(int idx);
 
 private:
     QAction *m_firstAct;
@@ -56,6 +59,7 @@ private:
     QAction *m_nextAct;
     QAction *m_lastAct;
     QComboBox *m_zoomCombo;
+    QComboBox *m_rotationCombo;
 };
 
 #endif
diff --git a/qt4/demos/pageview.cpp b/qt4/demos/pageview.cpp
index 734dacb..0dfa5e9 100644
--- a/qt4/demos/pageview.cpp
+++ b/qt4/demos/pageview.cpp
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2008-2009, Pino Toscano <[email protected]>
+ * Copyright (C) 2013, Fabio D'Urso <[email protected]>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -29,6 +30,7 @@
 PageView::PageView(QWidget *parent)
     : QScrollArea(parent)
     , m_zoom(1.0)
+    , m_rotation(0)
     , m_dpiX(QApplication::desktop()->physicalDpiX())
     , m_dpiY(QApplication::desktop()->physicalDpiY())
 {
@@ -56,7 +58,18 @@ void PageView::pageChanged(int page)
     Poppler::Page *popplerPage = document()->page(page);
     const double resX = m_dpiX * m_zoom;
     const double resY = m_dpiY * m_zoom;
-    QImage image = popplerPage->renderToImage(resX, resY);
+
+    Poppler::Page::Rotation rot;
+    if (m_rotation == 0)
+        rot = Poppler::Page::Rotate0;
+    else if (m_rotation == 90)
+        rot = Poppler::Page::Rotate90;
+    else if (m_rotation == 180)
+        rot = Poppler::Page::Rotate180;
+    else // m_rotation == 270
+        rot = Poppler::Page::Rotate270;
+
+    QImage image = popplerPage->renderToImage(resX, resY, -1, -1, -1, -1, rot);
     if (!image.isNull()) {
         m_imageLabel->resize(image.size());
         m_imageLabel->setPixmap(QPixmap::fromImage(image));
@@ -76,4 +89,13 @@ void PageView::slotZoomChanged(qreal value)
     reloadPage();
 }
 
+void PageView::slotRotationChanged(int value)
+{
+    m_rotation = value;
+    if (!document()) {
+        return;
+    }
+    reloadPage();
+}
+
 #include "pageview.moc"
diff --git a/qt4/demos/pageview.h b/qt4/demos/pageview.h
index 2f7ad61..2406502 100644
--- a/qt4/demos/pageview.h
+++ b/qt4/demos/pageview.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2008-2009, Pino Toscano <[email protected]>
+ * Copyright (C) 2013, Fabio D'Urso <[email protected]>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -39,10 +40,12 @@ public:
 
 private Q_SLOTS:
     void slotZoomChanged(qreal value);
+    void slotRotationChanged(int value);
 
 private:
     QLabel *m_imageLabel;
     qreal m_zoom;
+    int m_rotation;
     int m_dpiX;
     int m_dpiY;
 };
diff --git a/qt4/demos/viewer.cpp b/qt4/demos/viewer.cpp
index 0201eea..c34af23 100644
--- a/qt4/demos/viewer.cpp
+++ b/qt4/demos/viewer.cpp
@@ -2,6 +2,7 @@
  * Copyright (C) 2008-2009, Pino Toscano <[email protected]>
  * Copyright (C) 2008, Albert Astals Cid <[email protected]>
  * Copyright (C) 2009, Shawn Rutledge <[email protected]>
+ * Copyright (C) 2013, Fabio D'Urso <[email protected]>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -148,6 +149,7 @@ PdfViewer::PdfViewer()
     }
 
     connect(navbar, SIGNAL(zoomChanged(qreal)), view, SLOT(slotZoomChanged(qreal)));
+    connect(navbar, SIGNAL(rotationChanged(int)), view, SLOT(slotRotationChanged(int)));
 
     // activate AA by default
     m_settingsTextAAAct->setChecked(true);
-- 
1.8.1.4

>From fc88bdcf8687f69e141ff919f1cc65fb16d3c6c9 Mon Sep 17 00:00:00 2001
From: Fabio D'Urso <[email protected]>
Date: Mon, 18 Mar 2013 16:02:06 +0100
Subject: [PATCH 3/7] pdftops: Added "-rasterize" flag to force rasterization

---
 utils/pdftops.cc | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/utils/pdftops.cc b/utils/pdftops.cc
index 7f5a0ce..b3d9c11 100644
--- a/utils/pdftops.cc
+++ b/utils/pdftops.cc
@@ -22,6 +22,7 @@
 // Copyright (C) 2009, 2011, 2012 William Bader <[email protected]>
 // Copyright (C) 2010 Hib Eris <[email protected]>
 // Copyright (C) 2012 Thomas Freitag <[email protected]>
+// Copyright (C) 2013 Fabio D'Urso <[email protected]>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -86,6 +87,7 @@ static GBool doForm = gFalse;
 #if OPI_SUPPORT
 static GBool doOPI = gFalse;
 #endif
+static GBool forceRasterize = gFalse;
 static int splashResolution = 0;
 static GBool psBinary = gFalse;
 static GBool noEmbedT1Fonts = gFalse;
@@ -138,6 +140,8 @@ static const ArgDesc argDesc[] = {
   {"-opi",        argFlag,     &doOPI,          0,
    "generate OPI comments"},
 #endif
+  {"-rasterize",  argFlag,     &forceRasterize, 0,
+   "force rasterization"},
   {"-r",          argInt,      &splashResolution, 0,
    "resolution for rasterization, in DPI (default is 300)"},
   {"-binary",     argFlag,     &psBinary,       0,
@@ -392,7 +396,9 @@ int main(int argc, char *argv[]) {
 			  NULL, firstPage, lastPage, mode,
 			  paperWidth,
 			  paperHeight,
-			  duplex);
+			  duplex,
+			  0, 0, 0, 0,
+			  forceRasterize);
   if (psOut->isOk()) {
     doc->displayPages(psOut, firstPage, lastPage, 72, 72,
 		      0, noCrop, !noCrop, gTrue);
-- 
1.8.1.4

>From fba46a5c554375c4b722f5b732e4e25ea67c951a Mon Sep 17 00:00:00 2001
From: Fabio D'Urso <[email protected]>
Date: Sat, 2 Mar 2013 00:55:58 +0100
Subject: [PATCH 4/7] core: Remove geometry-related arguments from annotation
 constructors

Removed arguments from annotation constructors related to the geometry
of the annotation. This change will make it easier to support creating
annotations with flag NoRotate in the next patch (because no special
cases will be needed: coordinate conversion code will be able to always
assume that the underlying annotation object already exists).

Data that used to be taken from these arguments is now replaced by dummy
values, which can be modified using appropriate setter methods after
the annotation object is created.

Affected annotation types:
 - AnnotLine
 - AnnotTextMarkup
 - AnnotPolygon
 - AnnotInk
---
 poppler/Annot.cc              | 56 +++++++++++++------------------------------
 poppler/Annot.h               |  9 ++++---
 qt4/src/poppler-annotation.cc | 34 +++++++++++++-------------
 3 files changed, 39 insertions(+), 60 deletions(-)

diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 0e3f726..a422f5e 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -3012,21 +3012,13 @@ Object *AnnotFreeText::getAppearanceResDict(Object *dest) {
 // AnnotLine
 //------------------------------------------------------------------------
 
-AnnotLine::AnnotLine(PDFDoc *docA, PDFRectangle *rect, PDFRectangle *lRect) :
+AnnotLine::AnnotLine(PDFDoc *docA, PDFRectangle *rect) :
     AnnotMarkup(docA, rect) {
   Object obj1;
 
   type = typeLine;
   annotObj.dictSet ("Subtype", obj1.initName ("Line"));
 
-  Object obj2, obj3;
-  obj2.initArray (doc->getXRef());
-  obj2.arrayAdd (obj3.initReal (lRect->x1));
-  obj2.arrayAdd (obj3.initReal (lRect->y1));
-  obj2.arrayAdd (obj3.initReal (lRect->x2));
-  obj2.arrayAdd (obj3.initReal (lRect->y2));
-  annotObj.dictSet ("L", &obj2);
-
   initialize (docA, annotObj.getDict());
 }
 
@@ -3491,8 +3483,7 @@ Object *AnnotLine::getAppearanceResDict(Object *dest) {
 //------------------------------------------------------------------------
 // AnnotTextMarkup
 //------------------------------------------------------------------------
-AnnotTextMarkup::AnnotTextMarkup(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType,
-				 AnnotQuadrilaterals *quadPoints) :
+AnnotTextMarkup::AnnotTextMarkup(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType) :
     AnnotMarkup(docA, rect) {
   Object obj1;
 
@@ -3513,22 +3504,12 @@ AnnotTextMarkup::AnnotTextMarkup(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype
       assert (0 && "Invalid subtype for AnnotTextMarkup\n");
   }
 
-  Object obj2;
+  // Store dummy quadrilateral with null coordinates
+  Object obj2, obj3;
   obj2.initArray (doc->getXRef());
-
-  for (int i = 0; i < quadPoints->getQuadrilateralsLength(); ++i) {
-    Object obj3;
-
-    obj2.arrayAdd (obj3.initReal (quadPoints->getX1(i)));
-    obj2.arrayAdd (obj3.initReal (quadPoints->getY1(i)));
-    obj2.arrayAdd (obj3.initReal (quadPoints->getX2(i)));
-    obj2.arrayAdd (obj3.initReal (quadPoints->getY2(i)));
-    obj2.arrayAdd (obj3.initReal (quadPoints->getX3(i)));
-    obj2.arrayAdd (obj3.initReal (quadPoints->getY3(i)));
-    obj2.arrayAdd (obj3.initReal (quadPoints->getX4(i)));
-    obj2.arrayAdd (obj3.initReal (quadPoints->getY4(i)));
+  for (int i = 0; i < 4*2; ++i) {
+    obj2.arrayAdd (obj3.initReal (0));
   }
-
   annotObj.dictSet ("QuadPoints", &obj2);
 
   initialize(docA, annotObj.getDict());
@@ -5559,7 +5540,7 @@ void AnnotGeometry::draw(Gfx *gfx, GBool printing) {
 //------------------------------------------------------------------------
 // AnnotPolygon
 //------------------------------------------------------------------------
-AnnotPolygon::AnnotPolygon(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType, AnnotPath *path) :
+AnnotPolygon::AnnotPolygon(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType) :
     AnnotMarkup(docA, rect) {
   Object obj1;
 
@@ -5574,16 +5555,11 @@ AnnotPolygon::AnnotPolygon(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subTyp
       assert (0 && "Invalid subtype for AnnotGeometry\n");
   }
 
-  Object obj2;
+  // Store dummy path with one null vertex only
+  Object obj2, obj3;
   obj2.initArray (doc->getXRef());
-
-  for (int i = 0; i < path->getCoordsLength(); ++i) {
-    Object obj3;
-
-    obj2.arrayAdd (obj3.initReal (path->getX(i)));
-    obj2.arrayAdd (obj3.initReal (path->getY(i)));
-  }
-
+  obj2.arrayAdd (obj3.initReal (0));
+  obj2.arrayAdd (obj3.initReal (0));
   annotObj.dictSet ("Vertices", &obj2);
 
   initialize(docA, annotObj.getDict());
@@ -5904,7 +5880,7 @@ void AnnotCaret::setSymbol(AnnotCaretSymbol new_symbol) {
 //------------------------------------------------------------------------
 // AnnotInk
 //------------------------------------------------------------------------
-AnnotInk::AnnotInk(PDFDoc *docA, PDFRectangle *rect, AnnotPath **paths, int n_paths) :
+AnnotInk::AnnotInk(PDFDoc *docA, PDFRectangle *rect) :
     AnnotMarkup(docA, rect) {
   Object obj1;
 
@@ -5912,10 +5888,12 @@ AnnotInk::AnnotInk(PDFDoc *docA, PDFRectangle *rect, AnnotPath **paths, int n_pa
 
   annotObj.dictSet ("Subtype", obj1.initName ("Ink"));
 
-  Object obj2;
+  // Store dummy path with one null vertex only
+  Object obj2, obj3, obj4;
   obj2.initArray (doc->getXRef());
-  writeInkList(paths, n_paths, obj2.getArray());
-
+  obj2.arrayAdd (obj3.initArray (doc->getXRef()));
+  obj3.arrayAdd (obj4.initReal (0));
+  obj3.arrayAdd (obj4.initReal (0));
   annotObj.dictSet ("InkList", &obj2);
 
   initialize(docA, annotObj.getDict());
diff --git a/poppler/Annot.h b/poppler/Annot.h
index ca94429..3d3b0f6 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -960,7 +960,7 @@ public:
     captionPosTop     // Top
   };
 
-  AnnotLine(PDFDoc *docA, PDFRectangle *rect, PDFRectangle *lRect);
+  AnnotLine(PDFDoc *docA, PDFRectangle *rect);
   AnnotLine(PDFDoc *docA, Dict *dict, Object *obj);
   ~AnnotLine();
 
@@ -1025,8 +1025,7 @@ protected:
 class AnnotTextMarkup: public AnnotMarkup {
 public:
 
-  AnnotTextMarkup(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType,
-		  AnnotQuadrilaterals *quadPoints);
+  AnnotTextMarkup(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType);
   AnnotTextMarkup(PDFDoc *docA, Dict *dict, Object *obj);
   virtual ~AnnotTextMarkup();
 
@@ -1112,7 +1111,7 @@ public:
     polygonDimension   // PolygonDimension
   };
 
-  AnnotPolygon(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType, AnnotPath *path);
+  AnnotPolygon(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType);
   AnnotPolygon(PDFDoc *docA, Dict *dict, Object *obj);
   ~AnnotPolygon();
 
@@ -1187,7 +1186,7 @@ private:
 class AnnotInk: public AnnotMarkup {
 public:
 
-  AnnotInk(PDFDoc *docA, PDFRectangle *rect, AnnotPath **paths, int n_paths);
+  AnnotInk(PDFDoc *docA, PDFRectangle *rect);
   AnnotInk(PDFDoc *docA, Dict *dict, Object *obj);
   ~AnnotInk();
 
diff --git a/qt4/src/poppler-annotation.cc b/qt4/src/poppler-annotation.cc
index 5ecea80..173861e 100644
--- a/qt4/src/poppler-annotation.cc
+++ b/qt4/src/poppler-annotation.cc
@@ -2,7 +2,7 @@
  * Copyright (C) 2006, 2009, 2012 Albert Astals Cid <[email protected]>
  * Copyright (C) 2006, 2008, 2010 Pino Toscano <[email protected]>
  * Copyright (C) 2012, Guillermo A. Amaral B. <[email protected]>
- * Copyright (C) 2012, Fabio D'Urso <[email protected]>
+ * Copyright (C) 2012, 2013 Fabio D'Urso <[email protected]>
  * Copyright (C) 2012, Tobias Koenig <[email protected]>
  * Adapting code from
  *   Copyright (C) 2004 by Enrico Ros <[email protected]>
@@ -2063,22 +2063,20 @@ Annot* LineAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *
     parentDoc = doc;
 
     // Set pdfAnnot
-    AnnotPath * path = toAnnotPath(linePoints);
     PDFRectangle rect = toPdfRectangle(boundary);
     if (lineType == LineAnnotation::StraightLine)
     {
-        PDFRectangle lrect(path->getX(0), path->getY(0), path->getX(1), path->getY(1));
-        pdfAnnot = new AnnotLine(doc->doc, &rect, &lrect);
+        pdfAnnot = new AnnotLine(doc->doc, &rect);
     }
     else
     {
         pdfAnnot = new AnnotPolygon(doc->doc, &rect,
-                lineClosed ? Annot::typePolygon : Annot::typePolyLine, path );
+                lineClosed ? Annot::typePolygon : Annot::typePolyLine );
     }
-    delete path;
 
     // Set properties
     flushBaseAnnotationProperties();
+    q->setLinePoints(linePoints);
     q->setLineStartStyle(lineStartStyle);
     q->setLineEndStyle(lineEndStyle);
     q->setLineInnerColor(lineInnerColor);
@@ -2910,21 +2908,25 @@ AnnotQuadrilaterals * HighlightAnnotationPrivate::toQuadrilaterals(const QList<
 
 Annot* HighlightAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *doc)
 {
+    // Setters are defined in the public class
+    HighlightAnnotation *q = static_cast<HighlightAnnotation*>( makeAlias() );
+
     // Set page and document
     pdfPage = destPage;
     parentDoc = doc;
 
     // Set pdfAnnot
     PDFRectangle rect = toPdfRectangle(boundary);
-    AnnotQuadrilaterals * quads = toQuadrilaterals(highlightQuads);
-    pdfAnnot = new AnnotTextMarkup(destPage->getDoc(), &rect, toAnnotSubType(highlightType), quads);
-    delete quads;
+    pdfAnnot = new AnnotTextMarkup(destPage->getDoc(), &rect, toAnnotSubType(highlightType));
 
     // Set properties
     flushBaseAnnotationProperties();
+    q->setHighlightQuads(highlightQuads);
 
     highlightQuads.clear(); // Free up memory
 
+    delete q;
+
     return pdfAnnot;
 }
 
@@ -3255,25 +3257,25 @@ AnnotPath **InkAnnotationPrivate::toAnnotPaths(const QList< QLinkedList<QPointF>
 
 Annot* InkAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *doc)
 {
+    // Setters are defined in the public class
+    InkAnnotation *q = static_cast<InkAnnotation*>( makeAlias() );
+
     // Set page and document
     pdfPage = destPage;
     parentDoc = doc;
 
     // Set pdfAnnot
     PDFRectangle rect = toPdfRectangle(boundary);
-    AnnotPath **paths = toAnnotPaths(inkPaths);
-    const int pathsNumber = inkPaths.size();
-    pdfAnnot = new AnnotInk(destPage->getDoc(), &rect, paths, pathsNumber);
-
-    for (int i = 0; i < pathsNumber; ++i)
-        delete paths[i];
-    delete[] paths;
+    pdfAnnot = new AnnotInk(destPage->getDoc(), &rect);
 
     // Set properties
     flushBaseAnnotationProperties();
+    q->setInkPaths(inkPaths);
 
     inkPaths.clear(); // Free up memory
 
+    delete q;
+
     return pdfAnnot;
 }
 
-- 
1.8.1.4

>From 289563d8372802523a0503384a369275f3917082 Mon Sep 17 00:00:00 2001
From: Fabio D'Urso <[email protected]>
Date: Sat, 2 Mar 2013 19:06:49 +0100
Subject: [PATCH 5/7] qt4: FixedRotation annotations' coordinate conversion

FixedRotation(=flagNoRotate) annotations use a different coordinate
system than regular annotations. This patch implements transparent
conversion so that qt4 clients don't notice the difference.

Important! When dealing with FixedRotation annotations, poppler-qt4
clients will need to set geometry-related annotation properties in
the following order:
 1) flags (because we need to know if this is a FixedRotation
    annotation or not)
 2) boundary (because we need to know what the topleft corner is,
    so that we can construct the conversion matrix)
 3) anything else

This requirement will be documented in the next patch
---
 poppler/Annot.cc                     |   8 +++
 poppler/Annot.h                      |   2 +
 qt4/src/poppler-annotation-private.h |   7 ++-
 qt4/src/poppler-annotation.cc        | 111 +++++++++++++++++++++++++++--------
 4 files changed, 102 insertions(+), 26 deletions(-)

diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index a422f5e..8f29249 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -1519,6 +1519,14 @@ double Annot::getYMin() {
   return rect->y1;
 }
 
+double Annot::getXMax() {
+  return rect->x2;
+}
+
+double Annot::getYMax() {
+  return rect->y2;
+}
+
 void Annot::readArrayNum(Object *pdfArray, int key, double *value) {
   Object valueObject;
 
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 3d3b0f6..af29eb2 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -553,6 +553,8 @@ public:
 
   double getXMin();
   double getYMin();
+  double getXMax();
+  double getYMax();
 
   double getFontSize() { return fontSize; }
 
diff --git a/qt4/src/poppler-annotation-private.h b/qt4/src/poppler-annotation-private.h
index 3bfb5da..c755eb3 100644
--- a/qt4/src/poppler-annotation-private.h
+++ b/qt4/src/poppler-annotation-private.h
@@ -1,7 +1,7 @@
 /* poppler-annotation-private.h: qt interface to poppler
  * Copyright (C) 2007, Pino Toscano <[email protected]>
  * Copyright (C) 2012, Tobias Koenig <[email protected]>
- * Copyright (C) 2012, Fabio D'Urso <[email protected]>
+ * Copyright (C) 2012, 2013 Fabio D'Urso <[email protected]>
  * Copyright (C) 2012, Albert Astals Cid <[email protected]>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -87,9 +87,10 @@ class AnnotationPrivate : public QSharedData
 
         /* The following helpers only work if pdfPage is set */
         void flushBaseAnnotationProperties();
-        void fillMTX(double MTX[6]) const;
+        void fillNormalizationMTX(double MTX[6], int pageRotation) const;
+        void fillTransformationMTX(double MTX[6]) const;
         QRectF fromPdfRectangle(const PDFRectangle &r) const;
-        PDFRectangle toPdfRectangle(const QRectF &r) const;
+        PDFRectangle boundaryToPdfRectangle(const QRectF &r, int flags) const;
         AnnotPath * toAnnotPath(const QLinkedList<QPointF> &l) const;
 
         /* Scan page for annotations, parentId=0 searches for root annotations */
diff --git a/qt4/src/poppler-annotation.cc b/qt4/src/poppler-annotation.cc
index 173861e..f8a20d1 100644
--- a/qt4/src/poppler-annotation.cc
+++ b/qt4/src/poppler-annotation.cc
@@ -27,6 +27,7 @@
 #include <QtCore/QtAlgorithms>
 #include <QtXml/QDomElement>
 #include <QtGui/QColor>
+#include <QtGui/QTransform>
 
 // local includes
 #include "poppler-annotation.h"
@@ -198,19 +199,21 @@ void AnnotationPrivate::flushBaseAnnotationProperties()
     revisions.clear();
 }
 
-void AnnotationPrivate::fillMTX(double MTX[6]) const
+// Returns matrix to convert from user space coords (oriented according to the
+// specified rotation) to normalized coords
+void AnnotationPrivate::fillNormalizationMTX(double MTX[6], int pageRotation) const
 {
     Q_ASSERT ( pdfPage );
 
     // build a normalized transform matrix for this page at 100% scale
-    GfxState * gfxState = new GfxState( 72.0, 72.0, pdfPage->getCropBox(), pdfPage->getRotate(), gTrue );
+    GfxState * gfxState = new GfxState( 72.0, 72.0, pdfPage->getCropBox(), pageRotation, gTrue );
     double * gfxCTM = gfxState->getCTM();
 
     double w = pdfPage->getCropWidth();
     double h = pdfPage->getCropHeight();
 
     // Swap width and height if the page is rotated landscape or seascape
-    if ( pdfPage->getRotate() == 90 || pdfPage->getRotate() == 270 )
+    if ( pageRotation == 90 || pageRotation == 270 )
     {
         double t = w;
         w = h;
@@ -225,10 +228,51 @@ void AnnotationPrivate::fillMTX(double MTX[6]) const
     delete gfxState;
 }
 
+// Returns matrix to convert from user space coords (i.e. those that are stored
+// in the PDF file) to normalized coords (i.e. those that we expose to clients).
+// This method also applies a rotation around the top-left corner if the
+// FixedRotation flag is set.
+void AnnotationPrivate::fillTransformationMTX(double MTX[6]) const
+{
+    Q_ASSERT ( pdfPage );
+    Q_ASSERT ( pdfAnnot );
+
+    const int pageRotate = pdfPage->getRotate();
+
+    if ( pageRotate == 0 || ( pdfAnnot->getFlags() & Annot::flagNoRotate ) == 0 )
+    {
+        // Use the normalization matrix for this page's rotation
+        fillNormalizationMTX( MTX, pageRotate );
+    }
+    else
+    {
+        // Clients expect coordinates relative to this page's rotation, but
+        // FixedRotation annotations internally use unrotated coordinates:
+        // construct matrix to both normalize and rotate coordinates using the
+        // top-left corner as rotation pivot
+
+        double MTXnorm[6];
+        fillNormalizationMTX( MTXnorm, pageRotate );
+
+        QTransform transform( MTXnorm[0], MTXnorm[1], MTXnorm[2],
+                              MTXnorm[3], MTXnorm[4], MTXnorm[5] );
+        transform.translate( +pdfAnnot->getXMin(), +pdfAnnot->getYMax() );
+        transform.rotate( pageRotate );
+        transform.translate( -pdfAnnot->getXMin(), -pdfAnnot->getYMax() );
+
+        MTX[0] = transform.m11();
+        MTX[1] = transform.m12();
+        MTX[2] = transform.m21();
+        MTX[3] = transform.m22();
+        MTX[4] = transform.dx();
+        MTX[5] = transform.dy();
+    }
+}
+
 QRectF AnnotationPrivate::fromPdfRectangle(const PDFRectangle &r) const
 {
     double swp, MTX[6];
-    fillMTX(MTX);
+    fillTransformationMTX(MTX);
 
     QPointF p1, p2;
     XPDFReader::transform( MTX, r.x1, r.y1, p1 );
@@ -256,10 +300,20 @@ QRectF AnnotationPrivate::fromPdfRectangle(const PDFRectangle &r) const
     return QRectF( QPointF(tl_x,tl_y) , QPointF(br_x,br_y) );
 }
 
-PDFRectangle AnnotationPrivate::toPdfRectangle(const QRectF &r) const
+// This function converts a boundary QRectF in normalized coords to a
+// PDFRectangle in user coords. If the FixedRotation flag is set, this function
+// also applies a rotation around the top-left corner: it's the inverse of
+// the transformation produced by fillTransformationMTX, but we can't use
+// fillTransformationMTX here because it relies on the native annotation
+// object's boundary rect to be already set up.
+PDFRectangle AnnotationPrivate::boundaryToPdfRectangle(const QRectF &r, int flags) const
 {
+    Q_ASSERT ( pdfPage );
+
+    const int pageRotate = pdfPage->getRotate();
+
     double MTX[6];
-    fillMTX(MTX);
+    fillNormalizationMTX( MTX, pageRotate );
 
     double tl_x, tl_y, br_x, br_y, swp;
     XPDFReader::invTransform( MTX, r.topLeft(), tl_x, tl_y );
@@ -279,7 +333,18 @@ PDFRectangle AnnotationPrivate::toPdfRectangle(const QRectF &r) const
         br_y = swp;
     }
 
-    return PDFRectangle(tl_x, tl_y, br_x, br_y);
+    const int rotationFixUp = ( flags & Annotation::FixedRotation ) ? pageRotate : 0;
+    const double width = br_x - tl_x;
+    const double height = br_y - tl_y;
+
+    if ( rotationFixUp == 0 )
+        return PDFRectangle(tl_x, tl_y, br_x, br_y);
+    else if ( rotationFixUp == 90 )
+        return PDFRectangle(tl_x, tl_y - width, tl_x + height, tl_y);
+    else if ( rotationFixUp == 180 )
+        return PDFRectangle(br_x, tl_y - height, br_x + width, tl_y);
+    else // rotationFixUp == 270
+        return PDFRectangle(br_x, br_y - width, br_x + height, br_y);
 }
 
 AnnotPath * AnnotationPrivate::toAnnotPath(const QLinkedList<QPointF> &list) const
@@ -288,7 +353,7 @@ AnnotPath * AnnotationPrivate::toAnnotPath(const QLinkedList<QPointF> &list) con
     AnnotCoord **ac = (AnnotCoord **) gmallocn(count, sizeof(AnnotCoord*));
 
     double MTX[6];
-    fillMTX(MTX);
+    fillTransformationMTX(MTX);
 
     int pos = 0;
     foreach (const QPointF &p, list)
@@ -1305,7 +1370,7 @@ void Annotation::setBoundary( const QRectF &boundary )
         return;
     }
 
-    PDFRectangle rect = d->toPdfRectangle(boundary);
+    PDFRectangle rect = d->boundaryToPdfRectangle( boundary, flags() );
     d->pdfAnnot->setRect(&rect);
     d->pdfAnnot->invalidateAppearance();
 }
@@ -1601,7 +1666,7 @@ Annot* TextAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *
     parentDoc = doc;
 
     // Set pdfAnnot
-    PDFRectangle rect = toPdfRectangle(boundary);
+    PDFRectangle rect = boundaryToPdfRectangle(boundary, flags);
     if (textType == TextAnnotation::Linked)
     {
         pdfAnnot = new AnnotText(destPage->getDoc(), &rect);
@@ -1922,7 +1987,7 @@ QVector<QPointF> TextAnnotation::calloutPoints() const
         return QVector<QPointF>();
 
     double MTX[6];
-    d->fillMTX(MTX);
+    d->fillTransformationMTX(MTX);
 
     const AnnotCalloutMultiLine * callout_v6 = dynamic_cast<const AnnotCalloutMultiLine*>(callout);
     QVector<QPointF> res(callout_v6 ? 3 : 2);
@@ -1964,7 +2029,7 @@ void TextAnnotation::setCalloutPoints( const QVector<QPointF> &points )
     AnnotCalloutLine *callout;
     double x1, y1, x2, y2;
     double MTX[6];
-    d->fillMTX(MTX);
+    d->fillTransformationMTX(MTX);
 
     XPDFReader::invTransform( MTX, points[0], x1, y1 );
     XPDFReader::invTransform( MTX, points[1], x2, y2 );
@@ -2063,7 +2128,7 @@ Annot* LineAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *
     parentDoc = doc;
 
     // Set pdfAnnot
-    PDFRectangle rect = toPdfRectangle(boundary);
+    PDFRectangle rect = boundaryToPdfRectangle(boundary, flags);
     if (lineType == LineAnnotation::StraightLine)
     {
         pdfAnnot = new AnnotLine(doc->doc, &rect);
@@ -2239,7 +2304,7 @@ QLinkedList<QPointF> LineAnnotation::linePoints() const
         return d->linePoints;
 
     double MTX[6];
-    d->fillMTX(MTX);
+    d->fillTransformationMTX(MTX);
 
     QLinkedList<QPointF> res;
     if (d->pdfAnnot->getType() == Annot::typeLine)
@@ -2287,7 +2352,7 @@ void LineAnnotation::setLinePoints( const QLinkedList<QPointF> &points )
         }
         double x1, y1, x2, y2;
         double MTX[6];
-        d->fillMTX(MTX);
+        d->fillTransformationMTX(MTX);
         XPDFReader::invTransform( MTX, points.first(), x1, y1 );
         XPDFReader::invTransform( MTX, points.last(), x2, y2 );
         lineann->setVertices(x1, y1, x2, y2);
@@ -2679,7 +2744,7 @@ Annot* GeomAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *
         type = Annot::typeCircle;
 
     // Set pdfAnnot
-    PDFRectangle rect = toPdfRectangle(boundary);
+    PDFRectangle rect = boundaryToPdfRectangle(boundary, flags);
     pdfAnnot = new AnnotGeometry(destPage->getDoc(), &rect, type);
 
     // Set properties
@@ -2857,7 +2922,7 @@ QList< HighlightAnnotation::Quad > HighlightAnnotationPrivate::fromQuadrilateral
     const int quadsCount = hlquads->getQuadrilateralsLength();
 
     double MTX[6];
-    fillMTX(MTX);
+    fillTransformationMTX(MTX);
 
     for (int q = 0; q < quadsCount; ++q)
     {
@@ -2889,7 +2954,7 @@ AnnotQuadrilaterals * HighlightAnnotationPrivate::toQuadrilaterals(const QList<
             gmallocn( count, sizeof(AnnotQuadrilaterals::AnnotQuadrilateral*) );
 
     double MTX[6];
-    fillMTX(MTX);
+    fillTransformationMTX(MTX);
 
     int pos = 0;
     foreach (const HighlightAnnotation::Quad &q, quads)
@@ -2916,7 +2981,7 @@ Annot* HighlightAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentD
     parentDoc = doc;
 
     // Set pdfAnnot
-    PDFRectangle rect = toPdfRectangle(boundary);
+    PDFRectangle rect = boundaryToPdfRectangle(boundary, flags);
     pdfAnnot = new AnnotTextMarkup(destPage->getDoc(), &rect, toAnnotSubType(highlightType));
 
     // Set properties
@@ -3126,7 +3191,7 @@ Annot* StampAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData
     parentDoc = doc;
 
     // Set pdfAnnot
-    PDFRectangle rect = toPdfRectangle(boundary);
+    PDFRectangle rect = boundaryToPdfRectangle(boundary, flags);
     pdfAnnot = new AnnotStamp(destPage->getDoc(), &rect);
 
     // Set properties
@@ -3265,7 +3330,7 @@ Annot* InkAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *d
     parentDoc = doc;
 
     // Set pdfAnnot
-    PDFRectangle rect = toPdfRectangle(boundary);
+    PDFRectangle rect = boundaryToPdfRectangle(boundary, flags);
     pdfAnnot = new AnnotInk(destPage->getDoc(), &rect);
 
     // Set properties
@@ -3390,7 +3455,7 @@ QList< QLinkedList<QPointF> > InkAnnotation::inkPaths() const
         return QList< QLinkedList<QPointF> >();
 
     double MTX[6];
-    d->fillMTX(MTX);
+    d->fillTransformationMTX(MTX);
 
     const int pathsNumber = inkann->getInkListLength();
     QList< QLinkedList<QPointF> > inkPaths;
@@ -3811,7 +3876,7 @@ Annot* CaretAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData
     parentDoc = doc;
 
     // Set pdfAnnot
-    PDFRectangle rect = toPdfRectangle(boundary);
+    PDFRectangle rect = boundaryToPdfRectangle(boundary, flags);
     pdfAnnot = new AnnotCaret(destPage->getDoc(), &rect);
 
     // Set properties
-- 
1.8.1.4

>From 4755fe39d8cda4dc311dce37516b8014b01dc41e Mon Sep 17 00:00:00 2001
From: Fabio D'Urso <[email protected]>
Date: Thu, 7 Mar 2013 20:50:52 +0100
Subject: [PATCH 6/7] qt4: Some documentation about annotations

* Removed incorrect hint "Use uniqueName to test for Annotation
  equality": uniqueNames are optional and we don't actually guarantee
  uniqueness
* Added "How to add annotations" and "FixedRotation flag specifics"
  sections in the Annotation class page
* Added links from enum Annotation::SubType items to actual subclasses
* Added documentation for annotation flags that are known to work
* Added "see also" links between annotation flag and boundary
  setters/getters
* Added warning on Annotation::setPopup to tell that it's currently not
  implemented
---
 qt4/src/poppler-annotation.h | 143 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 135 insertions(+), 8 deletions(-)

diff --git a/qt4/src/poppler-annotation.h b/qt4/src/poppler-annotation.h
index 9208ca7..03f5e26 100644
--- a/qt4/src/poppler-annotation.h
+++ b/qt4/src/poppler-annotation.h
@@ -5,7 +5,7 @@
  * Copyright (C) 2010, Philip Lorenz <[email protected]>
  * Copyright (C) 2012, Tobias Koenig <[email protected]>
  * Copyright (C) 2012, Guillermo A. Amaral B. <[email protected]>
- * Copyright (C) 2012, Fabio D'Urso <[email protected]>
+ * Copyright (C) 2012, 2013 Fabio D'Urso <[email protected]>
  * Adapting code from
  *   Copyright (C) 2004 by Enrico Ros <[email protected]>
  *
@@ -101,7 +101,71 @@ class POPPLER_QT4_EXPORT AnnotationUtils
  * contained by a Page in the document.
  *
  * \warning Different Annotation objects might point to the same annotation.
- *          Use uniqueName to test for Annotation equality
+ *
+ * \section annotCreation How to add annotations
+ *
+ * Create an Annotation object of the desired subclass (for example
+ * TextAnnotation) and set its properties:
+ * @code
+ * Poppler::TextAnnotation* myann = new Poppler::TextAnnotation(Poppler::TextAnnotation::InPlace);
+ * myann->setBoundary(QRectF(0.1, 0.1, 0.2, 0.2)); // normalized coordinates: (0,0) is top-left, (1,1) is bottom-right
+ * myann->setContents("Hello, world!");
+ * @endcode
+ * \note Always set a boundary rectangle, or nothing will be shown!
+ *
+ * Obtain a pointer to the Page where you want to add the annotation (refer to
+ * \ref req for instructions) and add the annotation:
+ * @code
+ * Poppler::Page* mypage = ...;
+ * mypage->addAnnotation(myann);
+ * @endcode
+ *
+ * You can keep on editing the annotation after it has been added to the page:
+ * @code
+ * myann->setContents("World, hello!"); // Let's change text...
+ * myann->setAuthor("Your name here");  // ...and set an author too
+ * @endcode
+ *
+ * When you're done with editing the annotation, you must destroy the Annotation
+ * object:
+ * @code
+ * delete myann;
+ * @endcode
+ *
+ * Use the PDFConverter class to save the modified document.
+ *
+ * \section annotFixedRotation FixedRotation flag specifics
+ *
+ * According to the PDF specification, annotations whose
+ * Annotation::FixedRotation flag is set must always be shown in their original
+ * orientation, no matter what the current rendering rotation or the page's
+ * Page::orientation() values are. In comparison with regular annotations, such
+ * annotations should therefore be transformed by an extra rotation at rendering
+ * time to "undo" such context-related rotations, which is equal to
+ * <code>-(rendering_rotation + page_orientation)</code>. The rotation pivot
+ * is the top-left corner of the boundary rectangle.
+ *
+ * In practice, %Poppler's \ref Page::renderToImage only "unrotates" the
+ * page orientation, and does <b>not</b> unrotate the rendering rotation.
+ * This ensures consistent renderings at different Page::Rotation values:
+ * annotations are always positioned as if they were being positioned at the
+ * default page orientation.
+ *
+ * Just like regular annotations, %Poppler Qt4 exposes normalized coordinates
+ * relative to the page's default orientation. However, behind the scenes, the
+ * coordinate system is different and %Poppler transparently transforms each
+ * shape. If you never call either Annotation::setFlags or
+ * Annotation::setBoundary, you don't need to worry about this; but if you do
+ * call them, then you need to adhere to the following rules:
+ *  - Whenever you toggle the Annotation::FixedRotation flag, you <b>must</b>
+ *    set again the boundary rectangle first, and then you <b>must</b> set
+ *    again any other geometry-related property.
+ *  - Whenever you modify the boundary rectangle of an annotation whose
+ *    Annotation::FixedRotation flag is set, you <b>must</b> set again any other
+ *    geometry-related property.
+ *
+ * These two rules are necessary to make %Poppler's transparent coordinate
+ * conversion work properly.
  */
 class POPPLER_QT4_EXPORT Annotation
 {
@@ -111,12 +175,50 @@ class POPPLER_QT4_EXPORT Annotation
 
   public:
     // enum definitions
+    /**
+     * Annotation subclasses
+     *
+     * \sa subType()
+     */
     // WARNING!!! oKular uses that very same values so if you change them notify the author!
-    enum SubType { AText = 1, ALine = 2, AGeom = 3, AHighlight = 4, AStamp = 5,
-                   AInk = 6, ALink = 7, ACaret = 8, AFileAttachment = 9, ASound = 10,
-                   AMovie = 11, AScreen = 12 /** \since 0.20 */, AWidget = 13 /** \since 0.22 */, A_BASE = 0 };
-    enum Flag { Hidden = 1, FixedSize = 2, FixedRotation = 4, DenyPrint = 8,
-                DenyWrite = 16, DenyDelete = 32, ToggleHidingOnMouse = 64, External = 128 };
+    enum SubType
+    {
+        AText = 1,            ///< TextAnnotation
+        ALine = 2,            ///< LineAnnotation
+        AGeom = 3,            ///< GeomAnnotation
+        AHighlight = 4,       ///< HighlightAnnotation
+        AStamp = 5,           ///< StampAnnotation
+        AInk = 6,             ///< InkAnnotation
+        ALink = 7,            ///< LinkAnnotation
+        ACaret = 8,           ///< CaretAnnotation
+        AFileAttachment = 9,  ///< FileAttachmentAnnotation
+        ASound = 10,          ///< SoundAnnotation
+        AMovie = 11,          ///< MovieAnnotation
+        AScreen = 12,         ///< ScreenAnnotation \since 0.20
+        AWidget = 13,         ///< WidgetAnnotation \since 0.22
+        A_BASE = 0
+    };
+
+    /**
+     * Annotation flags
+     *
+     * They can be OR'd together (e.g. Annotation::FixedRotation | Annotation::DenyPrint).
+     *
+     * \sa flags(), setFlags(int)
+     */
+    // NOTE: Only flags that are known to work are documented
+    enum Flag
+    {
+        Hidden = 1,                ///< Do not display or print the annotation
+        FixedSize = 2,
+        FixedRotation = 4,         ///< Do not rotate the annotation according to page orientation and rendering rotation \warning Extra care is needed with this flag: see \ref annotFixedRotation
+        DenyPrint = 8,             ///< Do not print the annotation
+        DenyWrite = 16,
+        DenyDelete = 32,
+        ToggleHidingOnMouse = 64,
+        External = 128
+    };
+
     enum LineStyle { Solid = 1, Dashed = 2, Beveled = 4, Inset = 8, Underline = 16 };
     enum LineEffect { NoEffect = 1, Cloudy = 2};
     enum RevScope { Root = 0 /** \since 0.20 */, Reply = 1, Group = 2, Delete = 4 };
@@ -151,10 +253,35 @@ class POPPLER_QT4_EXPORT Annotation
     QDateTime creationDate() const;
     void setCreationDate( const QDateTime &date );
 
+    /**
+     * Returns this annotation's flags
+     *
+     * \sa Flag, setFlags(int)
+     */
     int flags() const;
+    /**
+     * Sets this annotation's flags
+     *
+     * \sa Flag, flags(), \ref annotFixedRotation
+     */
     void setFlags( int flags );
 
+    /**
+     * Returns this annotation's boundary rectangle in normalized coordinates
+     *
+     * \sa setBoundary(const QRectF&)
+     */
     QRectF boundary() const;
+    /**
+     * Sets this annotation's boundary rectangle
+     *
+     * The boundary rectangle is the smallest rectangle that contains the
+     * annotation.
+     *
+     * \warning This property is mandatory: you must always set this.
+     *
+     * \sa boundary(), \ref annotFixedRotation
+     */
     void setBoundary( const QRectF &boundary );
 
     /**
@@ -240,7 +367,7 @@ class POPPLER_QT4_EXPORT Annotation
 
     /// \since 0.20
     Popup popup() const;
-    /// \since 0.20
+    /// \warning Currently does nothing \since 0.20
     void setPopup( const Popup& popup );
 
     /// \cond PRIVATE
-- 
1.8.1.4

>From a11f0d5e12c84a51186a95d3388a09b538ee26bb Mon Sep 17 00:00:00 2001
From: Fabio D'Urso <[email protected]>
Date: Thu, 7 Mar 2013 00:20:15 +0100
Subject: [PATCH 7/7] qt4: Free some temporary memory in
 TextAnnotationPrivate::createNativeAnnot

There's no need to keep this buffer around after it has been flushed
---
 qt4/src/poppler-annotation.cc | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/qt4/src/poppler-annotation.cc b/qt4/src/poppler-annotation.cc
index f8a20d1..3edcbdb 100644
--- a/qt4/src/poppler-annotation.cc
+++ b/qt4/src/poppler-annotation.cc
@@ -1687,6 +1687,8 @@ Annot* TextAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *
 
     delete q;
 
+    inplaceCallout.clear(); // Free up memory
+
     return pdfAnnot;
 }
 
-- 
1.8.1.4

_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler

Reply via email to