Last active
February 23, 2018 13:28
-
-
Save haxtibal/eab9320d43e47dfefe47249ee1e6d01a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/poppler/Annot.cc b/poppler/Annot.cc | |
| index 15c86a05..8cbeb6a5 100644 | |
| --- a/poppler/Annot.cc | |
| +++ b/poppler/Annot.cc | |
| @@ -1565,40 +1565,54 @@ void Annot::incRefCnt() { | |
| annotLocker(); | |
| refCnt++; | |
| } | |
| void Annot::decRefCnt() { | |
| #ifdef MULTITHREADED | |
| gLockMutex(&mutex); | |
| #endif | |
| if (--refCnt == 0) { | |
| #ifdef MULTITHREADED | |
| gUnlockMutex(&mutex); | |
| #endif | |
| delete this; | |
| return; | |
| } | |
| #ifdef MULTITHREADED | |
| gUnlockMutex(&mutex); | |
| #endif | |
| } | |
| +Gfx* Annot::createGfx(OutputDev* output, double hDPI, double vDPI, double width, double height) { | |
| + int pageNum = getPageNum(); | |
| + Dict *resDict = getDoc()->getPage(pageNum)->getResourceDict(); | |
| + PDFRectangle box(0, 0, width, height); | |
| + int rotate = 0; | |
| + GBool (*abortCheckCbkA)(void *data) = NULL; | |
| + void *abortCheckCbkDataA = NULL; | |
| + XRef *xrefA = getXRef(); | |
| + Gfx *gfx = new Gfx(doc, output, pageNum, resDict, | |
| + hDPI, vDPI, &box, (PDFRectangle *)NULL, | |
| + rotate, abortCheckCbkA, abortCheckCbkDataA, xrefA); | |
| + return gfx; | |
| +} | |
| + | |
| Annot::~Annot() { | |
| delete rect; | |
| delete contents; | |
| if (name) | |
| delete name; | |
| if (modified) | |
| delete modified; | |
| delete appearStreams; | |
| delete appearBBox; | |
| if (appearState) | |
| delete appearState; | |
| if (border) | |
| delete border; | |
| if (color) | |
| @@ -1803,49 +1817,95 @@ GBool Annot::isVisible(GBool printing) { | |
| if (optContentConfig) { | |
| if (! optContentConfig->optContentIsVisible(&oc)) | |
| return gFalse; | |
| } | |
| return gTrue; | |
| } | |
| int Annot::getRotation() const | |
| { | |
| Page *pageobj = doc->getPage(page); | |
| assert(pageobj != nullptr); | |
| if (flags & flagNoRotate) { | |
| return (360 - pageobj->getRotate()) % 360; | |
| } else { | |
| return 0; | |
| } | |
| } | |
| -void Annot::draw(Gfx *gfx, GBool printing) { | |
| +void Annot::draw(Gfx *gfx, GBool printing, GBool drawAtOrigin) { | |
| + Object obj; | |
| + PDFRectangle drawRect; | |
| + | |
| + if (!isVisible (printing)) | |
| + return; | |
| + | |
| annotLocker(); | |
| + | |
| + makeAppearance(obj, drawRect, gfx->getXRef()); | |
| + | |
| + if (drawAtOrigin) { | |
| + drawRect.translate(-drawRect.x1, -drawRect.y1); | |
| + } | |
| + | |
| + drawAppearance(gfx, obj, drawRect); | |
| +} | |
| + | |
| +/* Only this Annot::draw overload can create a Gfx with correct size, because: | |
| + * -Size of Gfx must be given in Ctor Gfx::Gfx(...box...). Size can't be changed afterwards. | |
| + * -We don't know the actual size before makeAppearance (NB: Because drawRect may be != Annot::rect.) | |
| + * Which version of Annot::draw to use? */ | |
| +void Annot::draw(OutputDev *outputDev, GBool printing, double hDPI, double vDPI, GBool drawAtOrigin) { | |
| + Gfx *gfx; | |
| + Object obj; | |
| + PDFRectangle drawRect; | |
| + | |
| if (!isVisible (printing)) | |
| return; | |
| + annotLocker(); | |
| - // draw the appearance stream | |
| - Object obj = appearance.fetch(gfx->getXRef()); | |
| + /* 1st part of templated algorithm: recreate appearance to resulting form object and size rectangle */ | |
| + makeAppearance(obj, drawRect, getXRef()); | |
| + | |
| + /* Hook in here to respect size of new drawRect, which may be != Annot::rect. */ | |
| + gfx = createGfx(outputDev, hDPI, vDPI, drawRect.x2 - drawRect.x1, drawRect.y2 - drawRect.y1); | |
| + if (drawAtOrigin) { | |
| + /* Shift to origin. */ | |
| + drawRect.translate(-drawRect.x1, -drawRect.y1); | |
| + } | |
| + | |
| + /* 2nd part of templated algorithm: Draw appearance */ | |
| + drawAppearance(gfx, obj, drawRect); | |
| + | |
| + delete gfx; | |
| +} | |
| + | |
| +void Annot::makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) { | |
| + obj = appearance.fetch(xref); | |
| + drawRect = *Annot::rect; | |
| +} | |
| + | |
| +void Annot::drawAppearance(Gfx *gfx, Object& obj, const PDFRectangle& drawRect) { | |
| gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, | |
| - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); | |
| + drawRect.x1, drawRect.y1, drawRect.x2, drawRect.y2, getRotation()); | |
| } | |
| //------------------------------------------------------------------------ | |
| // AnnotPopup | |
| //------------------------------------------------------------------------ | |
| AnnotPopup::AnnotPopup(PDFDoc *docA, PDFRectangle *rect) : | |
| Annot(docA, rect) { | |
| type = typePopup; | |
| annotObj.dictSet ("Subtype", Object(objName, "Popup")); | |
| initialize (docA, annotObj.getDict()); | |
| } | |
| AnnotPopup::AnnotPopup(PDFDoc *docA, Object *dictObject, Object *obj) : | |
| Annot(docA, dictObject, obj) { | |
| type = typePopup; | |
| initialize(docA, dictObject->getDict()); | |
| } | |
| @@ -2408,52 +2468,49 @@ void AnnotText::setIcon(GooString *new_icon) { | |
| "0.729412 0.741176 0.713725 RG 18 6 m 6 18 l S\n" \ | |
| "6 6 m 18 18 l S\n" | |
| #define ANNOT_TEXT_AP_CIRCLE \ | |
| "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n" \ | |
| "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n" \ | |
| "l 1 21.523 2.477 23 4.301 23 c h\n" \ | |
| "4.301 23 m f\n" \ | |
| "0.533333 0.541176 0.521569 RG 2.5 w\n" \ | |
| "1 J\n" \ | |
| "1 j\n" \ | |
| "[] 0.0 d\n" \ | |
| "4 M 19.5 11.5 m 19.5 7.359 16.141 4 12 4 c 7.859 4 4.5 7.359 4.5 11.5 c 4.5\n" \ | |
| "15.641 7.859 19 12 19 c 16.141 19 19.5 15.641 19.5 11.5 c h\n" \ | |
| "19.5 11.5 m S\n" \ | |
| "0.729412 0.741176 0.713725 RG 19.5 12.5 m 19.5 8.359 16.141 5 12 5 c\n" \ | |
| "7.859 5 4.5 8.359 4.5 12.5 c 4.5\n" \ | |
| "16.641 7.859 20 12 20 c 16.141 20 19.5 16.641 19.5 12.5 c h\n" \ | |
| "19.5 12.5 m S\n" | |
| -void AnnotText::draw(Gfx *gfx, GBool printing) { | |
| +void AnnotText::makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) { | |
| double ca = 1; | |
| - if (!isVisible (printing)) | |
| - return; | |
| - | |
| - annotLocker(); | |
| + /* If there was no embedded appearance stream in document, | |
| + * generate a in-memory default appearance stream. | |
| + * Else use the appearance stream from PDF. */ | |
| if (appearance.isNull()) { | |
| ca = opacity; | |
| - | |
| appearBuf = new GooString (); | |
| - | |
| appearBuf->append ("q\n"); | |
| if (color) | |
| setColor(color, gTrue); | |
| else | |
| appearBuf->append ("1 1 1 rg\n"); | |
| if (!icon->cmp("Note")) | |
| appearBuf->append (ANNOT_TEXT_AP_NOTE); | |
| else if (!icon->cmp("Comment")) | |
| appearBuf->append (ANNOT_TEXT_AP_COMMENT); | |
| else if (!icon->cmp("Key")) | |
| appearBuf->append (ANNOT_TEXT_AP_KEY); | |
| else if (!icon->cmp("Help")) | |
| appearBuf->append (ANNOT_TEXT_AP_HELP); | |
| else if (!icon->cmp("NewParagraph")) | |
| appearBuf->append (ANNOT_TEXT_AP_NEW_PARAGRAPH); | |
| else if (!icon->cmp("Paragraph")) | |
| appearBuf->append (ANNOT_TEXT_AP_PARAGRAPH); | |
| else if (!icon->cmp("Insert")) | |
| appearBuf->append (ANNOT_TEXT_AP_INSERT); | |
| else if (!icon->cmp("Cross")) | |
| @@ -2463,50 +2520,46 @@ void AnnotText::draw(Gfx *gfx, GBool printing) { | |
| appearBuf->append ("Q\n"); | |
| // Force 24x24 rectangle | |
| PDFRectangle fixedRect(rect->x1, rect->y2 - 24, rect->x1 + 24, rect->y2); | |
| appearBBox = new AnnotAppearanceBBox(&fixedRect); | |
| double bbox[4]; | |
| appearBBox->getBBoxRect(bbox); | |
| if (ca == 1) { | |
| appearance = createForm(bbox, gFalse, nullptr); | |
| } else { | |
| Object aStream = createForm(bbox, gTrue, nullptr); | |
| delete appearBuf; | |
| appearBuf = new GooString ("/GS0 gs\n/Fm0 Do"); | |
| Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr); | |
| appearance = createForm(bbox, gFalse, resDict); | |
| } | |
| delete appearBuf; | |
| } | |
| - // draw the appearance stream | |
| - Object obj = appearance.fetch(gfx->getXRef()); | |
| + obj = appearance.fetch(xref); | |
| if (appearBBox) { | |
| - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, | |
| - appearBBox->getPageXMin(), appearBBox->getPageYMin(), | |
| - appearBBox->getPageXMax(), appearBBox->getPageYMax(), | |
| - getRotation()); | |
| + drawRect = PDFRectangle(appearBBox->getPageXMin(), appearBBox->getPageYMin(), | |
| + appearBBox->getPageXMax(), appearBBox->getPageYMax()); | |
| } else { | |
| - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, | |
| - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); | |
| + drawRect = *rect; | |
| } | |
| } | |
| //------------------------------------------------------------------------ | |
| // AnnotLink | |
| //------------------------------------------------------------------------ | |
| AnnotLink::AnnotLink(PDFDoc *docA, PDFRectangle *rect) : | |
| Annot(docA, rect) { | |
| type = typeLink; | |
| annotObj.dictSet ("Subtype", Object(objName, "Link")); | |
| initialize (docA, annotObj.getDict()); | |
| } | |
| AnnotLink::AnnotLink(PDFDoc *docA, Object *dictObject, Object *obj) : | |
| Annot(docA, dictObject, obj) { | |
| type = typeLink; | |
| initialize (docA, dictObject->getDict()); | |
| } | |
| @@ -2563,49 +2616,43 @@ void AnnotLink::initialize(PDFDoc *docA, Dict *dict) { | |
| uriAction = NULL; | |
| } | |
| obj1.free(); | |
| */ | |
| obj1 = dict->lookup("QuadPoints"); | |
| if (obj1.isArray()) { | |
| quadrilaterals = new AnnotQuadrilaterals(obj1.getArray(), rect); | |
| } else { | |
| quadrilaterals = nullptr; | |
| } | |
| obj1 = dict->lookup("BS"); | |
| if (obj1.isDict()) { | |
| delete border; | |
| border = new AnnotBorderBS(obj1.getDict()); | |
| } else if (!border) { | |
| border = new AnnotBorderBS(); | |
| } | |
| } | |
| -void AnnotLink::draw(Gfx *gfx, GBool printing) { | |
| - if (!isVisible (printing)) | |
| - return; | |
| - | |
| - annotLocker(); | |
| - // draw the appearance stream | |
| - Object obj = appearance.fetch(gfx->getXRef()); | |
| - gfx->drawAnnot(&obj, border, color, | |
| - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); | |
| +void AnnotLink::makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) { | |
| + obj = appearance.fetch(xref); | |
| + drawRect = *rect; | |
| } | |
| //------------------------------------------------------------------------ | |
| // AnnotFreeText | |
| //------------------------------------------------------------------------ | |
| AnnotFreeText::AnnotFreeText(PDFDoc *docA, PDFRectangle *rect, GooString *da) : | |
| AnnotMarkup(docA, rect) { | |
| type = typeFreeText; | |
| annotObj.dictSet ("Subtype", Object(objName, "FreeText")); | |
| annotObj.dictSet("DA", Object(da->copy())); | |
| initialize (docA, annotObj.getDict()); | |
| } | |
| AnnotFreeText::AnnotFreeText(PDFDoc *docA, Object *dictObject, Object *obj) : | |
| AnnotMarkup(docA, dictObject, obj) { | |
| type = typeFreeText; | |
| initialize(docA, dictObject->getDict()); | |
| } | |
| @@ -2940,53 +2987,47 @@ void AnnotFreeText::generateFreeTextAppearance() | |
| appearBuf->append ("ET Q\n"); | |
| double bbox[4]; | |
| bbox[0] = bbox[1] = 0; | |
| bbox[2] = rect->x2 - rect->x1; | |
| bbox[3] = rect->y2 - rect->y1; | |
| if (ca == 1) { | |
| appearance = createForm(bbox, gFalse, fontResDict); | |
| } else { | |
| Object aStream = createForm(bbox, gTrue, fontResDict); | |
| delete appearBuf; | |
| appearBuf = new GooString ("/GS0 gs\n/Fm0 Do"); | |
| Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr); | |
| appearance = createForm(bbox, gFalse, resDict); | |
| } | |
| delete appearBuf; | |
| } | |
| -void AnnotFreeText::draw(Gfx *gfx, GBool printing) { | |
| - if (!isVisible (printing)) | |
| - return; | |
| - | |
| - annotLocker(); | |
| +void AnnotFreeText::makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) { | |
| if (appearance.isNull()) { | |
| generateFreeTextAppearance(); | |
| } | |
| - // draw the appearance stream | |
| - Object obj = appearance.fetch(gfx->getXRef()); | |
| - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, | |
| - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); | |
| + obj = appearance.fetch(xref); | |
| + drawRect = *rect; | |
| } | |
| // Before retrieving the res dict, regenerate the appearance stream if needed, | |
| // because AnnotFreeText::draw needs to store font info in the res dict | |
| Object AnnotFreeText::getAppearanceResDict() { | |
| if (appearance.isNull()) { | |
| generateFreeTextAppearance(); | |
| } | |
| return Annot::getAppearanceResDict(); | |
| } | |
| //------------------------------------------------------------------------ | |
| // AnnotLine | |
| //------------------------------------------------------------------------ | |
| AnnotLine::AnnotLine(PDFDoc *docA, PDFRectangle *rect) : | |
| AnnotMarkup(docA, rect) { | |
| type = typeLine; | |
| annotObj.dictSet ("Subtype", Object(objName, "Line")); | |
| @@ -3378,59 +3419,52 @@ void AnnotLine::generateLineAppearance() | |
| appearBBox->extendTo (tx, ty); | |
| } | |
| appearBuf->append ("Q\n"); | |
| double bbox[4]; | |
| appearBBox->getBBoxRect(bbox); | |
| if (ca == 1) { | |
| appearance = createForm(bbox, gFalse, fontResDict); | |
| } else { | |
| Object aStream = createForm(bbox, gTrue, fontResDict); | |
| delete appearBuf; | |
| appearBuf = new GooString ("/GS0 gs\n/Fm0 Do"); | |
| Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr); | |
| appearance = createForm(bbox, gFalse, resDict); | |
| } | |
| delete appearBuf; | |
| } | |
| -void AnnotLine::draw(Gfx *gfx, GBool printing) { | |
| - if (!isVisible (printing)) | |
| - return; | |
| - | |
| - annotLocker(); | |
| +void AnnotLine::makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) { | |
| if (appearance.isNull()) { | |
| generateLineAppearance(); | |
| } | |
| // draw the appearance stream | |
| - Object obj = appearance.fetch(gfx->getXRef()); | |
| + obj = appearance.fetch(xref); | |
| if (appearBBox) { | |
| - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, | |
| - appearBBox->getPageXMin(), appearBBox->getPageYMin(), | |
| - appearBBox->getPageXMax(), appearBBox->getPageYMax(), | |
| - getRotation()); | |
| + drawRect = PDFRectangle(appearBBox->getPageXMin(), appearBBox->getPageYMin(), | |
| + appearBBox->getPageXMax(), appearBBox->getPageYMax()); | |
| } else { | |
| - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, | |
| - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); | |
| + drawRect = *rect; | |
| } | |
| } | |
| // Before retrieving the res dict, regenerate the appearance stream if needed, | |
| // because AnnotLine::draw may need to store font info in the res dict | |
| Object AnnotLine::getAppearanceResDict() { | |
| if (appearance.isNull()) { | |
| generateLineAppearance(); | |
| } | |
| return Annot::getAppearanceResDict(); | |
| } | |
| //------------------------------------------------------------------------ | |
| // AnnotTextMarkup | |
| //------------------------------------------------------------------------ | |
| AnnotTextMarkup::AnnotTextMarkup(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType) : | |
| AnnotMarkup(docA, rect) { | |
| switch (subType) { | |
| case typeHighlight: | |
| annotObj.dictSet ("Subtype", Object(objName, "Highlight")); | |
| @@ -3525,48 +3559,44 @@ void AnnotTextMarkup::setQuadrilaterals(AnnotQuadrilaterals *quadPoints) { | |
| Array *a = new Array(xref); | |
| for (int i = 0; i < quadPoints->getQuadrilateralsLength(); ++i) { | |
| a->add(Object(quadPoints->getX1(i))); | |
| a->add(Object(quadPoints->getY1(i))); | |
| a->add(Object(quadPoints->getX2(i))); | |
| a->add(Object(quadPoints->getY2(i))); | |
| a->add(Object(quadPoints->getX3(i))); | |
| a->add(Object(quadPoints->getY3(i))); | |
| a->add(Object(quadPoints->getX4(i))); | |
| a->add(Object(quadPoints->getY4(i))); | |
| } | |
| delete quadrilaterals; | |
| quadrilaterals = new AnnotQuadrilaterals(a, rect); | |
| annotObj.dictSet ("QuadPoints", Object(a)); | |
| invalidateAppearance(); | |
| } | |
| -void AnnotTextMarkup::draw(Gfx *gfx, GBool printing) { | |
| +void AnnotTextMarkup::makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) { | |
| double ca = 1; | |
| int i; | |
| - if (!isVisible (printing)) | |
| - return; | |
| - | |
| - annotLocker(); | |
| if (appearance.isNull() || type == typeHighlight) { | |
| GBool blendMultiply = gTrue; | |
| ca = opacity; | |
| appearBuf = new GooString (); | |
| appearBuf->append ("q\n"); | |
| /* Adjust BBox */ | |
| delete appearBBox; | |
| appearBBox = new AnnotAppearanceBBox(rect); | |
| for (i = 0; i < quadrilaterals->getQuadrilateralsLength(); ++i) { | |
| appearBBox->extendTo (quadrilaterals->getX1(i) - rect->x1, quadrilaterals->getY1(i) - rect->y1); | |
| appearBBox->extendTo (quadrilaterals->getX2(i) - rect->x1, quadrilaterals->getY2(i) - rect->y1); | |
| appearBBox->extendTo (quadrilaterals->getX3(i) - rect->x1, quadrilaterals->getY3(i) - rect->y1); | |
| appearBBox->extendTo (quadrilaterals->getX4(i) - rect->x1, quadrilaterals->getY4(i) - rect->y1); | |
| } | |
| switch (type) { | |
| case typeUnderline: | |
| if (color) { | |
| @@ -3683,50 +3713,46 @@ void AnnotTextMarkup::draw(Gfx *gfx, GBool printing) { | |
| bbox[2] = appearBBox->getPageXMax(); | |
| bbox[3] = appearBBox->getPageYMax(); | |
| aStream = createForm(bbox, gTrue, nullptr); | |
| delete appearBuf; | |
| appearBuf = new GooString ("/GS0 gs\n/Fm0 Do"); | |
| Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", 1, blendMultiply ? "Multiply" : nullptr); | |
| if (ca == 1) { | |
| appearance = createForm(bbox, gFalse, resDict); | |
| } else { | |
| aStream = createForm(bbox, gTrue, resDict); | |
| delete appearBuf; | |
| appearBuf = new GooString ("/GS0 gs\n/Fm0 Do"); | |
| Dict *resDict2 = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr); | |
| appearance = createForm(bbox, gFalse, resDict2); | |
| } | |
| delete appearBuf; | |
| } | |
| - // draw the appearance stream | |
| - Object obj = appearance.fetch(gfx->getXRef()); | |
| + obj = appearance.fetch(xref); | |
| if (appearBBox) { | |
| - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, | |
| - appearBBox->getPageXMin(), appearBBox->getPageYMin(), | |
| - appearBBox->getPageXMax(), appearBBox->getPageYMax(), | |
| - getRotation()); | |
| + drawRect = PDFRectangle(appearBBox->getPageXMin(), appearBBox->getPageYMin(), | |
| + appearBBox->getPageXMax(), appearBBox->getPageYMax()); | |
| } else { | |
| - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, | |
| - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); | |
| + drawRect = *rect; | |
| } | |
| } | |
| //------------------------------------------------------------------------ | |
| // AnnotWidget | |
| //------------------------------------------------------------------------ | |
| AnnotWidget::AnnotWidget(PDFDoc *docA, Object *dictObject, Object *obj) : | |
| Annot(docA, dictObject, obj) { | |
| type = typeWidget; | |
| field = nullptr; | |
| initialize(docA, dictObject->getDict()); | |
| } | |
| AnnotWidget::AnnotWidget(PDFDoc *docA, Object *dictObject, Object *obj, FormField *fieldA) : | |
| Annot(docA, dictObject, obj) { | |
| type = typeWidget; | |
| field = fieldA; | |
| initialize(docA, dictObject->getDict()); | |
| } | |
| @@ -4916,80 +4942,84 @@ void AnnotWidget::updateAppearanceStream() | |
| // create a new AP dictionary containing the new appearance stream. | |
| // Otherwise, just update the stream we had created previously. | |
| if (updatedAppearanceStream.num == -1) { | |
| // Write the appearance stream | |
| updatedAppearanceStream = xref->addIndirectObject(&obj1); | |
| // Write the AP dictionary | |
| obj1 = Object(new Dict(xref)); | |
| obj1.dictAdd(copyString("N"), Object(updatedAppearanceStream.num, updatedAppearanceStream.gen)); | |
| // Update our internal pointers to the appearance dictionary | |
| appearStreams = new AnnotAppearance(doc, &obj1); | |
| update("AP", std::move(obj1)); | |
| } else { | |
| // Replace the existing appearance stream | |
| xref->setModifiedObject(&obj1, updatedAppearanceStream); | |
| } | |
| } | |
| -void AnnotWidget::draw(Gfx *gfx, GBool printing) { | |
| - if (!isVisible (printing)) | |
| - return; | |
| - | |
| - annotLocker(); | |
| +void AnnotWidget::makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) { | |
| addDingbatsResource = gFalse; | |
| // Only construct the appearance stream when | |
| // - annot doesn't have an AP or | |
| // - NeedAppearances is true | |
| if (field) { | |
| if (appearance.isNull() || (form && form->getNeedAppearances())) | |
| generateFieldAppearance(); | |
| } | |
| // draw the appearance stream | |
| - Object obj = appearance.fetch(gfx->getXRef()); | |
| + obj = appearance.fetch(xref); | |
| + drawRect = *rect; | |
| if (addDingbatsResource) { | |
| // We are forcing ZaDb but the font does not exist | |
| // so create a fake one | |
| - Dict *fontDict = new Dict(gfx->getXRef()); | |
| + Dict *fontDict = new Dict(xref); | |
| fontDict->add(copyString("BaseFont"), Object(objName, "ZapfDingbats")); | |
| fontDict->add(copyString("Subtype"), Object(objName, "Type1")); | |
| - Dict *fontsDict = new Dict(gfx->getXRef()); | |
| + Dict *fontsDict = new Dict(xref); | |
| fontsDict->add(copyString("ZaDb"), Object(fontDict)); | |
| - Dict *dict = new Dict(gfx->getXRef()); | |
| - dict->add(copyString("Font"), Object(fontsDict)); | |
| - gfx->pushResources(dict); | |
| - delete dict; | |
| + fontResourceDict = new Dict(xref); | |
| + fontResourceDict->add(copyString("Font"), Object(fontsDict)); | |
| + } | |
| +} | |
| + | |
| +void AnnotWidget::drawAppearance(Gfx *gfx, Object& obj, const PDFRectangle& drawRect) { | |
| + if (fontResourceDict != nullptr) { | |
| + gfx->pushResources(fontResourceDict); | |
| } | |
| + | |
| gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, | |
| - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); | |
| - if (addDingbatsResource) { | |
| + drawRect.x1, drawRect.y1, drawRect.x2, drawRect.y2, getRotation()); | |
| + | |
| + if (fontResourceDict != nullptr) { | |
| gfx->popResources(); | |
| + delete fontResourceDict; | |
| + fontResourceDict = nullptr; | |
| } | |
| } | |
| - | |
| //------------------------------------------------------------------------ | |
| // AnnotMovie | |
| //------------------------------------------------------------------------ | |
| AnnotMovie::AnnotMovie(PDFDoc *docA, PDFRectangle *rect, Movie *movieA) : | |
| Annot(docA, rect) { | |
| type = typeMovie; | |
| annotObj.dictSet ("Subtype", Object(objName, "Movie")); | |
| movie = movieA->copy(); | |
| // TODO: create movie dict from movieA | |
| initialize(docA, annotObj.getDict()); | |
| } | |
| AnnotMovie::AnnotMovie(PDFDoc *docA, Object *dictObject, Object *obj) : | |
| Annot(docA, dictObject, obj) { | |
| type = typeMovie; | |
| initialize(docA, dictObject->getDict()); | |
| } | |
| @@ -5011,117 +5041,111 @@ void AnnotMovie::initialize(PDFDoc *docA, Dict* dict) { | |
| Object movieDict = dict->lookup("Movie"); | |
| if (movieDict.isDict()) { | |
| Object obj2 = dict->lookup("A"); | |
| if (obj2.isDict()) | |
| movie = new Movie (&movieDict, &obj2); | |
| else | |
| movie = new Movie (&movieDict); | |
| if (!movie->isOk()) { | |
| delete movie; | |
| movie = nullptr; | |
| ok = gFalse; | |
| } | |
| } else { | |
| error(errSyntaxError, -1, "Bad Annot Movie"); | |
| movie = nullptr; | |
| ok = gFalse; | |
| } | |
| } | |
| -void AnnotMovie::draw(Gfx *gfx, GBool printing) { | |
| - if (!isVisible (printing)) | |
| - return; | |
| - | |
| - annotLocker(); | |
| +void AnnotMovie::makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) { | |
| if (appearance.isNull() && movie->getShowPoster()) { | |
| int width, height; | |
| Object poster = movie->getPoster(); | |
| movie->getAspect(&width, &height); | |
| if (width != -1 && height != -1 && !poster.isNone()) { | |
| appearBuf = new GooString (); | |
| appearBuf->append ("q\n"); | |
| appearBuf->appendf ("{0:d} 0 0 {1:d} 0 0 cm\n", width, height); | |
| appearBuf->append ("/MImg Do\n"); | |
| appearBuf->append ("Q\n"); | |
| - Dict *imgDict = new Dict(gfx->getXRef()); | |
| + Dict *imgDict = new Dict(xref); | |
| imgDict->set("MImg", std::move(poster)); | |
| - Dict *resDict = new Dict(gfx->getXRef()); | |
| + Dict *resDict = new Dict(xref); | |
| resDict->set("XObject", Object(imgDict)); | |
| - Dict *formDict = new Dict(gfx->getXRef()); | |
| + Dict *formDict = new Dict(xref); | |
| formDict->set("Length", Object(appearBuf->getLength())); | |
| formDict->set("Subtype", Object(objName, "Form")); | |
| formDict->set("Name", Object(objName, "FRM")); | |
| - Array *bboxArray = new Array(gfx->getXRef()); | |
| + Array *bboxArray = new Array(xref); | |
| bboxArray->add(Object(0)); | |
| bboxArray->add(Object(0)); | |
| bboxArray->add(Object(width)); | |
| bboxArray->add(Object(height)); | |
| formDict->set("BBox", Object(bboxArray)); | |
| - Array *matrix = new Array(gfx->getXRef()); | |
| + Array *matrix = new Array(xref); | |
| matrix->add(Object(1)); | |
| matrix->add(Object(0)); | |
| matrix->add(Object(0)); | |
| matrix->add(Object(1)); | |
| matrix->add(Object(-width / 2)); | |
| matrix->add(Object(-height / 2)); | |
| formDict->set("Matrix", Object(matrix)); | |
| formDict->set("Resources", Object(resDict)); | |
| MemStream *mStream = new MemStream(copyString(appearBuf->getCString()), 0, | |
| appearBuf->getLength(), Object(formDict)); | |
| mStream->setNeedFree(gTrue); | |
| delete appearBuf; | |
| - Dict *dict = new Dict(gfx->getXRef()); | |
| + Dict *dict = new Dict(xref); | |
| dict->set("FRM", Object(static_cast<Stream*>(mStream))); | |
| - Dict *resDict2 = new Dict(gfx->getXRef()); | |
| + Dict *resDict2 = new Dict(xref); | |
| resDict2->set("XObject", Object(dict)); | |
| appearBuf = new GooString (); | |
| appearBuf->append ("q\n"); | |
| appearBuf->appendf ("0 0 {0:d} {1:d} re W n\n", width, height); | |
| appearBuf->append ("q\n"); | |
| appearBuf->appendf ("0 0 {0:d} {1:d} re W n\n", width, height); | |
| appearBuf->appendf ("1 0 0 1 {0:d} {1:d} cm\n", width / 2, height / 2); | |
| appearBuf->append ("/FRM Do\n"); | |
| appearBuf->append ("Q\n"); | |
| appearBuf->append ("Q\n"); | |
| double bbox[4]; | |
| bbox[0] = bbox[1] = 0; | |
| bbox[2] = width; | |
| bbox[3] = height; | |
| appearance = createForm(bbox, gFalse, resDict2); | |
| delete appearBuf; | |
| } | |
| } | |
| - // draw the appearance stream | |
| - Object obj = appearance.fetch(gfx->getXRef()); | |
| - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, | |
| - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); | |
| + obj = appearance.fetch(xref); | |
| + drawRect = *rect; | |
| } | |
| //------------------------------------------------------------------------ | |
| // AnnotScreen | |
| //------------------------------------------------------------------------ | |
| AnnotScreen::AnnotScreen(PDFDoc *docA, PDFRectangle *rect) : | |
| Annot(docA, rect) { | |
| type = typeScreen; | |
| annotObj.dictSet ("Subtype", Object(objName, "Screen")); | |
| initialize(docA, annotObj.getDict()); | |
| } | |
| AnnotScreen::AnnotScreen(PDFDoc *docA, Object *dictObject, Object *obj) : | |
| Annot(docA, dictObject, obj) { | |
| type = typeScreen; | |
| initialize(docA, dictObject->getDict()); | |
| } | |
| AnnotScreen::~AnnotScreen() { | |
| @@ -5300,47 +5324,43 @@ void AnnotGeometry::setType(AnnotSubtype new_type) { | |
| } | |
| type = new_type; | |
| update("Subtype", Object(objName, typeName)); | |
| invalidateAppearance(); | |
| } | |
| void AnnotGeometry::setInteriorColor(AnnotColor *new_color) { | |
| delete interiorColor; | |
| if (new_color) { | |
| Object obj1 = new_color->writeToObject(xref); | |
| update ("IC", std::move(obj1)); | |
| interiorColor = new_color; | |
| } else { | |
| interiorColor = nullptr; | |
| } | |
| invalidateAppearance(); | |
| } | |
| -void AnnotGeometry::draw(Gfx *gfx, GBool printing) { | |
| +void AnnotGeometry::makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) { | |
| double ca = 1; | |
| - if (!isVisible (printing)) | |
| - return; | |
| - | |
| - annotLocker(); | |
| if (appearance.isNull()) { | |
| ca = opacity; | |
| appearBuf = new GooString (); | |
| appearBuf->append ("q\n"); | |
| if (color) | |
| setColor(color, gFalse); | |
| double borderWidth = border->getWidth(); | |
| setLineStyleForBorder(border); | |
| if (interiorColor) | |
| setColor(interiorColor, gTrue); | |
| if (type == typeSquare) { | |
| appearBuf->appendf ("{0:.2f} {1:.2f} {2:.2f} {3:.2f} re\n", | |
| borderWidth / 2.0, borderWidth / 2.0, | |
| (rect->x2 - rect->x1) - borderWidth, | |
| (rect->y2 - rect->y1) - borderWidth); | |
| } else { | |
| @@ -5398,44 +5418,42 @@ void AnnotGeometry::draw(Gfx *gfx, GBool printing) { | |
| appearBuf->append ("Q\n"); | |
| double bbox[4]; | |
| bbox[0] = bbox[1] = 0; | |
| bbox[2] = rect->x2 - rect->x1; | |
| bbox[3] = rect->y2 - rect->y1; | |
| if (ca == 1) { | |
| appearance = createForm(bbox, gFalse, nullptr); | |
| } else { | |
| Object aStream = createForm(bbox, gTrue, nullptr); | |
| delete appearBuf; | |
| appearBuf = new GooString ("/GS0 gs\n/Fm0 Do"); | |
| Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr); | |
| appearance = createForm(bbox, gFalse, resDict); | |
| } | |
| delete appearBuf; | |
| } | |
| - // draw the appearance stream | |
| - Object obj = appearance.fetch(gfx->getXRef()); | |
| - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, | |
| - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); | |
| + obj = appearance.fetch(xref); | |
| + drawRect = *rect; | |
| } | |
| //------------------------------------------------------------------------ | |
| // AnnotPolygon | |
| //------------------------------------------------------------------------ | |
| AnnotPolygon::AnnotPolygon(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType) : | |
| AnnotMarkup(docA, rect) { | |
| switch (subType) { | |
| case typePolygon: | |
| annotObj.dictSet ("Subtype", Object(objName, "Polygon")); | |
| break; | |
| case typePolyLine: | |
| annotObj.dictSet ("Subtype", Object(objName, "PolyLine")); | |
| break; | |
| default: | |
| assert (0 && "Invalid subtype for AnnotGeometry\n"); | |
| } | |
| // Store dummy path with one null vertex only | |
| Array *a = new Array(doc->getXRef()); | |
| @@ -5596,47 +5614,43 @@ void AnnotPolygon::setInteriorColor(AnnotColor *new_color) { | |
| interiorColor = new_color; | |
| } else { | |
| interiorColor = nullptr; | |
| } | |
| invalidateAppearance(); | |
| } | |
| void AnnotPolygon::setIntent(AnnotPolygonIntent new_intent) { | |
| const char *intentName; | |
| intent = new_intent; | |
| if (new_intent == polygonCloud) | |
| intentName = "PolygonCloud"; | |
| else if (new_intent == polylineDimension) | |
| intentName = "PolyLineDimension"; | |
| else // polygonDimension | |
| intentName = "PolygonDimension"; | |
| update ("IT", Object(objName, intentName)); | |
| } | |
| -void AnnotPolygon::draw(Gfx *gfx, GBool printing) { | |
| +void AnnotPolygon::makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) { | |
| double ca = 1; | |
| - if (!isVisible (printing)) | |
| - return; | |
| - | |
| - annotLocker(); | |
| if (appearance.isNull()) { | |
| appearBBox = new AnnotAppearanceBBox(rect); | |
| ca = opacity; | |
| appearBuf = new GooString (); | |
| appearBuf->append ("q\n"); | |
| if (color) { | |
| setColor(color, gFalse); | |
| } | |
| setLineStyleForBorder(border); | |
| appearBBox->setBorderWidth(std::max(1., border->getWidth())); | |
| if (interiorColor) { | |
| setColor(interiorColor, gTrue); | |
| } | |
| if (vertices->getCoordsLength() != 0) { | |
| appearBuf->appendf ("{0:.2f} {1:.2f} m\n", vertices->getX(0) - rect->x1, vertices->getY(0) - rect->y1); | |
| @@ -5659,49 +5673,46 @@ void AnnotPolygon::draw(Gfx *gfx, GBool printing) { | |
| } | |
| appearBuf->append ("Q\n"); | |
| double bbox[4]; | |
| appearBBox->getBBoxRect(bbox); | |
| if (ca == 1) { | |
| appearance = createForm(bbox, gFalse, nullptr); | |
| } else { | |
| Object aStream = createForm(bbox, gTrue, nullptr); | |
| delete appearBuf; | |
| appearBuf = new GooString ("/GS0 gs\n/Fm0 Do"); | |
| Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr); | |
| appearance = createForm(bbox, gFalse, resDict); | |
| } | |
| delete appearBuf; | |
| } | |
| // draw the appearance stream | |
| - Object obj = appearance.fetch(gfx->getXRef()); | |
| + obj = appearance.fetch(xref); | |
| if (appearBBox) { | |
| - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, | |
| - appearBBox->getPageXMin(), appearBBox->getPageYMin(), | |
| - appearBBox->getPageXMax(), appearBBox->getPageYMax(), | |
| - getRotation()); | |
| + drawRect = PDFRectangle(appearBBox->getPageXMin(), appearBBox->getPageYMin(), | |
| + appearBBox->getPageXMax(), appearBBox->getPageYMax()); | |
| } else { | |
| - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, | |
| - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); | |
| + drawRect = *rect; | |
| } | |
| } | |
| //------------------------------------------------------------------------ | |
| // AnnotCaret | |
| //------------------------------------------------------------------------ | |
| AnnotCaret::AnnotCaret(PDFDoc *docA, PDFRectangle *rect) : | |
| AnnotMarkup(docA, rect) { | |
| type = typeCaret; | |
| annotObj.dictSet ("Subtype", Object(objName, "Caret")); | |
| initialize(docA, annotObj.getDict()); | |
| } | |
| AnnotCaret::AnnotCaret(PDFDoc *docA, Object *dictObject, Object *obj) : | |
| AnnotMarkup(docA, dictObject, obj) { | |
| type = typeCaret; | |
| initialize(docA, dictObject->getDict()); | |
| } | |
| @@ -5814,47 +5825,43 @@ void AnnotInk::parseInkList(Array *array) { | |
| void AnnotInk::freeInkList() { | |
| if (inkList) { | |
| for (int i = 0; i < inkListLength; ++i) | |
| delete inkList[i]; | |
| gfree(inkList); | |
| } | |
| } | |
| void AnnotInk::setInkList(AnnotPath **paths, int n_paths) { | |
| freeInkList(); | |
| Array *a = new Array(xref); | |
| writeInkList(paths, n_paths, a); | |
| parseInkList(a); | |
| annotObj.dictSet ("InkList", Object(a)); | |
| invalidateAppearance(); | |
| } | |
| -void AnnotInk::draw(Gfx *gfx, GBool printing) { | |
| +void AnnotInk::makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) { | |
| double ca = 1; | |
| - if (!isVisible (printing)) | |
| - return; | |
| - | |
| - annotLocker(); | |
| if (appearance.isNull()) { | |
| appearBBox = new AnnotAppearanceBBox(rect); | |
| ca = opacity; | |
| appearBuf = new GooString (); | |
| appearBuf->append ("q\n"); | |
| if (color) { | |
| setColor(color, gFalse); | |
| } | |
| setLineStyleForBorder(border); | |
| appearBBox->setBorderWidth(std::max(1., border->getWidth())); | |
| for (int i = 0; i < inkListLength; ++i) { | |
| const AnnotPath * path = inkList[i]; | |
| if (path && path->getCoordsLength() != 0) { | |
| appearBuf->appendf ("{0:.2f} {1:.2f} m\n", path->getX(0) - rect->x1, path->getY(0) - rect->y1); | |
| appearBBox->extendTo (path->getX(0) - rect->x1, path->getY(0) - rect->y1); | |
| @@ -5867,50 +5874,46 @@ void AnnotInk::draw(Gfx *gfx, GBool printing) { | |
| } | |
| } | |
| appearBuf->append ("Q\n"); | |
| double bbox[4]; | |
| appearBBox->getBBoxRect(bbox); | |
| if (ca == 1) { | |
| appearance = createForm(bbox, gFalse, nullptr); | |
| } else { | |
| Object aStream = createForm(bbox, gTrue, nullptr); | |
| delete appearBuf; | |
| appearBuf = new GooString ("/GS0 gs\n/Fm0 Do"); | |
| Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr); | |
| appearance = createForm(bbox, gFalse, resDict); | |
| } | |
| delete appearBuf; | |
| } | |
| - // draw the appearance stream | |
| - Object obj = appearance.fetch(gfx->getXRef()); | |
| + obj = appearance.fetch(xref); | |
| if (appearBBox) { | |
| - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, | |
| - appearBBox->getPageXMin(), appearBBox->getPageYMin(), | |
| - appearBBox->getPageXMax(), appearBBox->getPageYMax(), | |
| - getRotation()); | |
| + drawRect = PDFRectangle(appearBBox->getPageXMin(), appearBBox->getPageYMin(), | |
| + appearBBox->getPageXMax(), appearBBox->getPageYMax()); | |
| } else { | |
| - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, | |
| - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); | |
| + drawRect = *rect; | |
| } | |
| } | |
| //------------------------------------------------------------------------ | |
| // AnnotFileAttachment | |
| //------------------------------------------------------------------------ | |
| AnnotFileAttachment::AnnotFileAttachment(PDFDoc *docA, PDFRectangle *rect, GooString *filename) : | |
| AnnotMarkup(docA, rect) { | |
| type = typeFileAttachment; | |
| annotObj.dictSet("Subtype", Object(objName, "FileAttachment")); | |
| annotObj.dictSet("FS", Object(filename->copy())); | |
| initialize(docA, annotObj.getDict()); | |
| } | |
| AnnotFileAttachment::AnnotFileAttachment(PDFDoc *docA, Object *dictObject, Object *obj) : | |
| AnnotMarkup(docA, dictObject, obj) { | |
| type = typeFileAttachment; | |
| initialize(docA, dictObject->getDict()); | |
| @@ -6034,87 +6037,81 @@ void AnnotFileAttachment::initialize(PDFDoc *docA, Dict* dict) { | |
| "0.533333 0.541176 0.521569 RG 1 w\n" \ | |
| "0 j\n" \ | |
| "11.949 13.184 m 16.191 8.941 l S\n" \ | |
| "0.729412 0.741176 0.713725 RG 11.949 14.184 m 16.191 9.941 l S\n" \ | |
| "0.533333 0.541176 0.521569 RG 14.07 6.82 m 9.828 11.062 l S\n" \ | |
| "0.729412 0.741176 0.713725 RG 14.07 7.82 m 9.828 12.062 l S\n" \ | |
| "0.533333 0.541176 0.521569 RG 6.93 15.141 m 8 20 14.27 20.5 16 20.5 c\n" \ | |
| "18.094 20.504 19.5 20 19.5 18 c 19.5 16.699 20.91 16.418 22.5 16.5 c S\n" \ | |
| "0.729412 0.741176 0.713725 RG 0.999781 w\n" \ | |
| "1 j\n" \ | |
| "q 1 0 0 -1 0 24 cm\n" \ | |
| "8.492 7.707 m 8.492 8.535 7.82 9.207 6.992 9.207 c 6.164 9.207 5.492\n" \ | |
| "8.535 5.492 7.707 c 5.492 6.879 6.164 6.207 6.992 6.207 c 7.82 6.207\n" \ | |
| "8.492 6.879 8.492 7.707 c h\n" \ | |
| "8.492 7.707 m S Q\n" \ | |
| "1 w\n" \ | |
| "0 j\n" \ | |
| "6.93 16.141 m 8 21 14.27 21.5 16 21.5 c 18.094 21.504 19.5 21 19.5 19 c\n" \ | |
| "19.5 17.699 20.91 17.418 22.5 17.5 c S\n" | |
| -void AnnotFileAttachment::draw(Gfx *gfx, GBool printing) { | |
| +void AnnotFileAttachment::makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) { | |
| double ca = 1; | |
| - if (!isVisible (printing)) | |
| - return; | |
| - | |
| - annotLocker(); | |
| if (appearance.isNull()) { | |
| ca = opacity; | |
| appearBuf = new GooString (); | |
| appearBuf->append ("q\n"); | |
| if (color) | |
| setColor(color, gTrue); | |
| else | |
| appearBuf->append ("1 1 1 rg\n"); | |
| if (!name->cmp("PushPin")) | |
| appearBuf->append (ANNOT_FILE_ATTACHMENT_AP_PUSHPIN); | |
| else if (!name->cmp("Paperclip")) | |
| appearBuf->append (ANNOT_FILE_ATTACHMENT_AP_PAPERCLIP); | |
| else if (!name->cmp("Graph")) | |
| appearBuf->append (ANNOT_FILE_ATTACHMENT_AP_GRAPH); | |
| else if (!name->cmp("Tag")) | |
| appearBuf->append (ANNOT_FILE_ATTACHMENT_AP_TAG); | |
| appearBuf->append ("Q\n"); | |
| double bbox[4]; | |
| bbox[0] = bbox[1] = 0; | |
| bbox[2] = bbox[3] = 24; | |
| if (ca == 1) { | |
| appearance = createForm (bbox, gFalse, nullptr); | |
| } else { | |
| Object aStream = createForm (bbox, gTrue, nullptr); | |
| delete appearBuf; | |
| appearBuf = new GooString ("/GS0 gs\n/Fm0 Do"); | |
| Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr); | |
| appearance = createForm(bbox, gFalse, resDict); | |
| } | |
| delete appearBuf; | |
| } | |
| - // draw the appearance stream | |
| - Object obj = appearance.fetch(gfx->getXRef()); | |
| - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, | |
| - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); | |
| + obj = appearance.fetch(xref); | |
| + drawRect = *rect; | |
| } | |
| //------------------------------------------------------------------------ | |
| // AnnotSound | |
| //------------------------------------------------------------------------ | |
| AnnotSound::AnnotSound(PDFDoc *docA, PDFRectangle *rect, Sound *soundA) : | |
| AnnotMarkup(docA, rect) { | |
| type = typeSound; | |
| annotObj.dictSet ("Subtype", Object(objName, "Sound")); | |
| annotObj.dictSet ("Sound", soundA->getObject()->copy()); | |
| initialize(docA, annotObj.getDict()); | |
| } | |
| AnnotSound::AnnotSound(PDFDoc *docA, Object *dictObject, Object *obj) : | |
| AnnotMarkup(docA, dictObject, obj) { | |
| type = typeSound; | |
| initialize(docA, dictObject->getDict()); | |
| } | |
| @@ -6188,84 +6185,77 @@ void AnnotSound::initialize(PDFDoc *docA, Dict* dict) { | |
| "17.5 14.5 m 17.5 11.973 l 17.5 8.941 15.047 6.5 12 6.5 c 8.953 6.5 6.5\n" \ | |
| "8.941 6.5 11.973 c 6.5 14.5 l S\n" \ | |
| "2 w\n" \ | |
| "0 J\n" \ | |
| "12 6.52 m 12 3 l S\n" \ | |
| "1 J\n" \ | |
| "8 3 m 16 3 l S\n" \ | |
| "0.729412 0.741176 0.713725 RG 12 21 m 12 21 l 13.656 21 15 19.656 15 18 c\n" \ | |
| "15 14 l 15 12.344 13.656 11 12 11 c 12 11 l 10.344 11 9 12.344 9 14 c\n" \ | |
| "9 18 l 9 19.656 10.344 21 12 21 c h\n" \ | |
| "12 21 m S\n" \ | |
| "1 w\n" \ | |
| "17.5 15.5 m 17.5 12.973 l 17.5 9.941 15.047 7.5 12 7.5 c 8.953 7.5 6.5\n" \ | |
| "9.941 6.5 12.973 c 6.5 15.5 l S\n" \ | |
| "2 w\n" \ | |
| "0 J\n" \ | |
| "12 7.52 m 12 4 l S\n" \ | |
| "1 J\n" \ | |
| "8 4 m 16 4 l S\n" | |
| -void AnnotSound::draw(Gfx *gfx, GBool printing) { | |
| - Object obj; | |
| +void AnnotSound::makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) { | |
| double ca = 1; | |
| - if (!isVisible (printing)) | |
| - return; | |
| - | |
| - annotLocker(); | |
| if (appearance.isNull()) { | |
| ca = opacity; | |
| appearBuf = new GooString (); | |
| appearBuf->append ("q\n"); | |
| if (color) | |
| setColor(color, gTrue); | |
| else | |
| appearBuf->append ("1 1 1 rg\n"); | |
| if (!name->cmp("Speaker")) | |
| appearBuf->append (ANNOT_SOUND_AP_SPEAKER); | |
| else if (!name->cmp("Mic")) | |
| appearBuf->append (ANNOT_SOUND_AP_MIC); | |
| appearBuf->append ("Q\n"); | |
| double bbox[4]; | |
| bbox[0] = bbox[1] = 0; | |
| bbox[2] = bbox[3] = 24; | |
| if (ca == 1) { | |
| appearance = createForm(bbox, gFalse, nullptr); | |
| } else { | |
| Object aStream = createForm(bbox, gTrue, nullptr); | |
| delete appearBuf; | |
| appearBuf = new GooString ("/GS0 gs\n/Fm0 Do"); | |
| Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr); | |
| appearance = createForm(bbox, gFalse, resDict); | |
| } | |
| delete appearBuf; | |
| } | |
| - // draw the appearance stream | |
| - obj = appearance.fetch(gfx->getXRef()); | |
| - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, | |
| - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); | |
| + obj = appearance.fetch(xref); | |
| + drawRect = *rect; | |
| } | |
| //------------------------------------------------------------------------ | |
| // Annot3D | |
| //------------------------------------------------------------------------ | |
| Annot3D::Annot3D(PDFDoc *docA, PDFRectangle *rect) : | |
| Annot(docA, rect) { | |
| type = type3D; | |
| annotObj.dictSet ("Subtype", Object(objName, "3D")); | |
| initialize(docA, annotObj.getDict()); | |
| } | |
| Annot3D::Annot3D(PDFDoc *docA, Object *dictObject, Object *obj) : | |
| Annot(docA, dictObject, obj) { | |
| type = type3D; | |
| initialize(docA, dictObject->getDict()); | |
| } | |
| diff --git a/poppler/Annot.h b/poppler/Annot.h | |
| index 860d95e9..8cce6f75 100644 | |
| --- a/poppler/Annot.h | |
| +++ b/poppler/Annot.h | |
| @@ -40,40 +40,41 @@ | |
| #endif | |
| #include "Object.h" | |
| class XRef; | |
| class Gfx; | |
| class CharCodeToUnicode; | |
| class GfxFont; | |
| class GfxResources; | |
| class Page; | |
| class PDFDoc; | |
| class Form; | |
| class FormWidget; | |
| class FormField; | |
| class FormFieldChoice; | |
| class PDFRectangle; | |
| class Movie; | |
| class LinkAction; | |
| class Sound; | |
| class FileSpec; | |
| +class OutputDev; | |
| enum AnnotLineEndingStyle { | |
| annotLineEndingSquare, // Square | |
| annotLineEndingCircle, // Circle | |
| annotLineEndingDiamond, // Diamond | |
| annotLineEndingOpenArrow, // OpenArrow | |
| annotLineEndingClosedArrow, // ClosedArrow | |
| annotLineEndingNone, // None | |
| annotLineEndingButt, // Butt | |
| annotLineEndingROpenArrow, // ROpenArrow | |
| annotLineEndingRClosedArrow, // RClosedArrow | |
| annotLineEndingSlash // Slash | |
| }; | |
| enum AnnotExternalDataType { | |
| annotExternalDataMarkupUnknown, | |
| annotExternalDataMarkup3D // Markup3D | |
| }; | |
| //------------------------------------------------------------------------ | |
| @@ -560,41 +561,50 @@ public: | |
| actionPageClosing, ///< Performed when the page containing the annotation is closed | |
| actionPageVisible, ///< Performed when the page containing the annotation becomes visible | |
| actionPageInvisible ///< Performed when the page containing the annotation becomes invisible | |
| }; | |
| enum FormAdditionalActionsType { | |
| actionFieldModified, ///< Performed when the when the user modifies the field | |
| actionFormatField, ///< Performed before the field is formatted to display its value | |
| actionValidateField, ///< Performed when the field value changes | |
| actionCalculateField, ///< Performed when the field needs to be recalculated | |
| }; | |
| Annot(PDFDoc *docA, PDFRectangle *rectA); | |
| Annot(PDFDoc *docA, Object *dictObject); | |
| Annot(PDFDoc *docA, Object *dictObject, Object *obj); | |
| GBool isOk() { return ok; } | |
| void incRefCnt(); | |
| void decRefCnt(); | |
| - virtual void draw(Gfx *gfx, GBool printing); | |
| + Gfx* createGfx(OutputDev* splash_output, double hDPI, double vDPI, double width, double height); | |
| + | |
| + void draw(Gfx *gfx, GBool printing, GBool drawAtOrigin = gFalse); | |
| + | |
| + void draw(OutputDev *outputDev, GBool printing, double hDPI, double vDPI, GBool drawAtOrigin); | |
| + | |
| + virtual void makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref); | |
| + | |
| + virtual void drawAppearance(Gfx *gfx, Object& obj, const PDFRectangle& drawRect); | |
| + | |
| // Get the resource dict of the appearance stream | |
| virtual Object getAppearanceResDict(); | |
| GBool match(Ref *refA) | |
| { return ref.num == refA->num && ref.gen == refA->gen; } | |
| double getXMin(); | |
| double getYMin(); | |
| double getXMax(); | |
| double getYMax(); | |
| double getFontSize() { return fontSize; } | |
| void setRect(PDFRectangle *rect); | |
| void setRect(double x1, double y1, double x2, double y2); | |
| // Sets the annot contents to new_content | |
| // new_content should never be NULL | |
| virtual void setContents(GooString *new_content); | |
| void setName(GooString *new_name); | |
| @@ -784,74 +794,74 @@ private: | |
| class AnnotText: public AnnotMarkup { | |
| public: | |
| enum AnnotTextState { | |
| stateUnknown, | |
| // Marked state model | |
| stateMarked, // Marked | |
| stateUnmarked, // Unmarked | |
| // Review state model | |
| stateAccepted, // Accepted | |
| stateRejected, // Rejected | |
| stateCancelled, // Cancelled | |
| stateCompleted, // Completed | |
| stateNone // None | |
| }; | |
| AnnotText(PDFDoc *docA, PDFRectangle *rect); | |
| AnnotText(PDFDoc *docA, Object *dictObject, Object *obj); | |
| ~AnnotText(); | |
| - void draw(Gfx *gfx, GBool printing) override; | |
| + void makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) override; | |
| // getters | |
| GBool getOpen() const { return open; } | |
| GooString *getIcon() const { return icon; } | |
| AnnotTextState getState() const { return state; } | |
| void setOpen(GBool openA); | |
| void setIcon(GooString *new_icon); | |
| private: | |
| void initialize(PDFDoc *docA, Dict *dict); | |
| GBool open; // Open (Default false) | |
| GooString *icon; // Name (Default Note) | |
| AnnotTextState state; // State (Default Umarked if | |
| // StateModel Marked | |
| // None if StareModel Review) | |
| }; | |
| //------------------------------------------------------------------------ | |
| // AnnotMovie | |
| //------------------------------------------------------------------------ | |
| class AnnotMovie: public Annot { | |
| public: | |
| AnnotMovie(PDFDoc *docA, PDFRectangle *rect, Movie *movieA); | |
| AnnotMovie(PDFDoc *docA, Object *dictObject, Object *obj); | |
| ~AnnotMovie(); | |
| - void draw(Gfx *gfx, GBool printing) override; | |
| + void makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) override; | |
| GooString* getTitle() { return title; } | |
| Movie* getMovie() { return movie; } | |
| private: | |
| void initialize(PDFDoc *docA, Dict *dict); | |
| GooString* title; // T | |
| Movie* movie; // Movie + A | |
| }; | |
| //------------------------------------------------------------------------ | |
| // AnnotScreen | |
| //------------------------------------------------------------------------ | |
| class AnnotScreen: public Annot { | |
| public: | |
| AnnotScreen(PDFDoc *docA, PDFRectangle *rect); | |
| @@ -877,41 +887,41 @@ class AnnotScreen: public Annot { | |
| }; | |
| //------------------------------------------------------------------------ | |
| // AnnotLink | |
| //------------------------------------------------------------------------ | |
| class AnnotLink: public Annot { | |
| public: | |
| enum AnnotLinkEffect { | |
| effectNone, // N | |
| effectInvert, // I | |
| effectOutline, // O | |
| effectPush // P | |
| }; | |
| AnnotLink(PDFDoc *docA, PDFRectangle *rect); | |
| AnnotLink(PDFDoc *docA, Object *dictObject, Object *obj); | |
| ~AnnotLink(); | |
| - void draw(Gfx *gfx, GBool printing) override; | |
| + void makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) override; | |
| // getters | |
| LinkAction *getAction() const { return action; } | |
| AnnotLinkEffect getLinkEffect() const { return linkEffect; } | |
| Dict *getUriAction() const { return uriAction; } | |
| AnnotQuadrilaterals *getQuadrilaterals() const { return quadrilaterals; } | |
| protected: | |
| void initialize(PDFDoc *docA, Dict *dict); | |
| LinkAction *action; // A, Dest | |
| AnnotLinkEffect linkEffect; // H (Default I) | |
| Dict *uriAction; // PA | |
| AnnotQuadrilaterals *quadrilaterals; // QuadPoints | |
| }; | |
| //------------------------------------------------------------------------ | |
| // AnnotFreeText | |
| @@ -919,41 +929,41 @@ protected: | |
| class AnnotFreeText: public AnnotMarkup { | |
| public: | |
| enum AnnotFreeTextQuadding { | |
| quaddingLeftJustified, // 0 | |
| quaddingCentered, // 1 | |
| quaddingRightJustified // 2 | |
| }; | |
| enum AnnotFreeTextIntent { | |
| intentFreeText, // FreeText | |
| intentFreeTextCallout, // FreeTextCallout | |
| intentFreeTextTypeWriter // FreeTextTypeWriter | |
| }; | |
| AnnotFreeText(PDFDoc *docA, PDFRectangle *rect, GooString *da); | |
| AnnotFreeText(PDFDoc *docA, Object *dictObject, Object *obj); | |
| ~AnnotFreeText(); | |
| - void draw(Gfx *gfx, GBool printing) override; | |
| + void makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) override; | |
| Object getAppearanceResDict() override; | |
| void setContents(GooString *new_content) override; | |
| void setAppearanceString(GooString *new_string); | |
| void setQuadding(AnnotFreeTextQuadding new_quadding); | |
| void setStyleString(GooString *new_string); | |
| void setCalloutLine(AnnotCalloutLine *line); | |
| void setIntent(AnnotFreeTextIntent new_intent); | |
| // getters | |
| GooString *getAppearanceString() const { return appearanceString; } | |
| AnnotFreeTextQuadding getQuadding() const { return quadding; } | |
| // return rc | |
| GooString *getStyleString() const { return styleString; } | |
| AnnotCalloutLine *getCalloutLine() const { return calloutLine; } | |
| AnnotFreeTextIntent getIntent() const { return intent; } | |
| AnnotBorderEffect *getBorderEffect() const { return borderEffect; } | |
| PDFRectangle *getRectangle() const { return rectangle; } | |
| AnnotLineEndingStyle getEndStyle() const { return endStyle; } | |
| @@ -983,41 +993,41 @@ protected: | |
| // AnnotLine | |
| //------------------------------------------------------------------------ | |
| class AnnotLine: public AnnotMarkup { | |
| public: | |
| enum AnnotLineIntent { | |
| intentLineArrow, // LineArrow | |
| intentLineDimension // LineDimension | |
| }; | |
| enum AnnotLineCaptionPos { | |
| captionPosInline, // Inline | |
| captionPosTop // Top | |
| }; | |
| AnnotLine(PDFDoc *docA, PDFRectangle *rect); | |
| AnnotLine(PDFDoc *docA, Object *dictObject, Object *obj); | |
| ~AnnotLine(); | |
| - void draw(Gfx *gfx, GBool printing) override; | |
| + void makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) override; | |
| Object getAppearanceResDict() override; | |
| void setContents(GooString *new_content) override; | |
| void setVertices(double x1, double y1, double x2, double y2); | |
| void setStartEndStyle(AnnotLineEndingStyle start, AnnotLineEndingStyle end); | |
| void setInteriorColor(AnnotColor *new_color); | |
| void setLeaderLineLength(double len); | |
| void setLeaderLineExtension(double len); | |
| void setCaption(bool new_cap); | |
| void setIntent(AnnotLineIntent new_intent); | |
| // getters | |
| AnnotLineEndingStyle getStartStyle() const { return startStyle; } | |
| AnnotLineEndingStyle getEndStyle() const { return endStyle; } | |
| AnnotColor *getInteriorColor() const { return interiorColor; } | |
| double getLeaderLineLength() const { return leaderLineLength; } | |
| double getLeaderLineExtension() const { return leaderLineExtension; } | |
| bool getCaption() const { return caption; } | |
| AnnotLineIntent getIntent() const { return intent; } | |
| double getLeaderLineOffset() const { return leaderLineOffset; } | |
| @@ -1049,41 +1059,41 @@ protected: | |
| bool caption; // Cap (Default false) | |
| AnnotLineIntent intent; // IT | |
| double leaderLineOffset; // LLO | |
| AnnotLineCaptionPos captionPos; // CP (Default Inline) | |
| Dict *measure; // Measure | |
| double captionTextHorizontal; // CO (Default [0, 0]) | |
| double captionTextVertical; // | |
| }; | |
| //------------------------------------------------------------------------ | |
| // AnnotTextMarkup | |
| //------------------------------------------------------------------------ | |
| class AnnotTextMarkup: public AnnotMarkup { | |
| public: | |
| AnnotTextMarkup(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType); | |
| AnnotTextMarkup(PDFDoc *docA, Object *dictObject, Object *obj); | |
| ~AnnotTextMarkup(); | |
| - void draw(Gfx *gfx, GBool printing) override; | |
| + void makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) override; | |
| // typeHighlight, typeUnderline, typeSquiggly or typeStrikeOut | |
| void setType(AnnotSubtype new_type); | |
| void setQuadrilaterals(AnnotQuadrilaterals *quadPoints); | |
| AnnotQuadrilaterals *getQuadrilaterals() const { return quadrilaterals; } | |
| protected: | |
| void initialize(PDFDoc *docA, Dict *dict); | |
| AnnotQuadrilaterals *quadrilaterals; // QuadPoints | |
| }; | |
| //------------------------------------------------------------------------ | |
| // AnnotStamp | |
| //------------------------------------------------------------------------ | |
| class AnnotStamp: public AnnotMarkup { | |
| @@ -1099,77 +1109,77 @@ public: | |
| GooString *getIcon() const { return icon; } | |
| private: | |
| void initialize(PDFDoc *docA, Dict *dict); | |
| GooString *icon; // Name (Default Draft) | |
| }; | |
| //------------------------------------------------------------------------ | |
| // AnnotGeometry | |
| //------------------------------------------------------------------------ | |
| class AnnotGeometry: public AnnotMarkup { | |
| public: | |
| AnnotGeometry(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType); | |
| AnnotGeometry(PDFDoc *docA, Object *dictObject, Object *obj); | |
| ~AnnotGeometry(); | |
| - void draw(Gfx *gfx, GBool printing) override; | |
| + void makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) override; | |
| void setType(AnnotSubtype new_type); // typeSquare or typeCircle | |
| void setInteriorColor(AnnotColor *new_color); | |
| // getters | |
| AnnotColor *getInteriorColor() const { return interiorColor; } | |
| AnnotBorderEffect *getBorderEffect() const { return borderEffect; } | |
| PDFRectangle *getGeometryRect() const { return geometryRect; } | |
| private: | |
| void initialize(PDFDoc *docA, Dict *dict); | |
| AnnotColor *interiorColor; // IC | |
| AnnotBorderEffect *borderEffect; // BE | |
| PDFRectangle *geometryRect; // RD (combined with Rect) | |
| }; | |
| //------------------------------------------------------------------------ | |
| // AnnotPolygon | |
| //------------------------------------------------------------------------ | |
| class AnnotPolygon: public AnnotMarkup { | |
| public: | |
| enum AnnotPolygonIntent { | |
| polygonCloud, // PolygonCloud | |
| polylineDimension, // PolyLineDimension | |
| polygonDimension // PolygonDimension | |
| }; | |
| AnnotPolygon(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType); | |
| AnnotPolygon(PDFDoc *docA, Object *dictObject, Object *obj); | |
| ~AnnotPolygon(); | |
| - void draw(Gfx *gfx, GBool printing) override; | |
| + void makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) override; | |
| void setType(AnnotSubtype new_type); // typePolygon or typePolyLine | |
| void setVertices(AnnotPath *path); | |
| void setStartEndStyle(AnnotLineEndingStyle start, AnnotLineEndingStyle end); | |
| void setInteriorColor(AnnotColor *new_color); | |
| void setIntent(AnnotPolygonIntent new_intent); | |
| // getters | |
| AnnotPath *getVertices() const { return vertices; } | |
| AnnotLineEndingStyle getStartStyle() const { return startStyle; } | |
| AnnotLineEndingStyle getEndStyle() const { return endStyle; } | |
| AnnotColor *getInteriorColor() const { return interiorColor; } | |
| AnnotBorderEffect *getBorderEffect() const { return borderEffect; } | |
| AnnotPolygonIntent getIntent() const { return intent; } | |
| private: | |
| void initialize(PDFDoc *docA, Dict *dict); | |
| // required | |
| @@ -1210,176 +1220,178 @@ public: | |
| private: | |
| void initialize(PDFDoc *docA, Dict *dict); | |
| AnnotCaretSymbol symbol; // Sy (Default None) | |
| PDFRectangle *caretRect; // RD (combined with Rect) | |
| }; | |
| //------------------------------------------------------------------------ | |
| // AnnotInk | |
| //------------------------------------------------------------------------ | |
| class AnnotInk: public AnnotMarkup { | |
| public: | |
| AnnotInk(PDFDoc *docA, PDFRectangle *rect); | |
| AnnotInk(PDFDoc *docA, Object *dictObject, Object *obj); | |
| ~AnnotInk(); | |
| - void draw(Gfx *gfx, GBool printing) override; | |
| + void makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) override; | |
| void setInkList(AnnotPath **paths, int n_paths); | |
| // getters | |
| AnnotPath **getInkList() const { return inkList; } | |
| int getInkListLength() const { return inkListLength; } | |
| private: | |
| void initialize(PDFDoc *docA, Dict *dict); | |
| void writeInkList(AnnotPath **paths, int n_paths, Array *dest_array); | |
| void parseInkList(Array *src_array); | |
| void freeInkList(); | |
| // required | |
| AnnotPath **inkList; // InkList | |
| int inkListLength; | |
| // optional | |
| // inherited from Annot | |
| // AnnotBorderBS border; // BS | |
| }; | |
| //------------------------------------------------------------------------ | |
| // AnnotFileAttachment | |
| //------------------------------------------------------------------------ | |
| class AnnotFileAttachment: public AnnotMarkup { | |
| public: | |
| AnnotFileAttachment(PDFDoc *docA, PDFRectangle *rect, GooString *filename); | |
| AnnotFileAttachment(PDFDoc *docA, Object *dictObject, Object *obj); | |
| ~AnnotFileAttachment(); | |
| - void draw(Gfx *gfx, GBool printing) override; | |
| + void makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) override; | |
| // getters | |
| Object *getFile() { return &file; } | |
| GooString *getName() const { return name; } | |
| private: | |
| void initialize(PDFDoc *docA, Dict *dict); | |
| // required | |
| Object file; // FS | |
| // optional | |
| GooString *name; // Name | |
| }; | |
| //------------------------------------------------------------------------ | |
| // AnnotSound | |
| //------------------------------------------------------------------------ | |
| class AnnotSound: public AnnotMarkup { | |
| public: | |
| AnnotSound(PDFDoc *docA, PDFRectangle *rect, Sound *soundA); | |
| AnnotSound(PDFDoc *docA, Object *dictObject, Object *obj); | |
| ~AnnotSound(); | |
| - void draw(Gfx *gfx, GBool printing) override; | |
| + void makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) override; | |
| // getters | |
| Sound *getSound() { return sound; } | |
| GooString *getName() const { return name; } | |
| private: | |
| void initialize(PDFDoc *docA, Dict *dict); | |
| // required | |
| Sound *sound; // Sound | |
| // optional | |
| GooString *name; // Name | |
| }; | |
| //------------------------------------------------------------------------ | |
| // AnnotWidget | |
| //------------------------------------------------------------------------ | |
| class AnnotWidget: public Annot { | |
| public: | |
| enum AnnotWidgetHighlightMode { | |
| highlightModeNone, // N | |
| highlightModeInvert, // I | |
| highlightModeOutline, // O | |
| highlightModePush // P,T | |
| }; | |
| AnnotWidget(PDFDoc *docA, Object *dictObject, Object *obj); | |
| AnnotWidget(PDFDoc *docA, Object *dictObject, Object *obj, FormField *fieldA); | |
| ~AnnotWidget(); | |
| - void draw(Gfx *gfx, GBool printing) override; | |
| + void makeAppearance(Object& obj, PDFRectangle& drawRect, XRef* xref) override; | |
| + void drawAppearance(Gfx *gfx, Object& obj, const PDFRectangle& drawRect) override; | |
| void drawBorder(); | |
| void drawFormFieldButton(GfxResources *resources, GooString *da); | |
| void drawFormFieldText(GfxResources *resources, GooString *da); | |
| void drawFormFieldChoice(GfxResources *resources, GooString *da); | |
| void generateFieldAppearance (); | |
| void updateAppearanceStream (); | |
| AnnotWidgetHighlightMode getMode() { return mode; } | |
| AnnotAppearanceCharacs *getAppearCharacs() { return appearCharacs; } | |
| LinkAction *getAction() { return action; } // The caller should not delete the result | |
| LinkAction *getAdditionalAction(AdditionalActionsType type); // The caller should delete the result | |
| LinkAction *getFormAdditionalAction(FormAdditionalActionsType type); // The caller should delete the result | |
| Dict *getParent() { return parent; } | |
| private: | |
| void initialize(PDFDoc *docA, Dict *dict); | |
| void drawText(GooString *text, GooString *da, GfxResources *resources, | |
| GBool multiline, int comb, int quadding, | |
| GBool txField, GBool forceZapfDingbats, | |
| GBool password=false); | |
| void drawListBox(FormFieldChoice *fieldChoice, | |
| GooString *da, GfxResources *resources, int quadding); | |
| Form *form; | |
| FormField *field; // FormField object for this annotation | |
| AnnotWidgetHighlightMode mode; // H (Default I) | |
| AnnotAppearanceCharacs *appearCharacs; // MK | |
| LinkAction *action; // A | |
| Object additionalActions; // AA | |
| // inherited from Annot | |
| // AnnotBorderBS border; // BS | |
| Dict *parent; // Parent | |
| GBool addDingbatsResource; | |
| Ref updatedAppearanceStream; // {-1,-1} if updateAppearanceStream has never been called | |
| + Dict *fontResourceDict; // a fake resource, required if drawText is called with forceZapfDingbats = true | |
| }; | |
| //------------------------------------------------------------------------ | |
| // Annot3D | |
| //------------------------------------------------------------------------ | |
| class Annot3D: public Annot { | |
| class Activation { | |
| public: | |
| enum ActivationATrigger { | |
| aTriggerUnknown, | |
| aTriggerPageOpened, // PO | |
| aTriggerPageVisible, // PV | |
| aTriggerUserAction // XA | |
| }; | |
| enum ActivationAState { | |
| aStateUnknown, | |
| aStateEnabled, // I | |
| aStateDisabled // L | |
| diff --git a/poppler/Page.cc b/poppler/Page.cc | |
| index d4799dd1..cbd6d2f7 100644 | |
| --- a/poppler/Page.cc | |
| +++ b/poppler/Page.cc | |
| @@ -76,40 +76,47 @@ void PDFRectangle::clipTo(PDFRectangle *rect) { | |
| } else if (x1 > rect->x2) { | |
| x1 = rect->x2; | |
| } | |
| if (x2 < rect->x1) { | |
| x2 = rect->x1; | |
| } else if (x2 > rect->x2) { | |
| x2 = rect->x2; | |
| } | |
| if (y1 < rect->y1) { | |
| y1 = rect->y1; | |
| } else if (y1 > rect->y2) { | |
| y1 = rect->y2; | |
| } | |
| if (y2 < rect->y1) { | |
| y2 = rect->y1; | |
| } else if (y2 > rect->y2) { | |
| y2 = rect->y2; | |
| } | |
| } | |
| +void PDFRectangle::translate(double dx, double dy) { | |
| + x1 += dx; | |
| + y1 += dy; | |
| + y2 += dy; | |
| + x2 += dx; | |
| +} | |
| + | |
| //------------------------------------------------------------------------ | |
| // PageAttrs | |
| //------------------------------------------------------------------------ | |
| PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { | |
| Object obj1; | |
| PDFRectangle mBox; | |
| const GBool isPage = dict->is("Page"); | |
| // get old/default values | |
| if (attrs) { | |
| mediaBox = attrs->mediaBox; | |
| cropBox = attrs->cropBox; | |
| haveCropBox = attrs->haveCropBox; | |
| rotate = attrs->rotate; | |
| resources = attrs->resources.copy(); | |
| } else { | |
| // set default MediaBox to 8.5" x 11" -- this shouldn't be necessary | |
| // but some (non-compliant) PDF files don't specify a MediaBox | |
| mediaBox.x1 = 0; | |
| diff --git a/poppler/Page.h b/poppler/Page.h | |
| index 61570791..47ac5bf4 100644 | |
| --- a/poppler/Page.h | |
| +++ b/poppler/Page.h | |
| @@ -47,40 +47,41 @@ class OutputDev; | |
| class Links; | |
| class LinkAction; | |
| class Annots; | |
| class Annot; | |
| class Gfx; | |
| class FormPageWidgets; | |
| class Form; | |
| //------------------------------------------------------------------------ | |
| class PDFRectangle { | |
| public: | |
| double x1, y1, x2, y2; | |
| PDFRectangle() { x1 = y1 = x2 = y2 = 0; } | |
| PDFRectangle(double x1A, double y1A, double x2A, double y2A) | |
| { x1 = x1A; y1 = y1A; x2 = x2A; y2 = y2A; } | |
| GBool isValid() { return x1 != 0 || y1 != 0 || x2 != 0 || y2 != 0; } | |
| GBool contains(double x, double y) { return x1 <= x && x <= x2 && y1 <= y && y <= y2; } | |
| void clipTo(PDFRectangle *rect); | |
| + void translate(double dx, double dy); | |
| bool operator==(const PDFRectangle &rect) const { return x1 == rect.x1 && y1 == rect.y1 && x2 == rect.x2 && y2 == rect.y2; } | |
| }; | |
| //------------------------------------------------------------------------ | |
| // PageAttrs | |
| //------------------------------------------------------------------------ | |
| class PageAttrs { | |
| public: | |
| // Construct a new PageAttrs object by merging a dictionary | |
| // (of type Pages or Page) into another PageAttrs object. If | |
| // <attrs> is NULL, uses defaults. | |
| PageAttrs(PageAttrs *attrs, Dict *dict); | |
| // Destructor. | |
| ~PageAttrs(); | |
| // Accessors. | |
| diff --git a/qt5/src/ArthurOutputDev.cc b/qt5/src/ArthurOutputDev.cc | |
| index 34fde569..2cd69b7d 100644 | |
| --- a/qt5/src/ArthurOutputDev.cc | |
| +++ b/qt5/src/ArthurOutputDev.cc | |
| @@ -39,40 +39,41 @@ | |
| #include <string.h> | |
| #include <math.h> | |
| #include "goo/gfile.h" | |
| #include "GlobalParams.h" | |
| #include "Error.h" | |
| #include "Object.h" | |
| #include "GfxState.h" | |
| #include "GfxFont.h" | |
| #include "Link.h" | |
| #include "FontEncodingTables.h" | |
| #include <fofi/FoFiTrueType.h> | |
| #include "ArthurOutputDev.h" | |
| #include <QtCore/QtDebug> | |
| #include <QRawFont> | |
| #include <QGlyphRun> | |
| #include <QtGui/QPainterPath> | |
| #include <QPicture> | |
| +#include <QImage> | |
| //------------------------------------------------------------------------ | |
| #ifdef HAVE_SPLASH | |
| #include "splash/SplashFontFileID.h" | |
| #include "splash/SplashFTFontFile.h" | |
| #include "splash/SplashFontEngine.h" | |
| //------------------------------------------------------------------------ | |
| // SplashOutFontFileID | |
| //------------------------------------------------------------------------ | |
| class SplashOutFontFileID: public SplashFontFileID { | |
| public: | |
| SplashOutFontFileID(Ref *rA) { r = *rA; } | |
| ~SplashOutFontFileID() {} | |
| GBool matches(SplashFontFileID *id) override { | |
| return ((SplashOutFontFileID *)id)->r.num == r.num && | |
| @@ -1018,20 +1019,76 @@ void ArthurOutputDev::endTransparencyGroup(GfxState * /*state*/) | |
| // painting. It will be painted and deleted in the method paintTransparencyGroup. | |
| if (m_lastTransparencyGroupPicture) | |
| { | |
| qDebug() << "Found a transparency group that has not been painted"; | |
| delete(m_lastTransparencyGroupPicture); | |
| } | |
| m_lastTransparencyGroupPicture = m_qpictures.top(); | |
| m_qpictures.pop(); | |
| } | |
| void ArthurOutputDev::paintTransparencyGroup(GfxState * /*state*/, double * /*bbox*/) | |
| { | |
| // Actually draw the transparency group | |
| m_painter.top()->drawPicture(0,0,*m_lastTransparencyGroupPicture); | |
| // And delete it | |
| delete(m_lastTransparencyGroupPicture); | |
| m_lastTransparencyGroupPicture = nullptr; | |
| } | |
| +ScopedPageQPainter::ScopedPageQPainter(QImage& image, int docHints, const QColor& docPaperColor, int pageFlags, int x, int y) | |
| +: m_painter(new QPainter(&image)), m_deletePainter(true) { | |
| + image.fill(docPaperColor); | |
| + setup(docHints, pageFlags, x, y); | |
| +} | |
| + | |
| +ScopedPageQPainter::ScopedPageQPainter(QPainter* painter, int docHints, int pageFlags, int x, int y) | |
| +: m_painter(painter), m_deletePainter(false) { | |
| + setup(docHints, pageFlags, x, y); | |
| +} | |
| + | |
| +ScopedPageQPainter::operator QPainter*() { | |
| + return m_painter; | |
| +} | |
| + | |
| +void ScopedPageQPainter::setup(int docHints, int pageFlags, int x, int y) { | |
| + m_savePainter = !(pageFlags & Poppler::Page:: DontSaveAndRestore); | |
| + if (m_savePainter) | |
| + m_painter->save(); | |
| + if (docHints & Poppler::Document::Antialiasing) | |
| + m_painter->setRenderHint(QPainter::Antialiasing); | |
| + if (docHints & Poppler::Document::TextAntialiasing) | |
| + m_painter->setRenderHint(QPainter::TextAntialiasing); | |
| + m_painter->translate(x == -1 ? 0 : -x, y == -1 ? 0 : -y); | |
| +} | |
| + | |
| +ScopedPageQPainter::~ScopedPageQPainter() { | |
| + if (m_savePainter) | |
| + m_painter->restore(); | |
| + m_painter->end(); | |
| + if (m_deletePainter) | |
| + delete m_painter; | |
| +} | |
| + | |
| +QImageDumpingArthurOutputDev::QImageDumpingArthurOutputDev(QPainter *painter, QImage *i) | |
| + : ArthurOutputDev(painter) | |
| + , partialUpdateCallback(nullptr) | |
| + , shouldDoPartialUpdateCallback(nullptr) | |
| + , image(i) | |
| +{ | |
| +} | |
| + | |
| +void QImageDumpingArthurOutputDev::setPartialUpdateCallbackData(Poppler::Page::RenderToImagePartialUpdateFunc callback, | |
| + Poppler::Page::ShouldRenderToImagePartialQueryFunc shouldDoCallback, const QVariant &payloadA) | |
| +{ | |
| + partialUpdateCallback = callback; | |
| + shouldDoPartialUpdateCallback = shouldDoCallback; | |
| + payload = payloadA; | |
| +} | |
| + | |
| +void QImageDumpingArthurOutputDev::dump() | |
| +{ | |
| + if (partialUpdateCallback && shouldDoPartialUpdateCallback && shouldDoPartialUpdateCallback(payload)) { | |
| + partialUpdateCallback(*image, payload); | |
| + } | |
| +} | |
| diff --git a/qt5/src/ArthurOutputDev.h b/qt5/src/ArthurOutputDev.h | |
| index b4ab3d7e..0d954449 100644 | |
| --- a/qt5/src/ArthurOutputDev.h | |
| +++ b/qt5/src/ArthurOutputDev.h | |
| @@ -24,40 +24,42 @@ | |
| // | |
| // 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 | |
| // | |
| //======================================================================== | |
| #ifndef ARTHUROUTPUTDEV_H | |
| #define ARTHUROUTPUTDEV_H | |
| #ifdef USE_GCC_PRAGMAS | |
| #pragma interface | |
| #endif | |
| #include <memory> | |
| #include <map> | |
| #include <stack> | |
| #include "goo/gtypes.h" | |
| #include "OutputDev.h" | |
| #include "GfxState.h" | |
| +#include "poppler-qt5.h" | |
| +#include "OutputDevCallbackHelper.h" | |
| #include <QtGui/QPainter> | |
| class GfxState; | |
| class SplashFontEngine; | |
| class QRawFont; | |
| //------------------------------------------------------------------------ | |
| // ArthurOutputDev - Qt 5 QPainter renderer | |
| //------------------------------------------------------------------------ | |
| class ArthurOutputDev: public OutputDev { | |
| public: | |
| /** | |
| * Describes how fonts are distorted (aka hinted) to fit the pixel grid. | |
| * More hinting means sharper edges and less adherence to the true letter shapes. | |
| */ | |
| enum FontHinting { | |
| @@ -214,21 +216,48 @@ private: | |
| struct ArthurFontID | |
| { | |
| Ref ref; | |
| double fontSize; | |
| bool operator<(const ArthurFontID& other) const | |
| { | |
| return (ref.num < other.ref.num) | |
| || ((ref.num == other.ref.num) && (fontSize < other.fontSize)); | |
| } | |
| }; | |
| // Cache all fonts | |
| std::map<ArthurFontID,std::unique_ptr<QRawFont> > m_rawFontCache; | |
| // The table that maps character codes to glyph indexes | |
| int* m_codeToGID; | |
| std::stack<int*> m_codeToGIDStack; | |
| }; | |
| +class ScopedPageQPainter { | |
| +public: | |
| + ScopedPageQPainter(QImage& image, int docHints, const QColor& docPaperColor, int pageFlags, int x, int y); | |
| + ScopedPageQPainter(QPainter* painter, int docHints, int pageFlags, int x, int y); | |
| + operator QPainter*(); | |
| + ~ScopedPageQPainter(); | |
| +private: | |
| + void setup(int docHints, int pageFlags, int x, int y); | |
| + QPainter* m_painter; | |
| + bool m_savePainter; | |
| + bool m_deletePainter; | |
| +}; | |
| + | |
| +class QImageDumpingArthurOutputDev : public ArthurOutputDev, public OutputDevCallbackHelper | |
| +{ | |
| +public: | |
| + QImageDumpingArthurOutputDev(QPainter *painter, QImage *i); | |
| + void setPartialUpdateCallbackData(Poppler::Page::RenderToImagePartialUpdateFunc callback, Poppler::Page::ShouldRenderToImagePartialQueryFunc shouldDoCallback, const QVariant &payloadA); | |
| + void dump() override; | |
| + | |
| +private: | |
| + Poppler::Page::RenderToImagePartialUpdateFunc partialUpdateCallback; | |
| + Poppler::Page::ShouldRenderToImagePartialQueryFunc shouldDoPartialUpdateCallback; | |
| + QVariant payload; | |
| + QImage *image; | |
| +}; | |
| + | |
| #endif | |
| diff --git a/qt5/src/CMakeLists.txt b/qt5/src/CMakeLists.txt | |
| index 63757c6b..fa656b5a 100644 | |
| --- a/qt5/src/CMakeLists.txt | |
| +++ b/qt5/src/CMakeLists.txt | |
| @@ -10,41 +10,43 @@ include_directories( | |
| set(poppler_qt5_SRCS | |
| poppler-annotation.cc | |
| poppler-document.cc | |
| poppler-embeddedfile.cc | |
| poppler-fontinfo.cc | |
| poppler-form.cc | |
| poppler-link.cc | |
| poppler-link-extractor.cc | |
| poppler-movie.cc | |
| poppler-optcontent.cc | |
| poppler-page.cc | |
| poppler-base-converter.cc | |
| poppler-pdf-converter.cc | |
| poppler-private.cc | |
| poppler-ps-converter.cc | |
| poppler-qiodeviceoutstream.cc | |
| poppler-sound.cc | |
| poppler-textbox.cc | |
| poppler-page-transition.cc | |
| poppler-media.cc | |
| + OutputDevCallbackHelper.cpp | |
| ArthurOutputDev.cc | |
| + Qt5OutputDev.cc | |
| ) | |
| add_library(poppler-qt5 ${poppler_qt5_SRCS}) | |
| set_target_properties(poppler-qt5 PROPERTIES VERSION 1.12.0 SOVERSION 1) | |
| if(MINGW) | |
| get_target_property(POPPLER_QT5_SOVERSION poppler-qt5 SOVERSION) | |
| set_target_properties(poppler-qt5 PROPERTIES SUFFIX "-${POPPLER_QT5_SOVERSION}${CMAKE_SHARED_LIBRARY_SUFFIX}") | |
| endif() | |
| target_link_libraries(poppler-qt5 poppler ${Qt5Core_LIBRARIES} ${Qt5Gui_LIBRARIES} ${Qt5Xml_LIBRARIES}) | |
| if(MSVC) | |
| target_link_libraries(poppler-qt5 poppler ${poppler_LIBS}) | |
| endif() | |
| install(TARGETS poppler-qt5 RUNTIME DESTINATION bin LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) | |
| install(FILES | |
| poppler-qt5.h | |
| poppler-link.h | |
| poppler-annotation.h | |
| poppler-form.h | |
| poppler-optcontent.h | |
| poppler-export.h | |
| diff --git a/qt5/src/OutputDevCallbackHelper.cpp b/qt5/src/OutputDevCallbackHelper.cpp | |
| new file mode 100644 | |
| index 00000000..0af70fbf | |
| --- /dev/null | |
| +++ b/qt5/src/OutputDevCallbackHelper.cpp | |
| @@ -0,0 +1,10 @@ | |
| +#include "OutputDevCallbackHelper.h" | |
| + | |
| +void OutputDevCallbackHelper::setCallbacks(Poppler::Page::RenderToImagePartialUpdateFunc callback, Poppler::Page::ShouldRenderToImagePartialQueryFunc shouldDoCallback, | |
| + Poppler::Page::ShouldAbortQueryFunc shouldAbortCallback, const QVariant &payloadA) | |
| +{ | |
| + partialUpdateCallback = callback; | |
| + shouldDoPartialUpdateCallback = shouldDoCallback; | |
| + shouldAbortRenderCallback = shouldAbortCallback; | |
| + payload = payloadA; | |
| +} | |
| diff --git a/qt5/src/OutputDevCallbackHelper.h b/qt5/src/OutputDevCallbackHelper.h | |
| new file mode 100644 | |
| index 00000000..3ec27f3e | |
| --- /dev/null | |
| +++ b/qt5/src/OutputDevCallbackHelper.h | |
| @@ -0,0 +1,18 @@ | |
| +#ifndef __QT5_OUTCALLBACKHELPER__ | |
| +#define __QT5_OUTCALLBACKHELPER__ | |
| + | |
| +#include "poppler-qt5.h" | |
| + | |
| +class OutputDevCallbackHelper | |
| +{ | |
| +public: | |
| + void setCallbacks(Poppler::Page::RenderToImagePartialUpdateFunc callback, Poppler::Page::ShouldRenderToImagePartialQueryFunc shouldDoCallback, | |
| + Poppler::Page::ShouldAbortQueryFunc shouldAbortCallback, const QVariant &payloadA); | |
| + | |
| + Poppler::Page::RenderToImagePartialUpdateFunc partialUpdateCallback = nullptr; | |
| + Poppler::Page::ShouldRenderToImagePartialQueryFunc shouldDoPartialUpdateCallback = nullptr; | |
| + Poppler::Page::ShouldAbortQueryFunc shouldAbortRenderCallback = nullptr; | |
| + QVariant payload; | |
| +}; | |
| + | |
| +#endif | |
| diff --git a/qt5/src/Qt5OutputDev.cc b/qt5/src/Qt5OutputDev.cc | |
| new file mode 100644 | |
| index 00000000..8bf54f2f | |
| --- /dev/null | |
| +++ b/qt5/src/Qt5OutputDev.cc | |
| @@ -0,0 +1,137 @@ | |
| +#include "Qt5OutputDev.h" | |
| +#include <QImage> | |
| +#include <SplashOutputDev.h> | |
| +#include <splash/SplashBitmap.h> | |
| +#include <ArthurOutputDev.h> | |
| +#include "poppler-qt5.h" | |
| +#include "poppler-private.h" | |
| + | |
| +Qt5SplashSettings::Qt5SplashSettings(const int docHints, QColor docPaperColor) | |
| +: bitmapRowPad(4), | |
| + reverseVideo(gFalse), | |
| + ignorePaperColorA(docHints & Poppler::Document::IgnorePaperColor), | |
| + bitmapTopDown(gTrue), | |
| + overprintPreview(gFalse) { | |
| +#ifdef SPLASH_CMYK | |
| + overprintPreview = docHints & Document::OverprintPreview ? gTrue : gFalse; | |
| + if (overprintPreview) | |
| + { | |
| + Guchar c, m, y, k; | |
| + | |
| + c = 255 - docPaperColor.blue(); | |
| + m = 255 - docPaperColor.red(); | |
| + y = 255 - docPaperColor.green(); | |
| + k = c; | |
| + if (m < k) { | |
| + k = m; | |
| + } | |
| + if (y < k) { | |
| + k = y; | |
| + } | |
| + bgColor[0] = c - k; | |
| + bgColor[1] = m - k; | |
| + bgColor[2] = y - k; | |
| + bgColor[3] = k; | |
| + for (int i = 4; i < SPOT_NCOMPS + 4; i++) { | |
| + bgColor[i] = 0; | |
| + } | |
| + } | |
| + else | |
| +#endif | |
| + { | |
| + bgColor[0] = docPaperColor.blue(); | |
| + bgColor[1] = docPaperColor.green(); | |
| + bgColor[2] = docPaperColor.red(); | |
| + } | |
| + | |
| + colorMode = splashModeXBGR8; | |
| +#ifdef SPLASH_CMYK | |
| + if (overprintPreview) colorMode = splashModeDeviceN8; | |
| +#endif | |
| + | |
| + thinLineMode = splashThinLineDefault; | |
| + if (docHints & Poppler::Document::ThinLineShape) | |
| + thinLineMode = splashThinLineShape; | |
| + if (docHints & Poppler::Document::ThinLineSolid) | |
| + thinLineMode = splashThinLineSolid; | |
| + | |
| + paperColor = ignorePaperColorA ? nullptr : bgColor; | |
| + | |
| + textAntialiasing = docHints & Poppler::Document::TextAntialiasing ? gTrue : gFalse; | |
| + vectorAntialias = docHints & Poppler::Document::Antialiasing ? gTrue : gFalse; | |
| + freeTypeHintingEnable = docHints & Poppler::Document::TextHinting ? gTrue : gFalse; | |
| + freeTypeHintingEnableSlightHintingA = docHints & Poppler::Document::TextSlightHinting ? gTrue : gFalse; | |
| +} | |
| + | |
| +Qt5SplashOutputDev::Qt5SplashOutputDev(const Qt5SplashSettings& settings) | |
| + : SplashOutputDev(settings.colorMode, settings.bitmapRowPad, settings.reverseVideo, settings.paperColor, settings.bitmapTopDown, settings.thinLineMode, settings.overprintPreview) | |
| + , partialUpdateCallback(nullptr) | |
| + , shouldDoPartialUpdateCallback(nullptr) | |
| + , ignorePaperColor(settings.ignorePaperColorA) | |
| +{ | |
| + setFontAntialias(settings.textAntialiasing); | |
| + setVectorAntialias(settings.vectorAntialias); | |
| + setFreeTypeHinting(settings.freeTypeHintingEnable, settings.freeTypeHintingEnableSlightHintingA); | |
| +} | |
| + | |
| +Qt5SplashOutputDev::Qt5SplashOutputDev(SplashColorMode colorMode, int bitmapRowPad, | |
| + GBool reverseVideo, bool ignorePaperColorA, SplashColorPtr paperColor, | |
| + GBool bitmapTopDown, SplashThinLineMode thinLineMode, | |
| + GBool overprintPreview) | |
| + : SplashOutputDev(colorMode, bitmapRowPad, reverseVideo, paperColor, bitmapTopDown, thinLineMode, overprintPreview) | |
| + , partialUpdateCallback(nullptr) | |
| + , shouldDoPartialUpdateCallback(nullptr) | |
| + , ignorePaperColor(ignorePaperColorA) | |
| +{ | |
| +} | |
| + | |
| +void Qt5SplashOutputDev::dump() | |
| +{ | |
| + if (partialUpdateCallback && shouldDoPartialUpdateCallback && shouldDoPartialUpdateCallback(payload)) { | |
| + partialUpdateCallback(getXBGRImage( false /* takeImageData */), payload); | |
| + } | |
| +} | |
| + | |
| +QImage Qt5SplashOutputDev::getXBGRImage(bool takeImageData) | |
| +{ | |
| + SplashBitmap *b = getBitmap(); | |
| + | |
| + const int bw = b->getWidth(); | |
| + const int bh = b->getHeight(); | |
| + const int brs = b->getRowSize(); | |
| + | |
| + // If we use DeviceN8, convert to XBGR8. | |
| + // If requested, also transfer Splash's internal alpha channel. | |
| + const SplashBitmap::ConversionMode mode = ignorePaperColor | |
| + ? SplashBitmap::conversionAlphaPremultiplied | |
| + : SplashBitmap::conversionOpaque; | |
| + | |
| + const QImage::Format format = ignorePaperColor | |
| + ? QImage::Format_ARGB32_Premultiplied | |
| + : QImage::Format_RGB32; | |
| + | |
| + if (b->convertToXBGR(mode)) { | |
| + SplashColorPtr data = takeImageData ? b->takeData() : b->getDataPtr(); | |
| + | |
| + if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { | |
| + // Convert byte order from RGBX to XBGR. | |
| + for (int i = 0; i < bh; ++i) { | |
| + for (int j = 0; j < bw; ++j) { | |
| + SplashColorPtr pixel = &data[i * brs + j]; | |
| + | |
| + qSwap(pixel[0], pixel[3]); | |
| + qSwap(pixel[1], pixel[2]); | |
| + } | |
| + } | |
| + } | |
| + | |
| + if (takeImageData) { | |
| + // Construct a Qt image holding (and also owning) the raw bitmap data. | |
| + return QImage(data, bw, bh, brs, format, gfree, data); | |
| + } else { | |
| + return QImage(data, bw, bh, brs, format).copy(); | |
| + } | |
| + } | |
| + | |
| + return QImage(); | |
| +} | |
| diff --git a/qt5/src/Qt5OutputDev.h b/qt5/src/Qt5OutputDev.h | |
| new file mode 100644 | |
| index 00000000..7c73b413 | |
| --- /dev/null | |
| +++ b/qt5/src/Qt5OutputDev.h | |
| @@ -0,0 +1,51 @@ | |
| +#ifndef __QT5_OUTPUTDEV__ | |
| +#define __QT5_OUTPUTDEV__ | |
| + | |
| +#include <QImage> | |
| +#include <SplashOutputDev.h> | |
| +#include <splash/SplashBitmap.h> | |
| +#include <ArthurOutputDev.h> | |
| +#include "poppler-qt5.h" | |
| +#include "OutputDevCallbackHelper.h" | |
| + | |
| +class Qt5SplashOutputDev; | |
| + | |
| +struct Qt5SplashSettings { | |
| + Qt5SplashSettings(const int docHints, QColor docPaperColor); | |
| + | |
| + SplashColorMode colorMode; | |
| + int bitmapRowPad; | |
| + GBool reverseVideo; | |
| + const bool ignorePaperColorA; | |
| + SplashColorPtr paperColor; | |
| + GBool bitmapTopDown; | |
| + SplashThinLineMode thinLineMode; | |
| + GBool overprintPreview; | |
| + SplashColor bgColor; | |
| + GBool textAntialiasing; | |
| + GBool vectorAntialias; | |
| + GBool freeTypeHintingEnable; | |
| + GBool freeTypeHintingEnableSlightHintingA; | |
| +}; | |
| + | |
| +class Qt5SplashOutputDev : public SplashOutputDev, public OutputDevCallbackHelper | |
| +{ | |
| +public: | |
| + Qt5SplashOutputDev(const Qt5SplashSettings& settings); | |
| + Qt5SplashOutputDev(SplashColorMode colorMode, int bitmapRowPad, | |
| + GBool reverseVideo, bool ignorePaperColorA, SplashColorPtr paperColor, | |
| + GBool bitmapTopDown, SplashThinLineMode thinLineMode, | |
| + GBool overprintPreview); | |
| + | |
| + void setPartialUpdateCallbackData(Poppler::Page::RenderToImagePartialUpdateFunc callback, Poppler::Page::ShouldRenderToImagePartialQueryFunc shouldDoCallback, const QVariant &payloadA); | |
| + void dump() override; | |
| + QImage getXBGRImage(bool takeImageData); | |
| + | |
| +private: | |
| + Poppler::Page::RenderToImagePartialUpdateFunc partialUpdateCallback; | |
| + Poppler::Page::ShouldRenderToImagePartialQueryFunc shouldDoPartialUpdateCallback; | |
| + QVariant payload; | |
| + bool ignorePaperColor; | |
| +}; | |
| + | |
| +#endif | |
| diff --git a/qt5/src/poppler-annotation.cc b/qt5/src/poppler-annotation.cc | |
| index 42f2e9fe..0f86bb7f 100644 | |
| --- a/qt5/src/poppler-annotation.cc | |
| +++ b/qt5/src/poppler-annotation.cc | |
| @@ -21,49 +21,49 @@ | |
| * You should have received a copy of the GNU General Public License | |
| * along with this program; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. | |
| */ | |
| // qt/kde includes | |
| #include <QtCore/QRegExp> | |
| #include <QtCore/QtAlgorithms> | |
| #include <QtXml/QDomElement> | |
| #include <QtGui/QColor> | |
| #include <QtGui/QTransform> | |
| // local includes | |
| #include "poppler-annotation.h" | |
| #include "poppler-link.h" | |
| #include "poppler-qt5.h" | |
| #include "poppler-annotation-helper.h" | |
| #include "poppler-annotation-private.h" | |
| #include "poppler-page-private.h" | |
| #include "poppler-private.h" | |
| - | |
| -// poppler includes | |
| +#include "Qt5OutputDev.h" | |
| #include <Page.h> | |
| #include <Annot.h> | |
| #include <Gfx.h> | |
| #include <Error.h> | |
| #include <FileSpec.h> | |
| #include <Link.h> | |
| + | |
| /* Almost all getters directly query the underlying poppler annotation, with | |
| * the exceptions of link, file attachment, sound, movie and screen annotations, | |
| * Whose data retrieval logic has not been moved yet. Their getters return | |
| * static data set at creation time by findAnnotations | |
| */ | |
| namespace Poppler { | |
| //BEGIN AnnotationUtils implementation | |
| Annotation * AnnotationUtils::createAnnotation( const QDomElement & annElement ) | |
| { | |
| // safety check on annotation element | |
| if ( !annElement.hasAttribute( QStringLiteral("type") ) ) | |
| return nullptr; | |
| // build annotation of given type | |
| Annotation * annotation = nullptr; | |
| int typeNumber = annElement.attribute( QStringLiteral("type") ).toInt(); | |
| switch ( typeNumber ) | |
| { | |
| @@ -1562,40 +1562,80 @@ QRectF Annotation::boundary() const | |
| return d->boundary; | |
| const PDFRectangle * rect = d->pdfAnnot->getRect(); | |
| return d->fromPdfRectangle( *rect ); | |
| } | |
| void Annotation::setBoundary( const QRectF &boundary ) | |
| { | |
| Q_D( Annotation ); | |
| if (!d->pdfAnnot) | |
| { | |
| d->boundary = boundary; | |
| return; | |
| } | |
| PDFRectangle rect = d->boundaryToPdfRectangle( boundary, flags() ); | |
| d->pdfAnnot->setRect(&rect); | |
| } | |
| +//QImage Annotation::renderToPainter(QPainter* painter, double xres, double yres, int x, int y, int w, int h, Rotation rotate, PainterFlags flags) const { | |
| +// | |
| +//} | |
| + | |
| +QImage Annotation::renderToImage(double hDPI, double vDPI) const | |
| +{ | |
| + Q_D( const Annotation ); | |
| + QImage img; | |
| + switch(d->parentDoc->m_backend) | |
| + { | |
| + case Poppler::Document::SplashBackend: | |
| + { | |
| +#if defined(HAVE_SPLASH) | |
| + int hints = d->parentDoc->m_hints | Poppler::Document::IgnorePaperColor; | |
| + Qt5SplashSettings splashSettings(hints, d->parentDoc->paperColor); | |
| + Qt5SplashOutputDev splash_output(splashSettings); | |
| + splash_output.startDoc( d->parentDoc->doc); | |
| + splash_output.dump(); | |
| + d->pdfAnnot->draw(&splash_output, gFalse, hDPI, vDPI, gTrue); | |
| + splash_output.dump(); | |
| + img = splash_output.getXBGRImage(true); // must happen after delete gfx | |
| +#endif | |
| + break; | |
| + } | |
| + case Poppler::Document::ArthurBackend: | |
| + { | |
| + /* Warning: pdfAnnot->getRect() may not be the real size. Annot::draw choses to ignore that sometimes.*/ | |
| + int x = qRound((d->pdfAnnot->getRect()->x2 - d->pdfAnnot->getRect()->x1) * hDPI / 72.0); | |
| + int y = qRound((d->pdfAnnot->getRect()->y2 - d->pdfAnnot->getRect()->y1) * vDPI / 72.0); | |
| + QImage tmpimg(x, y, QImage::Format_ARGB32); | |
| + ScopedPageQPainter painter(tmpimg, d->parentDoc->m_hints, d->parentDoc->paperColor, Page::DontSaveAndRestore, -1, -1); | |
| + QImageDumpingArthurOutputDev arthur_output(painter, &tmpimg); | |
| + arthur_output.startDoc(d->parentDoc->doc->getXRef()); | |
| + d->pdfAnnot->draw(&arthur_output, gFalse, hDPI, vDPI, gTrue); | |
| + img = tmpimg; | |
| + } | |
| + } | |
| + return img; | |
| +} | |
| + | |
| Annotation::Style Annotation::style() const | |
| { | |
| Q_D( const Annotation ); | |
| if (!d->pdfAnnot) | |
| return d->style; | |
| Style s; | |
| s.setColor(convertAnnotColor( d->pdfAnnot->getColor() )); | |
| const AnnotMarkup *markupann = dynamic_cast<const AnnotMarkup*>(d->pdfAnnot); | |
| if (markupann) | |
| s.setOpacity( markupann->getOpacity() ); | |
| const AnnotBorder *border = d->pdfAnnot->getBorder(); | |
| if (border) | |
| { | |
| if ( border->getType() == AnnotBorder::typeArray ) | |
| { | |
| const AnnotBorderArray *border_array = static_cast<const AnnotBorderArray*>(border); | |
| diff --git a/qt5/src/poppler-annotation.h b/qt5/src/poppler-annotation.h | |
| index a70cbe4f..5c578f6e 100644 | |
| --- a/qt5/src/poppler-annotation.h | |
| +++ b/qt5/src/poppler-annotation.h | |
| @@ -271,40 +271,49 @@ class POPPLER_QT5_EXPORT Annotation | |
| 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 ); | |
| + /** | |
| + * Renders the annotations normal appearance, closed state, into a QImage. | |
| + * It renders the single object onto transparent background. | |
| + * Resulting QImage is in Format_ARGB32_Premultiplied format. | |
| + * | |
| + * \since 0.63 | |
| + */ | |
| + QImage renderToImage(double hDPI, double vDPI) const; | |
| + | |
| /** | |
| * \short Container class for Annotation style information | |
| * | |
| * \since 0.20 | |
| */ | |
| class POPPLER_QT5_EXPORT Style | |
| { | |
| public: | |
| Style(); | |
| Style( const Style &other ); | |
| Style& operator=( const Style &other ); | |
| ~Style(); | |
| // appearance properties | |
| QColor color() const; // black | |
| void setColor(const QColor &color); | |
| double opacity() const; // 1.0 | |
| void setOpacity(double opacity); | |
| // pen properties | |
| diff --git a/qt5/src/poppler-page.cc b/qt5/src/poppler-page.cc | |
| index 381a608b..0fd28e8d 100644 | |
| --- a/qt5/src/poppler-page.cc | |
| +++ b/qt5/src/poppler-page.cc | |
| @@ -50,163 +50,57 @@ | |
| #include <Form.h> | |
| #include <ErrorCodes.h> | |
| #include <TextOutputDev.h> | |
| #include <Annot.h> | |
| #include <Link.h> | |
| #include <ArthurOutputDev.h> | |
| #include <Rendition.h> | |
| #if defined(HAVE_SPLASH) | |
| #include <SplashOutputDev.h> | |
| #include <splash/SplashBitmap.h> | |
| #endif | |
| #include "poppler-private.h" | |
| #include "poppler-page-transition-private.h" | |
| #include "poppler-page-private.h" | |
| #include "poppler-link-extractor-private.h" | |
| #include "poppler-link-private.h" | |
| #include "poppler-annotation-private.h" | |
| #include "poppler-form.h" | |
| #include "poppler-media.h" | |
| +#include "Qt5OutputDev.h" | |
| namespace Poppler { | |
| class TextExtractionAbortHelper | |
| { | |
| public: | |
| TextExtractionAbortHelper(Page::ShouldAbortQueryFunc shouldAbortCallback, const QVariant &payloadA) | |
| { | |
| shouldAbortExtractionCallback = shouldAbortCallback; | |
| payload = payloadA; | |
| } | |
| Page::ShouldAbortQueryFunc shouldAbortExtractionCallback = nullptr; | |
| QVariant payload; | |
| }; | |
| -class OutputDevCallbackHelper | |
| -{ | |
| -public: | |
| - void setCallbacks(Page::RenderToImagePartialUpdateFunc callback, Page::ShouldRenderToImagePartialQueryFunc shouldDoCallback, Page::ShouldAbortQueryFunc shouldAbortCallback, const QVariant &payloadA) | |
| - { | |
| - partialUpdateCallback = callback; | |
| - shouldDoPartialUpdateCallback = shouldDoCallback; | |
| - shouldAbortRenderCallback = shouldAbortCallback; | |
| - payload = payloadA; | |
| - } | |
| - | |
| - Page::RenderToImagePartialUpdateFunc partialUpdateCallback = nullptr; | |
| - Page::ShouldRenderToImagePartialQueryFunc shouldDoPartialUpdateCallback = nullptr; | |
| - Page::ShouldAbortQueryFunc shouldAbortRenderCallback = nullptr; | |
| - QVariant payload; | |
| -}; | |
| - | |
| -class Qt5SplashOutputDev : public SplashOutputDev, public OutputDevCallbackHelper | |
| -{ | |
| -public: | |
| - Qt5SplashOutputDev(SplashColorMode colorModeA, int bitmapRowPadA, | |
| - GBool reverseVideoA, bool ignorePaperColorA, SplashColorPtr paperColorA, | |
| - GBool bitmapTopDownA, SplashThinLineMode thinLineMode, | |
| - GBool overprintPreviewA) | |
| - : SplashOutputDev(colorModeA, bitmapRowPadA, reverseVideoA, paperColorA, bitmapTopDownA, thinLineMode, overprintPreviewA) | |
| - , ignorePaperColor(ignorePaperColorA) | |
| - { | |
| - } | |
| - | |
| - void dump() override | |
| - { | |
| - if (partialUpdateCallback && shouldDoPartialUpdateCallback && shouldDoPartialUpdateCallback(payload)) { | |
| - partialUpdateCallback(getXBGRImage( false /* takeImageData */), payload); | |
| - } | |
| - } | |
| - | |
| - QImage getXBGRImage(bool takeImageData) | |
| - { | |
| - SplashBitmap *b = getBitmap(); | |
| - | |
| - const int bw = b->getWidth(); | |
| - const int bh = b->getHeight(); | |
| - const int brs = b->getRowSize(); | |
| - | |
| - // If we use DeviceN8, convert to XBGR8. | |
| - // If requested, also transfer Splash's internal alpha channel. | |
| - const SplashBitmap::ConversionMode mode = ignorePaperColor | |
| - ? SplashBitmap::conversionAlphaPremultiplied | |
| - : SplashBitmap::conversionOpaque; | |
| - | |
| - const QImage::Format format = ignorePaperColor | |
| - ? QImage::Format_ARGB32_Premultiplied | |
| - : QImage::Format_RGB32; | |
| - | |
| - if (b->convertToXBGR(mode)) { | |
| - SplashColorPtr data = takeImageData ? b->takeData() : b->getDataPtr(); | |
| - | |
| - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { | |
| - // Convert byte order from RGBX to XBGR. | |
| - for (int i = 0; i < bh; ++i) { | |
| - for (int j = 0; j < bw; ++j) { | |
| - SplashColorPtr pixel = &data[i * brs + j]; | |
| - | |
| - qSwap(pixel[0], pixel[3]); | |
| - qSwap(pixel[1], pixel[2]); | |
| - } | |
| - } | |
| - } | |
| - | |
| - if (takeImageData) { | |
| - // Construct a Qt image holding (and also owning) the raw bitmap data. | |
| - return QImage(data, bw, bh, brs, format, gfree, data); | |
| - } else { | |
| - return QImage(data, bw, bh, brs, format).copy(); | |
| - } | |
| - } | |
| - | |
| - return QImage(); | |
| - } | |
| - | |
| -private: | |
| - bool ignorePaperColor; | |
| -}; | |
| - | |
| - | |
| -class QImageDumpingArthurOutputDev : public ArthurOutputDev, public OutputDevCallbackHelper | |
| -{ | |
| -public: | |
| - QImageDumpingArthurOutputDev(QPainter *painter, QImage *i) | |
| - : ArthurOutputDev(painter) | |
| - , image(i) | |
| - { | |
| - } | |
| - | |
| - void dump() override | |
| - { | |
| - if (partialUpdateCallback && shouldDoPartialUpdateCallback && shouldDoPartialUpdateCallback(payload)) { | |
| - partialUpdateCallback(*image, payload); | |
| - } | |
| - } | |
| - | |
| -private: | |
| - QImage *image; | |
| -}; | |
| - | |
| - | |
| - | |
| Link* PageData::convertLinkActionToLink(::LinkAction * a, const QRectF &linkArea) | |
| { | |
| return convertLinkActionToLink(a, parentDoc, linkArea); | |
| } | |
| Link* PageData::convertLinkActionToLink(::LinkAction * a, DocumentData *parentDoc, const QRectF &linkArea) | |
| { | |
| if ( !a ) | |
| return nullptr; | |
| Link * popplerLink = nullptr; | |
| switch ( a->getKind() ) | |
| { | |
| case actionGoTo: | |
| { | |
| LinkGoTo * g = (LinkGoTo *) a; | |
| const LinkDestinationData ldd( g->getDest(), g->getNamedDest(), parentDoc, false ); | |
| // create link: no ext file, namedDest, object pointer | |
| popplerLink = new LinkGoto( linkArea, QString::null, LinkDestination( ldd ) ); | |
| } | |
| @@ -430,186 +324,128 @@ static auto annotDisplayDecideCbk = [](Annot *annot, void *user_data) | |
| static GBool (*nullAnnotCallBack)(Annot *annot, void *user_data) = nullptr; | |
| static auto shouldAbortRenderInternalCallback = [](void *user_data) | |
| { | |
| OutputDevCallbackHelper *helper = reinterpret_cast<OutputDevCallbackHelper*>(user_data); | |
| return helper->shouldAbortRenderCallback(helper->payload); | |
| }; | |
| static auto shouldAbortExtractionInternalCallback = [](void *user_data) | |
| { | |
| TextExtractionAbortHelper *helper = reinterpret_cast<TextExtractionAbortHelper*>(user_data); | |
| return helper->shouldAbortExtractionCallback(helper->payload); | |
| }; | |
| // A nullptr, but with the type of a function pointer | |
| // Needed to make the ternary operator happy. | |
| static GBool (*nullAbortCallBack)(void *user_data) = nullptr; | |
| static bool renderToArthur(QImageDumpingArthurOutputDev *arthur_output, QPainter *painter, PageData *page, double xres, double yres, int x, int y, int w, int h, Page::Rotation rotate, Page::PainterFlags flags) | |
| { | |
| - const bool savePainter = !(flags & Page:: DontSaveAndRestore); | |
| - if (savePainter) | |
| - painter->save(); | |
| - if (page->parentDoc->m_hints & Document::Antialiasing) | |
| - painter->setRenderHint(QPainter::Antialiasing); | |
| - if (page->parentDoc->m_hints & Document::TextAntialiasing) | |
| - painter->setRenderHint(QPainter::TextAntialiasing); | |
| - painter->translate(x == -1 ? 0 : -x, y == -1 ? 0 : -y); | |
| - | |
| + ScopedPageQPainter scopedPainter(painter, page->parentDoc->m_hints, flags, x, y); | |
| arthur_output->startDoc(page->parentDoc->doc->getXRef()); | |
| const GBool hideAnnotations = page->parentDoc->m_hints & Document::HideAnnotations; | |
| OutputDevCallbackHelper *abortHelper = arthur_output; | |
| page->parentDoc->doc->displayPageSlice(arthur_output, | |
| page->index + 1, | |
| xres, | |
| yres, | |
| (int)rotate * 90, | |
| false, | |
| true, | |
| false, | |
| x, | |
| y, | |
| w, | |
| h, | |
| abortHelper->shouldAbortRenderCallback ? shouldAbortRenderInternalCallback : nullAbortCallBack, | |
| abortHelper, | |
| (hideAnnotations) ? annotDisplayDecideCbk : nullAnnotCallBack); | |
| - if (savePainter) | |
| - painter->restore(); | |
| return true; | |
| } | |
| QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h, Rotation rotate) const | |
| { | |
| return renderToImage(xres, yres, x, y, w, h, rotate, nullptr, nullptr, QVariant()); | |
| } | |
| QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h, Rotation rotate, RenderToImagePartialUpdateFunc partialUpdateCallback, ShouldRenderToImagePartialQueryFunc shouldDoPartialUpdateCallback, const QVariant &payload) const | |
| { | |
| return renderToImage(xres, yres, x, y, w, h, rotate, partialUpdateCallback, shouldDoPartialUpdateCallback, nullptr, payload); | |
| } | |
| QImage Page::renderToImage(double xres, double yres, int x, int y, int w, int h, Rotation rotate, RenderToImagePartialUpdateFunc partialUpdateCallback, ShouldRenderToImagePartialQueryFunc shouldDoPartialUpdateCallback, ShouldAbortQueryFunc shouldAbortRenderCallback, const QVariant &payload) const | |
| { | |
| int rotation = (int)rotate * 90; | |
| QImage img; | |
| switch(m_page->parentDoc->m_backend) | |
| { | |
| case Poppler::Document::SplashBackend: | |
| { | |
| #if defined(HAVE_SPLASH) | |
| - SplashColor bgColor; | |
| - GBool overprintPreview = gFalse; | |
| -#ifdef SPLASH_CMYK | |
| - overprintPreview = m_page->parentDoc->m_hints & Document::OverprintPreview ? gTrue : gFalse; | |
| - if (overprintPreview) | |
| - { | |
| - Guchar c, m, y, k; | |
| - | |
| - c = 255 - m_page->parentDoc->paperColor.blue(); | |
| - m = 255 - m_page->parentDoc->paperColor.red(); | |
| - y = 255 - m_page->parentDoc->paperColor.green(); | |
| - k = c; | |
| - if (m < k) { | |
| - k = m; | |
| - } | |
| - if (y < k) { | |
| - k = y; | |
| - } | |
| - bgColor[0] = c - k; | |
| - bgColor[1] = m - k; | |
| - bgColor[2] = y - k; | |
| - bgColor[3] = k; | |
| - for (int i = 4; i < SPOT_NCOMPS + 4; i++) { | |
| - bgColor[i] = 0; | |
| - } | |
| - } | |
| - else | |
| -#endif | |
| - { | |
| - bgColor[0] = m_page->parentDoc->paperColor.blue(); | |
| - bgColor[1] = m_page->parentDoc->paperColor.green(); | |
| - bgColor[2] = m_page->parentDoc->paperColor.red(); | |
| - } | |
| - | |
| - SplashColorMode colorMode = splashModeXBGR8; | |
| -#ifdef SPLASH_CMYK | |
| - if (overprintPreview) colorMode = splashModeDeviceN8; | |
| -#endif | |
| - | |
| - SplashThinLineMode thinLineMode = splashThinLineDefault; | |
| - if (m_page->parentDoc->m_hints & Document::ThinLineShape) thinLineMode = splashThinLineShape; | |
| - if (m_page->parentDoc->m_hints & Document::ThinLineSolid) thinLineMode = splashThinLineSolid; | |
| - | |
| - const bool ignorePaperColor = m_page->parentDoc->m_hints & Document::IgnorePaperColor; | |
| - | |
| - Qt5SplashOutputDev splash_output( | |
| - colorMode, 4, | |
| - gFalse, | |
| - ignorePaperColor, | |
| - ignorePaperColor ? nullptr : bgColor, | |
| - gTrue, | |
| - thinLineMode, | |
| - overprintPreview); | |
| - | |
| + Qt5SplashSettings splashSettings(m_page->parentDoc->m_hints, m_page->parentDoc->paperColor); | |
| + Qt5SplashOutputDev splash_output(splashSettings); | |
| splash_output.setCallbacks(partialUpdateCallback, shouldDoPartialUpdateCallback, shouldAbortRenderCallback, payload); | |
| - | |
| - splash_output.setFontAntialias(m_page->parentDoc->m_hints & Document::TextAntialiasing ? gTrue : gFalse); | |
| - splash_output.setVectorAntialias(m_page->parentDoc->m_hints & Document::Antialiasing ? gTrue : gFalse); | |
| - splash_output.setFreeTypeHinting(m_page->parentDoc->m_hints & Document::TextHinting ? gTrue : gFalse, | |
| - m_page->parentDoc->m_hints & Document::TextSlightHinting ? gTrue : gFalse); | |
| - | |
| splash_output.startDoc(m_page->parentDoc->doc); | |
| const GBool hideAnnotations = m_page->parentDoc->m_hints & Document::HideAnnotations; | |
| - | |
| OutputDevCallbackHelper *abortHelper = &splash_output; | |
| m_page->parentDoc->doc->displayPageSlice(&splash_output, m_page->index + 1, xres, yres, | |
| rotation, false, true, false, x, y, w, h, | |
| shouldAbortRenderCallback ? shouldAbortRenderInternalCallback : nullAbortCallBack, abortHelper, | |
| (hideAnnotations) ? annotDisplayDecideCbk : nullAnnotCallBack, | |
| nullptr, gTrue); | |
| img = splash_output.getXBGRImage( true /* takeImageData */); | |
| #endif | |
| break; | |
| } | |
| case Poppler::Document::ArthurBackend: | |
| { | |
| QSize size = pageSize(); | |
| QImage tmpimg(w == -1 ? qRound( size.width() * xres / 72.0 ) : w, h == -1 ? qRound( size.height() * yres / 72.0 ) : h, QImage::Format_ARGB32); | |
| + ScopedPageQPainter painter(tmpimg, m_page->parentDoc->m_hints, m_page->parentDoc->paperColor, DontSaveAndRestore, x, y); | |
| + QImageDumpingArthurOutputDev arthur_output(painter, &tmpimg); | |
| - QColor bgColor(m_page->parentDoc->paperColor.red(), | |
| - m_page->parentDoc->paperColor.green(), | |
| - m_page->parentDoc->paperColor.blue(), | |
| - m_page->parentDoc->paperColor.alpha()); | |
| + arthur_output.setCallbacks(partialUpdateCallback, shouldDoPartialUpdateCallback, shouldAbortRenderCallback, payload); | |
| + arthur_output.startDoc(m_page->parentDoc->doc->getXRef()); | |
| - tmpimg.fill(bgColor); | |
| + const GBool hideAnnotations = m_page->parentDoc->m_hints & Document::HideAnnotations; | |
| - QPainter painter(&tmpimg); | |
| - QImageDumpingArthurOutputDev arthur_output(&painter, &tmpimg); | |
| - arthur_output.setCallbacks(partialUpdateCallback, shouldDoPartialUpdateCallback, shouldAbortRenderCallback, payload); | |
| - renderToArthur(&arthur_output, &painter, m_page, xres, yres, x, y, w, h, rotate, DontSaveAndRestore); | |
| - painter.end(); | |
| + OutputDevCallbackHelper *abortHelper = &arthur_output; | |
| + m_page->parentDoc->doc->displayPageSlice(&arthur_output, | |
| + m_page->index + 1, | |
| + xres, | |
| + yres, | |
| + (int)rotate * 90, | |
| + false, | |
| + true, | |
| + false, | |
| + x, | |
| + y, | |
| + w, | |
| + h, | |
| + abortHelper->shouldAbortRenderCallback ? shouldAbortRenderInternalCallback : nullAbortCallBack, | |
| + abortHelper, | |
| + (hideAnnotations) ? annotDisplayDecideCbk : nullAnnotCallBack); | |
| img = tmpimg; | |
| break; | |
| } | |
| } | |
| if (shouldAbortRenderCallback && shouldAbortRenderCallback(payload)) | |
| return QImage(); | |
| return img; | |
| } | |
| bool Page::renderToPainter(QPainter* painter, double xres, double yres, int x, int y, int w, int h, Rotation rotate, PainterFlags flags) const | |
| { | |
| if (!painter) | |
| return false; | |
| switch(m_page->parentDoc->m_backend) | |
| { | |
| case Poppler::Document::SplashBackend: | |
| return false; | |
| diff --git a/qt5/tests/CMakeLists.txt b/qt5/tests/CMakeLists.txt | |
| index 1e67e6ec..ca09f11c 100644 | |
| --- a/qt5/tests/CMakeLists.txt | |
| +++ b/qt5/tests/CMakeLists.txt | |
| @@ -37,39 +37,40 @@ macro(QT5_ADD_QTEST exe source) | |
| poppler_add_unittest(${exe} BUILD_QT5_TESTS ${${test_name}_SOURCES}) | |
| target_link_libraries(${exe} poppler-qt5 ${Qt5Widgets_LIBRARIES} ${Qt5Test_LIBRARIES} ${Qt5Core_LIBRARIES} ${Qt5Gui_LIBRARIES}) | |
| if(MSVC) | |
| target_link_libraries(${exe} poppler ${poppler_LIBS}) | |
| endif() | |
| endif () | |
| endmacro(QT5_ADD_QTEST) | |
| qt5_add_simpletest(test-poppler-qt5 test-poppler-qt5.cpp) | |
| qt5_add_simpletest(test-password-qt5 test-password-qt5.cpp) | |
| qt5_add_simpletest(test-render-to-file-qt5 test-render-to-file.cpp) | |
| qt5_add_simpletest(poppler-qt5-forms poppler-forms.cpp) | |
| qt5_add_simpletest(poppler-qt5-fonts poppler-fonts.cpp) | |
| qt5_add_simpletest(poppler-qt5-attachments poppler-attachments.cpp) | |
| qt5_add_simpletest(stress-poppler-qt5 stress-poppler-qt5.cpp) | |
| qt5_add_simpletest(stress-poppler-dir-qt5 stress-poppler-dir.cpp) | |
| qt5_add_simpletest(stress-threads-qt5 stress-threads-qt5.cpp) | |
| qt5_add_simpletest(poppler-qt5-texts poppler-texts.cpp) | |
| +qt5_add_qtest(check_qt5_annotations check_annotations.cpp) | |
| qt5_add_qtest(check_qt5_attachments check_attachments.cpp) | |
| qt5_add_qtest(check_qt5_dateConversion check_dateConversion.cpp) | |
| qt5_add_qtest(check_qt5_fonts check_fonts.cpp) | |
| qt5_add_qtest(check_qt5_links check_links.cpp) | |
| qt5_add_qtest(check_qt5_metadata check_metadata.cpp) | |
| qt5_add_qtest(check_qt5_optcontent check_optcontent.cpp) | |
| qt5_add_qtest(check_qt5_pagelayout check_pagelayout.cpp) | |
| qt5_add_qtest(check_qt5_pagemode check_pagemode.cpp) | |
| qt5_add_qtest(check_qt5_password check_password.cpp) | |
| qt5_add_qtest(check_qt5_permissions check_permissions.cpp) | |
| qt5_add_qtest(check_qt5_search check_search.cpp) | |
| qt5_add_qtest(check_qt5_actualtext check_actualtext.cpp) | |
| qt5_add_qtest(check_qt5_lexer check_lexer.cpp) | |
| qt5_add_qtest(check_qt5_pagelabelinfo check_pagelabelinfo.cpp) | |
| qt5_add_qtest(check_qt5_goostring check_goostring.cpp) | |
| qt5_add_qtest(check_qt5_utf_conversion check_utf_conversion.cpp) | |
| if (NOT WIN32) | |
| qt5_add_qtest(check_qt5_strings check_strings.cpp) | |
| endif () | |
| diff --git a/qt5/tests/check_annotations.cpp b/qt5/tests/check_annotations.cpp | |
| new file mode 100644 | |
| index 00000000..312e5112 | |
| --- /dev/null | |
| +++ b/qt5/tests/check_annotations.cpp | |
| @@ -0,0 +1,57 @@ | |
| +#include <QtTest/QtTest> | |
| + | |
| +#include "PDFDoc.h" | |
| +#include "GlobalParams.h" | |
| + | |
| +#include <poppler-qt5.h> | |
| + | |
| +class TestAnnotations: public QObject | |
| +{ | |
| + Q_OBJECT | |
| +private slots: | |
| + void checkRenderToImage(); | |
| + void checkRenderToImage_data(); | |
| +}; | |
| + | |
| +void TestAnnotations::checkRenderToImage_data() | |
| +{ | |
| + QTest::addColumn<int>("dpi"); | |
| + QTest::addColumn<int>("backend"); | |
| + | |
| + QTest::newRow("Splash 100dpi") | |
| + << int(100) | |
| + << static_cast<int>(Poppler::Document::SplashBackend); | |
| + | |
| + QTest::newRow("Arthur 100dpi") | |
| + << int(100) | |
| + << static_cast<int>(Poppler::Document::ArthurBackend); | |
| +} | |
| + | |
| +void TestAnnotations::checkRenderToImage() | |
| +{ | |
| + QFETCH(int, dpi); | |
| + QFETCH(int, backend); | |
| + Poppler::Document *doc; | |
| + doc = Poppler::Document::load(TESTDATADIR "/unittestcases/annots_test.pdf"); | |
| + QVERIFY( doc ); | |
| + | |
| + Poppler::Page* page = doc->page(0); | |
| + QVERIFY( page ); | |
| + | |
| + /* Free Text - Subtype freetext, 72 x 72 pts. */ | |
| + Poppler::Annotation* annot = page->annotations()[0]; | |
| + QVERIFY( annot ); | |
| + doc->setRenderBackend(static_cast<Poppler::Document::RenderBackend>(backend)); | |
| + QImage image = annot->renderToImage(dpi, dpi); | |
| + qDebug() << image.size(); | |
| + QCOMPARE( image.size(), QSize(dpi, dpi) ); // 72pts x 72pts @ 100dpi = 100px x 100px | |
| + QCOMPARE(QColor( image.pixel( 0, 0 ) ), QColor(0, 0, 0)); // black border @ top left | |
| + QCOMPARE(QColor( image.pixel( 49, 49 ) ), QColor(0, 0, 255)); // blue background @ center | |
| + QCOMPARE(QColor( image.pixel( 99, 99 ) ), QColor(0, 0, 0)); | |
| + | |
| + delete doc; | |
| +} | |
| + | |
| +QTEST_GUILESS_MAIN(TestAnnotations) | |
| + | |
| +#include "check_annotations.moc" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment