[poppler] 2 commits - poppler/Annot.cc poppler/Annot.h
Albert Astals Cid
aacid at kemper.freedesktop.org
Wed Apr 11 16:37:00 PDT 2012
poppler/Annot.cc | 408 +++++++++++++++++++++++++++++++++++++++----------------
poppler/Annot.h | 3
2 files changed, 298 insertions(+), 113 deletions(-)
New commits:
commit 46b3a70cae3b37cb4270a83afaddd6734442b752
Author: Fabio D'Urso <fabiodurso at hotmail.it>
Date: Mon Apr 9 19:32:24 2012 +0200
Caption text rendering in AnnotLine
diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index d733501..5d03e33 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -3101,111 +3101,202 @@ void AnnotLine::setIntent(AnnotLineIntent new_intent) {
update ("IT", &obj1);
}
-void AnnotLine::draw(Gfx *gfx, GBool printing) {
- Object obj;
- double ca = 1;
+void AnnotLine::generateLineAppearance()
+{
+ double borderWidth, ca = opacity;
- if (!isVisible (printing))
- return;
+ appearBBox = new AnnotAppearanceBBox(rect);
+ appearBuf = new GooString ();
+ appearBuf->append ("q\n");
+ if (color) {
+ setColor(color, gFalse);
+ }
- if (appearance.isNull()) {
- appearBBox = new AnnotAppearanceBBox(rect);
- ca = opacity;
+ if (border) {
+ int i, dashLength;
+ double *dash;
- appearBuf = new GooString ();
- appearBuf->append ("q\n");
- if (color)
- setColor(color, gFalse);
+ switch (border->getStyle()) {
+ case AnnotBorder::borderDashed:
+ appearBuf->append("[");
+ dashLength = border->getDashLength();
+ dash = border->getDash();
+ for (i = 0; i < dashLength; ++i)
+ appearBuf->appendf(" {0:.2f}", dash[i]);
+ appearBuf->append(" ] 0 d\n");
+ break;
+ default:
+ appearBuf->append("[] 0 d\n");
+ break;
+ }
+ borderWidth = border->getWidth();
+ appearBuf->appendf("{0:.2f} w\n", borderWidth);
+ appearBBox->setBorderWidth(borderWidth);
+ } else {
+ borderWidth = 0;
+ }
- if (border) {
- int i, dashLength;
- double *dash;
+ const double x1 = coord1->getX();
+ const double y1 = coord1->getY();
+ const double x2 = coord2->getX();
+ const double y2 = coord2->getY();
- switch (border->getStyle()) {
- case AnnotBorder::borderDashed:
- appearBuf->append("[");
- dashLength = border->getDashLength();
- dash = border->getDash();
- for (i = 0; i < dashLength; ++i)
- appearBuf->appendf(" {0:.2f}", dash[i]);
- appearBuf->append(" ] 0 d\n");
- break;
- default:
- appearBuf->append("[] 0 d\n");
- break;
+ // Main segment length
+ const double main_len = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
+
+ // Main segment becomes positive x direction, coord1 becomes (0,0)
+ Matrix matr;
+ const double angle = atan2(y2 - y1, x2 - x1);
+ matr.m[0] = matr.m[3] = cos(angle);
+ matr.m[1] = sin(angle);
+ matr.m[2] = -matr.m[1];
+ matr.m[4] = x1-rect->x1;
+ matr.m[5] = y1-rect->y1;
+
+ double tx, ty, captionwidth = 0, captionheight = 0;
+ AnnotLineCaptionPos actualCaptionPos = captionPos;
+ const double fontsize = 9;
+ const double captionhmargin = 2; // Left and right margin (inline caption only)
+ const double captionmaxwidth = main_len - 2 * captionhmargin;
+
+ Object fontResDict;
+ GfxFont *font;
+
+ // Calculate caption width and height
+ if (caption) {
+ font = createAnnotDrawFont(xref, &fontResDict);
+ int lines = 0;
+ int i = 0;
+ while (i < contents->getLength()) {
+ GooString out;
+ double linewidth;
+ layoutText(contents, &out, &i, font, &linewidth, 0, NULL, gFalse);
+ linewidth *= fontsize;
+ if (linewidth > captionwidth) {
+ captionwidth = linewidth;
}
- appearBuf->appendf("{0:.2f} w\n", border->getWidth());
- appearBBox->setBorderWidth(border->getWidth());
+ ++lines;
}
+ captionheight = lines * fontsize;
+ // If text is longer than available space, turn into captionPosTop
+ if (captionwidth > captionmaxwidth) {
+ actualCaptionPos = captionPosTop;
+ }
+ } else {
+ fontResDict.initNull();
+ font = NULL;
+ }
- const double x1 = coord1->getX();
- const double y1 = coord1->getY();
- const double x2 = coord2->getX();
- const double y2 = coord2->getY();
+ // Draw main segment
+ matr.transform (0, leaderLineLength, &tx, &ty);
+ appearBuf->appendf ("{0:.2f} {1:.2f} m\n", tx, ty);
+ appearBBox->extendTo (tx, ty);
- // Main segment length
- const double main_len = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
+ if (captionwidth != 0 && actualCaptionPos == captionPosInline) { // Break in the middle
+ matr.transform ((main_len-captionwidth)/2 - captionhmargin, leaderLineLength, &tx, &ty);
+ appearBuf->appendf ("{0:.2f} {1:.2f} l S\n", tx, ty);
- // Main segment becomes positive x direction, coord1 becomes (0,0)
- Matrix matr;
- const double angle = atan2(y2 - y1, x2 - x1);
- matr.m[0] = matr.m[3] = cos(angle);
- matr.m[1] = sin(angle);
- matr.m[2] = -matr.m[1];
- matr.m[4] = x1-rect->x1;
- matr.m[5] = y1-rect->y1;
+ matr.transform ((main_len+captionwidth)/2 + captionhmargin, leaderLineLength, &tx, &ty);
+ appearBuf->appendf ("{0:.2f} {1:.2f} m\n", tx, ty);
+ }
- double tx, ty;
+ matr.transform (main_len, leaderLineLength, &tx, &ty);
+ appearBuf->appendf ("{0:.2f} {1:.2f} l S\n", tx, ty);
+ appearBBox->extendTo (tx, ty);
- // Draw main segment
- matr.transform (0, leaderLineLength, &tx, &ty);
- appearBuf->appendf ("{0:.2f} {1:.2f} m\n", tx, ty);
+ // TODO: Line endings
+
+ // Draw caption text
+ if (caption) {
+ double tlx = (main_len - captionwidth) / 2, tly; // Top-left coords
+ if (actualCaptionPos == captionPosInline) {
+ tly = leaderLineLength + captionheight / 2;
+ } else {
+ tly = leaderLineLength + captionheight + 2*borderWidth;
+ }
+
+ tlx += captionTextHorizontal;
+ tly += captionTextVertical;
+
+ // Adjust bounding box
+ matr.transform (tlx, tly-captionheight, &tx, &ty);
+ appearBBox->extendTo (tx, ty);
+ matr.transform (tlx+captionwidth, tly-captionheight, &tx, &ty);
+ appearBBox->extendTo (tx, ty);
+ matr.transform (tlx+captionwidth, tly, &tx, &ty);
+ appearBBox->extendTo (tx, ty);
+ matr.transform (tlx, tly, &tx, &ty);
appearBBox->extendTo (tx, ty);
- matr.transform (main_len, leaderLineLength, &tx, &ty);
+ // Setup text state (reusing transformed top-left coord)
+ appearBuf->appendf ("0 g BT /AnnotDrawFont {0:.2f} Tf\n", fontsize); // Font color: black
+ appearBuf->appendf ("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} Tm\n",
+ matr.m[0], matr.m[1], matr.m[2], matr.m[3], tx, ty);
+ appearBuf->appendf ("0 {0:.2f} Td\n", -fontsize * font->getDescent());
+ // Draw text
+ int i = 0;
+ double xposPrev = 0;
+ while (i < contents->getLength()) {
+ GooString out;
+ double linewidth, xpos;
+ layoutText(contents, &out, &i, font, &linewidth, 0, NULL, gFalse);
+ linewidth *= fontsize;
+ xpos = (captionwidth - linewidth) / 2;
+ appearBuf->appendf("{0:.2f} {1:.2f} Td\n", xpos - xposPrev, -fontsize);
+ writeString(&out, appearBuf);
+ appearBuf->append ("Tj\n");
+ xposPrev = xpos;
+ }
+ appearBuf->append ("ET\n");
+ font->decRefCnt();
+ }
+
+ // Draw leader lines
+ double ll_len = fabs(leaderLineLength) + leaderLineExtension;
+ double sign = leaderLineLength >= 0 ? 1 : -1;
+ if (ll_len != 0) {
+ matr.transform (0, 0, &tx, &ty);
+ appearBuf->appendf ("{0:.2f} {1:.2f} m\n", tx, ty);
+ appearBBox->extendTo (tx, ty);
+ matr.transform (0, sign*ll_len, &tx, &ty);
appearBuf->appendf ("{0:.2f} {1:.2f} l S\n", tx, ty);
appearBBox->extendTo (tx, ty);
- // TODO: Line ending, caption
-
- // Draw leader lines
- double ll_len = fabs(leaderLineLength) + leaderLineExtension;
- double sign = leaderLineLength >= 0 ? 1 : -1;
- if (ll_len != 0) {
- matr.transform (0, 0, &tx, &ty);
- appearBuf->appendf ("{0:.2f} {1:.2f} m\n", tx, ty);
- appearBBox->extendTo (tx, ty);
+ matr.transform (main_len, 0, &tx, &ty);
+ appearBuf->appendf ("{0:.2f} {1:.2f} m\n", tx, ty);
+ appearBBox->extendTo (tx, ty);
+ matr.transform (main_len, sign*ll_len, &tx, &ty);
+ appearBuf->appendf ("{0:.2f} {1:.2f} l S\n", tx, ty);
+ appearBBox->extendTo (tx, ty);
+ }
- matr.transform (0, sign*ll_len, &tx, &ty);
- appearBuf->appendf ("{0:.2f} {1:.2f} l S\n", tx, ty);
- appearBBox->extendTo (tx, ty);
+ appearBuf->append ("Q\n");
- matr.transform (main_len, 0, &tx, &ty);
- appearBuf->appendf ("{0:.2f} {1:.2f} m\n", tx, ty);
- appearBBox->extendTo (tx, ty);
+ double bbox[4];
+ appearBBox->getBBoxRect(bbox);
+ if (ca == 1) {
+ createForm(bbox, gFalse, &fontResDict, &appearance);
+ } else {
+ Object aStream, resDict;
- matr.transform (main_len, sign*ll_len, &tx, &ty);
- appearBuf->appendf ("{0:.2f} {1:.2f} l S\n", tx, ty);
- appearBBox->extendTo (tx, ty);
- }
+ createForm(bbox, gTrue, &fontResDict, &aStream);
+ delete appearBuf;
- appearBuf->append ("Q\n");
+ appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
+ createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
+ createForm(bbox, gFalse, &resDict, &appearance);
+ }
+ delete appearBuf;
+}
- double bbox[4];
- appearBBox->getBBoxRect(bbox);
- if (ca == 1) {
- createForm(bbox, gFalse, NULL, &appearance);
- } else {
- Object aStream, resDict;
+void AnnotLine::draw(Gfx *gfx, GBool printing) {
+ Object obj;
- createForm(bbox, gTrue, NULL, &aStream);
- delete appearBuf;
+ if (!isVisible (printing))
+ return;
- appearBuf = new GooString ("/GS0 gs\n/Fm0 Do");
- createResourcesDict("Fm0", &aStream, "GS0", ca, NULL, &resDict);
- createForm(bbox, gFalse, &resDict, &appearance);
- }
- delete appearBuf;
+ if (appearance.isNull()) {
+ generateLineAppearance();
}
// draw the appearance stream
@@ -3221,6 +3312,15 @@ void AnnotLine::draw(Gfx *gfx, GBool printing) {
obj.free();
}
+// 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(Object *dest) {
+ if (appearance.isNull()) {
+ generateLineAppearance();
+ }
+ return Annot::getAppearanceResDict(dest);
+}
+
//------------------------------------------------------------------------
// AnnotTextMarkup
//------------------------------------------------------------------------
diff --git a/poppler/Annot.h b/poppler/Annot.h
index e3afbc3..98e4d70 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -932,6 +932,7 @@ public:
~AnnotLine();
virtual void draw(Gfx *gfx, GBool printing);
+ virtual Object *getAppearanceResDict(Object *dest);
void setVertices(double x1, double y1, double x2, double y2);
void setStartEndStyle(AnnotLineEndingStyle start, AnnotLineEndingStyle end);
@@ -962,6 +963,7 @@ public:
protected:
void initialize(PDFDoc *docA, Dict *dict);
+ void generateLineAppearance();
// required
AnnotCoord *coord1, *coord2;
commit 855607828447ecec2c8444650d015e21bd17d2e2
Author: Fabio D'Urso <fabiodurso at hotmail.it>
Date: Mon Apr 9 16:45:50 2012 +0200
AnnotFreeText rendering improvements (auto word-wrap, quadding, border style, font/border color)
diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 53d71ed..d733501 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -2649,26 +2649,14 @@ static GfxFont * createAnnotDrawFont(XRef * xref, Object *fontResDict)
return GfxFont::makeFont(xref, "AnnotDrawFont", dummyRef, fontDict);
}
-void AnnotFreeText::generateFreeTextAppearance()
-{
- double ca = opacity;
-
- appearBuf = new GooString ();
- appearBuf->append ("q\n");
- if (color) {
- setColor(color, gTrue);
- }
-
- // Main segment length
- const double width = rect->x2 - rect->x1;
- const double height = rect->y2 - rect->y1;
-
- // Parse text size from appearance string (TODO: other properties)
- double fontsize = 0;
- GooString * da = appearanceString;
+void AnnotFreeText::parseAppearanceString(GooString *da, double &fontsize, AnnotColor* &fontcolor) {
+ fontsize = -1;
+ fontcolor = NULL;
if (da) {
GooList * daToks = new GooList();
int j, i = 0;
+
+ // Tokenize
while (i < da->getLength()) {
while (i < da->getLength() && Lexer::isSpace(da->getChar(i))) {
++i;
@@ -2680,39 +2668,133 @@ void AnnotFreeText::generateFreeTextAppearance()
i = j;
}
}
- for (i = 2; i < daToks->getLength(); ++i) {
- if (!((GooString *)daToks->get(i))->cmp("Tf")) {
- GooString * tok = (GooString *)daToks->get(i - 1);
- fontsize = gatof(tok->getCString());
- break;
+
+ // Scan backwards: we are looking for the last set value
+ for (i = daToks->getLength()-1; i >= 0; --i) {
+ if (fontsize == -1) {
+ if (!((GooString *)daToks->get(i))->cmp("Tf") && i >= 2) {
+ // TODO: Font name
+ fontsize = gatof(( (GooString *)daToks->get(i-1) )->getCString());
+ }
+ }
+ if (fontcolor == NULL) {
+ if (!((GooString *)daToks->get(i))->cmp("g") && i >= 1) {
+ fontcolor = new AnnotColor(gatof(( (GooString *)daToks->get(i-1) )->getCString()));
+ } else if (!((GooString *)daToks->get(i))->cmp("rg") && i >= 3) {
+ fontcolor = new AnnotColor(gatof(( (GooString *)daToks->get(i-3) )->getCString()),
+ gatof(( (GooString *)daToks->get(i-2) )->getCString()),
+ gatof(( (GooString *)daToks->get(i-1) )->getCString()));
+ } else if (!((GooString *)daToks->get(i))->cmp("k") && i >= 4) {
+ fontcolor = new AnnotColor(gatof(( (GooString *)daToks->get(i-4) )->getCString()),
+ gatof(( (GooString *)daToks->get(i-3) )->getCString()),
+ gatof(( (GooString *)daToks->get(i-2) )->getCString()),
+ gatof(( (GooString *)daToks->get(i-1) )->getCString()));
+ }
}
}
deleteGooList(daToks, GooString);
}
- if (fontsize <= 0) {
- fontsize = 10; // Default value
+}
+
+void AnnotFreeText::generateFreeTextAppearance()
+{
+ double borderWidth, ca = opacity;
+
+ appearBuf = new GooString ();
+ appearBuf->append ("q\n");
+
+ if (border) {
+ int i, dashLength;
+ double *dash;
+ borderWidth = border->getWidth();
+
+ switch (border->getStyle()) {
+ case AnnotBorder::borderDashed:
+ appearBuf->append("[");
+ dashLength = border->getDashLength();
+ dash = border->getDash();
+ for (i = 0; i < dashLength; ++i)
+ appearBuf->appendf(" {0:.2f}", dash[i]);
+ appearBuf->append(" ] 0 d\n");
+ break;
+ default:
+ appearBuf->append("[] 0 d\n");
+ break;
+ }
+ appearBuf->appendf("{0:.2f} w\n", borderWidth);
+ } else {
+ borderWidth = 0; // No border
}
- // Draw box and setup clipping
- appearBuf->appendf ("[] 0 d 1 w 0 G 0 0 {0:.2f} {1:.2f} re b\n", width, height);
- appearBuf->appendf ("2 0 {0:.2f} {1:.2f} re W n\n", width-4, height);
+ // Box size
+ const double width = rect->x2 - rect->x1;
+ const double height = rect->y2 - rect->y1;
- // Set font state
- appearBuf->appendf ("0 g BT 1 0 0 1 2 {0:.2f} Tm\n", height);
- appearBuf->appendf ("{0:.2f} TL /AnnotDrawFont {0:.2f} Tf\n", fontsize);
+ // Parse some properties from the appearance string
+ double fontsize;
+ AnnotColor *fontcolor;
+ parseAppearanceString(appearanceString, fontsize, fontcolor);
+ // Default values
+ if (fontsize <= 0)
+ fontsize = 10;
+ if (fontcolor == NULL)
+ fontcolor = new AnnotColor(0, 0, 0); // Black
+
+ // Draw box
+ GBool doFill = (color && color->getSpace() != AnnotColor::colorTransparent);
+ GBool doStroke = (borderWidth != 0);
+ if (doFill || doStroke) {
+ if (doStroke) {
+ setColor(fontcolor, gFalse); // Border color: same as font color
+ }
+ appearBuf->appendf ("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re\n", borderWidth/2, width-borderWidth, height-borderWidth);
+ if (doFill) {
+ setColor(color, gTrue);
+ appearBuf->append(doStroke ? "B\n" : "f\n");
+ } else {
+ appearBuf->append("S\n");
+ }
+ }
+
+ // Setup text clipping
+ const double textmargin = borderWidth * 2;
+ const double textwidth = width - 2*textmargin;
+ appearBuf->appendf ("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re W n\n", textmargin, textwidth, height - 2*textmargin);
Object fontResDict;
GfxFont *font = createAnnotDrawFont(xref, &fontResDict);
+ // Set font state
+ setColor(fontcolor, gTrue);
+ appearBuf->appendf ("BT 1 0 0 1 {0:.2f} {1:.2f} Tm\n", textmargin, height - textmargin - fontsize * font->getDescent());
+ appearBuf->appendf ("/AnnotDrawFont {0:.2f} Tf\n", fontsize);
+
int i = 0;
+ double xposPrev = 0;
while (i < contents->getLength()) {
GooString out;
- layoutText(contents, &out, &i, font, NULL, 0, NULL, gFalse);
+ double linewidth, xpos;
+ layoutText(contents, &out, &i, font, &linewidth, textwidth/fontsize, NULL, gFalse);
+ linewidth *= fontsize;
+ switch (quadding) {
+ case quaddingCentered:
+ xpos = (textwidth - linewidth) / 2;
+ break;
+ case quaddingRightJustified:
+ xpos = textwidth - linewidth;
+ break;
+ default: // quaddingLeftJustified:
+ xpos = 0;
+ break;
+ }
+ appearBuf->appendf("{0:.2f} {1:.2f} Td\n", xpos - xposPrev, -fontsize);
writeString(&out, appearBuf);
- appearBuf->append("'\n");
+ appearBuf->append("Tj\n");
+ xposPrev = xpos;
}
font->decRefCnt();
+ delete fontcolor;
appearBuf->append ("ET Q\n");
double bbox[4];
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 2e64ac9..e3afbc3 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -891,6 +891,7 @@ public:
protected:
void initialize(PDFDoc *docA, Dict *dict);
+ static void parseAppearanceString(GooString *da, double &fontsize, AnnotColor* &fontcolor);
void generateFreeTextAppearance();
// required
More information about the poppler
mailing list