📄 annot.cc
字号:
} else { appearBuf->append(c); } } appearBuf->append(") Tj\n"); } } // cleanup appearBuf->append("ET\n"); appearBuf->append("Q\n"); if (txField) { appearBuf->append("EMC\n"); } if (daToks) { deleteGList(daToks, GString); }}// Draw the variable text or caption for a field.void Annot::drawListBox(GString **text, GBool *selection, int nOptions, int topIdx, GString *da, GfxFontDict *fontDict, GBool quadding) { GList *daToks; GString *tok; GfxFont *font; double fontSize, fontSize2, border, x, y, w, wMax; int tfPos, tmPos, i, j, c; //~ if there is no MK entry, this should use the existing content stream, //~ and only replace the marked content portion of it //~ (this is only relevant for Tx fields) // parse the default appearance string tfPos = tmPos = -1; if (da) { daToks = new GList(); i = 0; while (i < da->getLength()) { while (i < da->getLength() && Lexer::isSpace(da->getChar(i))) { ++i; } if (i < da->getLength()) { for (j = i + 1; j < da->getLength() && !Lexer::isSpace(da->getChar(j)); ++j) ; daToks->append(new GString(da, i, j - i)); i = j; } } for (i = 2; i < daToks->getLength(); ++i) { if (i >= 2 && !((GString *)daToks->get(i))->cmp("Tf")) { tfPos = i - 2; } else if (i >= 6 && !((GString *)daToks->get(i))->cmp("Tm")) { tmPos = i - 6; } } } else { daToks = NULL; } // get the font and font size font = NULL; fontSize = 0; if (tfPos >= 0) { tok = (GString *)daToks->get(tfPos); if (tok->getLength() >= 1 && tok->getChar(0) == '/') { if (!fontDict || !(font = fontDict->lookup(tok->getCString() + 1))) { error(-1, "Unknown font in field's DA string"); } } else { error(-1, "Invalid font name in 'Tf' operator in field's DA string"); } tok = (GString *)daToks->get(tfPos + 1); fontSize = atof(tok->getCString()); } else { error(-1, "Missing 'Tf' operator in field's DA string"); } // get the border width border = borderStyle->getWidth(); // compute font autosize if (fontSize == 0) { wMax = 0; for (i = 0; i < nOptions; ++i) { if (font && !font->isCIDFont()) { w = 0; for (j = 0; j < text[i]->getLength(); ++j) { w += ((Gfx8BitFont *)font)->getWidth(text[i]->getChar(j)); } } else { // otherwise, make a crude estimate w = text[i]->getLength() * 0.5; } if (w > wMax) { wMax = w; } } fontSize = yMax - yMin - 2 * border; fontSize2 = (xMax - xMin - 4 - 2 * border) / wMax; if (fontSize2 < fontSize) { fontSize = fontSize2; } fontSize = floor(fontSize); if (tfPos >= 0) { tok = (GString *)daToks->get(tfPos + 1); tok->clear(); tok->appendf("{0:.2f}", fontSize); } } // draw the text y = yMax - yMin - 1.1 * fontSize; for (i = topIdx; i < nOptions; ++i) { // setup appearBuf->append("q\n"); // draw the background if selected if (selection[i]) { appearBuf->append("0 g f\n"); appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} re f\n", border, y - 0.2 * fontSize, xMax - xMin - 2 * border, 1.1 * fontSize); } // setup appearBuf->append("BT\n"); // compute string width if (font && !font->isCIDFont()) { w = 0; for (j = 0; j < text[i]->getLength(); ++j) { w += ((Gfx8BitFont *)font)->getWidth(text[i]->getChar(j)); } } else { // otherwise, make a crude estimate w = text[i]->getLength() * 0.5; } // compute text start position w *= fontSize; switch (quadding) { case fieldQuadLeft: default: x = border + 2; break; case fieldQuadCenter: x = (xMax - xMin - w) / 2; break; case fieldQuadRight: x = xMax - xMin - border - 2 - w; break; } // set the font matrix if (tmPos >= 0) { tok = (GString *)daToks->get(tmPos + 4); tok->clear(); tok->appendf("{0:.2f}", x); tok = (GString *)daToks->get(tmPos + 5); tok->clear(); tok->appendf("{0:.2f}", y); } // write the DA string if (daToks) { for (j = 0; j < daToks->getLength(); ++j) { appearBuf->append((GString *)daToks->get(j))->append(' '); } } // write the font matrix (if not part of the DA string) if (tmPos < 0) { appearBuf->appendf("1 0 0 1 {0:.2f} {1:.2f} Tm\n", x, y); } // change the text color if selected if (selection[i]) { appearBuf->append("1 g\n"); } // write the text string appearBuf->append('('); for (j = 0; j < text[i]->getLength(); ++j) { c = text[i]->getChar(j) & 0xff; if (c == '(' || c == ')' || c == '\\') { appearBuf->append('\\'); appearBuf->append(c); } else if (c < 0x20 || c >= 0x80) { appearBuf->appendf("\\{0:03o}", c); } else { appearBuf->append(c); } } appearBuf->append(") Tj\n"); // cleanup appearBuf->append("ET\n"); appearBuf->append("Q\n"); // next line y -= 1.1 * fontSize; } if (daToks) { deleteGList(daToks, GString); }}// Figure out how much text will fit on the next line. Returns:// *end = one past the last character to be included// *width = width of the characters start .. end-1// *next = index of first character on the following linevoid Annot::getNextLine(GString *text, int start, GfxFont *font, double fontSize, double wMax, int *end, double *width, int *next) { double w, dw; int j, k, c; // figure out how much text will fit on the line //~ what does Adobe do with tabs? w = 0; for (j = start; j < text->getLength() && w <= wMax; ++j) { c = text->getChar(j) & 0xff; if (c == 0x0a || c == 0x0d) { break; } if (font && !font->isCIDFont()) { dw = ((Gfx8BitFont *)font)->getWidth(c) * fontSize; } else { // otherwise, make a crude estimate dw = 0.5 * fontSize; } w += dw; } if (w > wMax) { for (k = j; k > start && text->getChar(k-1) != ' '; --k) ; for (; k > start && text->getChar(k-1) == ' '; --k) ; if (k > start) { j = k; } if (j == start) { // handle the pathological case where the first character is // too wide to fit on the line all by itself j = start + 1; } } *end = j; // compute the width w = 0; for (k = start; k < j; ++k) { if (font && !font->isCIDFont()) { dw = ((Gfx8BitFont *)font)->getWidth(text->getChar(k)) * fontSize; } else { // otherwise, make a crude estimate dw = 0.5 * fontSize; } w += dw; } *width = w; // next line while (j < text->getLength() && text->getChar(j) == ' ') { ++j; } if (j < text->getLength() && text->getChar(j) == 0x0d) { ++j; } if (j < text->getLength() && text->getChar(j) == 0x0a) { ++j; } *next = j;}// Draw an (approximate) circle of radius <r> centered at (<cx>, <cy>).// If <fill> is true, the circle is filled; otherwise it is stroked.void Annot::drawCircle(double cx, double cy, double r, GBool fill) { appearBuf->appendf("{0:.2f} {1:.2f} m\n", cx + r, cy); appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx + r, cy + bezierCircle * r, cx + bezierCircle * r, cy + r, cx, cy + r); appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx - bezierCircle * r, cy + r, cx - r, cy + bezierCircle * r, cx - r, cy); appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx - r, cy - bezierCircle * r, cx - bezierCircle * r, cy - r, cx, cy - r); appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx + bezierCircle * r, cy - r, cx + r, cy - bezierCircle * r, cx + r, cy); appearBuf->append(fill ? "f\n" : "s\n");}// Draw the top-left half of an (approximate) circle of radius <r>// centered at (<cx>, <cy>).void Annot::drawCircleTopLeft(double cx, double cy, double r) { double r2; r2 = r / sqrt(2.0); appearBuf->appendf("{0:.2f} {1:.2f} m\n", cx + r2, cy + r2); appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx + (1 - bezierCircle) * r2, cy + (1 + bezierCircle) * r2, cx - (1 - bezierCircle) * r2, cy + (1 + bezierCircle) * r2, cx - r2, cy + r2); appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx - (1 + bezierCircle) * r2, cy + (1 - bezierCircle) * r2, cx - (1 + bezierCircle) * r2, cy - (1 - bezierCircle) * r2, cx - r2, cy - r2); appearBuf->append("S\n");}// Draw the bottom-right half of an (approximate) circle of radius <r>// centered at (<cx>, <cy>).void Annot::drawCircleBottomRight(double cx, double cy, double r) { double r2; r2 = r / sqrt(2.0); appearBuf->appendf("{0:.2f} {1:.2f} m\n", cx - r2, cy - r2); appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx - (1 - bezierCircle) * r2, cy - (1 + bezierCircle) * r2, cx + (1 - bezierCircle) * r2, cy - (1 + bezierCircle) * r2, cx + r2, cy - r2); appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx + (1 + bezierCircle) * r2, cy - (1 - bezierCircle) * r2, cx + (1 + bezierCircle) * r2, cy + (1 - bezierCircle) * r2, cx + r2, cy + r2); appearBuf->append("S\n");}// Look up an inheritable field dictionary entry.Object *Annot::fieldLookup(Dict *field, char *key, Object *obj) { Dict *dict; Object parent; dict = field; if (!dict->lookup(key, obj)->isNull()) { return obj; } obj->free(); if (dict->lookup("Parent", &parent)->isDict()) { fieldLookup(parent.getDict(), key, obj); } else { obj->initNull(); } parent.free(); return obj;}void Annot::draw(Gfx *gfx, GBool printing) { Object obj; GBool isLink; // check the flags if ((flags & annotFlagHidden) || (printing && !(flags & annotFlagPrint)) || (!printing && (flags & annotFlagNoView))) { return; } // draw the appearance stream isLink = type && !type->cmp("Link"); appearance.fetch(xref, &obj); gfx->drawAnnot(&obj, isLink ? borderStyle : (AnnotBorderStyle *)NULL, xMin, yMin, xMax, yMax); obj.free();}//------------------------------------------------------------------------// Annots//------------------------------------------------------------------------Annots::Annots(XRef *xref, Catalog *catalog, Object *annotsObj) { Dict *acroForm; Annot *annot; Object obj1; Ref ref; int size; int i; annots = NULL; size = 0; nAnnots = 0; acroForm = catalog->getAcroForm()->isDict() ? catalog->getAcroForm()->getDict() : NULL; if (annotsObj->isArray()) { for (i = 0; i < annotsObj->arrayGetLength(); ++i) { if (annotsObj->arrayGetNF(i, &obj1)->isRef()) { ref = obj1.getRef(); obj1.free(); annotsObj->arrayGet(i, &obj1); } else { ref.num = ref.gen = -1; } if (obj1.isDict()) { annot = new Annot(xref, acroForm, obj1.getDict(), &ref); if (annot->isOk()) { if (nAnnots >= size) { size += 16; annots = (Annot **)greallocn(annots, size, sizeof(Annot *)); } annots[nAnnots++] = annot; } else { delete annot; } } obj1.free(); } }}Annots::~Annots() { int i; for (i = 0; i < nAnnots; ++i) { delete annots[i]; } gfree(annots);}void Annots::generateAppearances(Dict *acroForm) { Object obj1, obj2; Ref ref; int i; if (acroForm->lookup("Fields", &obj1)->isArray()) { for (i = 0; i < obj1.arrayGetLength(); ++i) { if (obj1.arrayGetNF(i, &obj2)->isRef()) { ref = obj2.getRef(); obj2.free(); obj1.arrayGet(i, &obj2); } else { ref.num = ref.gen = -1; } if (obj2.isDict()) { scanFieldAppearances(obj2.getDict(), &ref, NULL, acroForm); } obj2.free(); } } obj1.free();}void Annots::scanFieldAppearances(Dict *node, Ref *ref, Dict *parent, Dict *acroForm) { Annot *annot; Object obj1, obj2; Ref ref2; int i; // non-terminal node: scan the children if (node->lookup("Kids", &obj1)->isArray()) { for (i = 0; i < obj1.arrayGetLength(); ++i) { if (obj1.arrayGetNF(i, &obj2)->isRef()) { ref2 = obj2.getRef(); obj2.free(); obj1.arrayGet(i, &obj2); } else { ref2.num = ref2.gen = -1; } if (obj2.isDict()) { scanFieldAppearances(obj2.getDict(), &ref2, node, acroForm); } obj2.free(); } obj1.free(); return; } obj1.free(); // terminal node: this is either a combined annot/field dict, or an // annot dict whose parent is a field if ((annot = findAnnot(ref))) { node->lookupNF("Parent", &obj1); if (!parent || !obj1.isNull()) { annot->generateFieldAppearance(node, node, acroForm); } else { annot->generateFieldAppearance(parent, node, acroForm); } obj1.free(); }}Annot *Annots::findAnnot(Ref *ref) { int i; for (i = 0; i < nAnnots; ++i) { if (annots[i]->match(ref)) { return annots[i]; } } return NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -