Adam, On Wednesday, April 03, 2013 06:41:10 PM Fabio D'Urso wrote: > [snip] > So here's what I am going to do: > > 1) Edit rendering patches so that they only look at rotation A. > Unfortunatly I'll be preparing for an exam in the next two weeks. I'll try > to post a preliminary version as soon as I can.
Modified patches attached. They are not final yet: I still have to update the documentation in the second-to-last patch. Unless we find bugs / suggestions, the code is final. > 2) Add extra rotation and scale arguments (maybe in a container class, > haven't decided yet) to all Annotation getter/setters. > They will default to 0°/100%, which will correspond to the same position you > get in renderToImage. I'll do this after the exam. Hope this new set of patches enables you to start your work :) P.S.: Now that we don't have context-dependent rotations, the issue I described in the original post no longer exists and the PSOutputDev patch is not needed anymore, so I've removed it. When you print, you now always get the same layout as the renderToImage with rotate=0. Fabio
>From 2950c53baf62b708a06aff2e67f32d6c343b8c0e 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 | 1 + poppler/Gfx.cc | 41 +++++++++++++++++++++++++++++++++++++---- poppler/Gfx.h | 3 ++- 4 files changed, 76 insertions(+), 24 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..9a10fe0 100644 --- a/poppler/Annot.h +++ b/poppler/Annot.h @@ -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 32bd523afd38f22b369b8b4249153d6dc0faf5ff 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 2cc47423340c77e9fe100c8212d9a864b469e52d 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 728ad63e2b5a756707f6237161558be52d10b13d 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 | 11 ++++----- qt4/src/poppler-annotation.cc | 34 +++++++++++++------------- 3 files changed, 40 insertions(+), 61 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 9a10fe0..3d3b0f6 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]> // @@ -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 8b449605470b3d67c4e73205b026a2e7d79b6f4a 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 04ddf2205cb506ecc37206055bdf4420aa7506db 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 issues" 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 | 135 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 127 insertions(+), 8 deletions(-) diff --git a/qt4/src/poppler-annotation.h b/qt4/src/poppler-annotation.h index 9208ca7..b80b9c6 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,63 @@ 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 issues + * + * Annotations whose Annotation::FixedRotation flag is set are always + * shown in their original orientation, no matter what the page's + * Page::orientation() value is or the requested rendering rotation (see + * \ref Page::renderToImage). In order to preserve the original orientation, the + * annotation is rotated during rendering around the top-left corner of its + * boundary rectangle. + * + * 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 converts each + * point. 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 +167,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 +245,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 +359,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 e18510fc045287968dec0eb1ef4bcf8a6eba2960 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
