📄 annot.cc
字号:
//========================================================================//// Annot.cc//// Copyright 2000-2003 Glyph & Cog, LLC////========================================================================#include <aconf.h>#ifdef USE_GCC_PRAGMAS#pragma implementation#endif#include <stdlib.h>#include <math.h>#include "gmem.h"#include "GList.h"#include "Error.h"#include "Object.h"#include "Catalog.h"#include "Gfx.h"#include "GfxFont.h"#include "Lexer.h"#include "Annot.h"//------------------------------------------------------------------------#define annotFlagHidden 0x0002#define annotFlagPrint 0x0004#define annotFlagNoView 0x0020#define fieldFlagReadOnly 0x00000001#define fieldFlagRequired 0x00000002#define fieldFlagNoExport 0x00000004#define fieldFlagMultiline 0x00001000#define fieldFlagPassword 0x00002000#define fieldFlagNoToggleToOff 0x00004000#define fieldFlagRadio 0x00008000#define fieldFlagPushbutton 0x00010000#define fieldFlagCombo 0x00020000#define fieldFlagEdit 0x00040000#define fieldFlagSort 0x00080000#define fieldFlagFileSelect 0x00100000#define fieldFlagMultiSelect 0x00200000#define fieldFlagDoNotSpellCheck 0x00400000#define fieldFlagDoNotScroll 0x00800000#define fieldFlagComb 0x01000000#define fieldFlagRichText 0x02000000#define fieldFlagRadiosInUnison 0x02000000#define fieldFlagCommitOnSelChange 0x04000000#define fieldQuadLeft 0#define fieldQuadCenter 1#define fieldQuadRight 2// distance of Bezier control point from center for circle approximation// = (4 * (sqrt(2) - 1) / 3) * r#define bezierCircle 0.55228475//------------------------------------------------------------------------// AnnotBorderStyle//------------------------------------------------------------------------AnnotBorderStyle::AnnotBorderStyle(AnnotBorderType typeA, double widthA, double *dashA, int dashLengthA, double rA, double gA, double bA) { type = typeA; width = widthA; dash = dashA; dashLength = dashLengthA; r = rA; g = gA; b = bA;}AnnotBorderStyle::~AnnotBorderStyle() { if (dash) { gfree(dash); }}//------------------------------------------------------------------------// Annot//------------------------------------------------------------------------Annot::Annot(XRef *xrefA, Dict *acroForm, Dict *dict, Ref *refA) { Object apObj, asObj, obj1, obj2, obj3; AnnotBorderType borderType; double borderWidth; double *borderDash; int borderDashLength; double borderR, borderG, borderB; double t; int i; ok = gTrue; xref = xrefA; ref = *refA; type = NULL; appearBuf = NULL; borderStyle = NULL; //----- parse the type if (dict->lookup("Subtype", &obj1)->isName()) { type = new GString(obj1.getName()); } obj1.free(); //----- parse the rectangle if (dict->lookup("Rect", &obj1)->isArray() && obj1.arrayGetLength() == 4) { xMin = yMin = xMax = yMax = 0; if (obj1.arrayGet(0, &obj2)->isNum()) { xMin = obj2.getNum(); } obj2.free(); if (obj1.arrayGet(1, &obj2)->isNum()) { yMin = obj2.getNum(); } obj2.free(); if (obj1.arrayGet(2, &obj2)->isNum()) { xMax = obj2.getNum(); } obj2.free(); if (obj1.arrayGet(3, &obj2)->isNum()) { yMax = obj2.getNum(); } obj2.free(); if (xMin > xMax) { t = xMin; xMin = xMax; xMax = t; } if (yMin > yMax) { t = yMin; yMin = yMax; yMax = t; } } else { error(-1, "Bad bounding box for annotation"); ok = gFalse; } obj1.free(); //----- parse the flags if (dict->lookup("F", &obj1)->isInt()) { flags = obj1.getInt(); } else { flags = 0; } obj1.free(); //----- parse the border style borderType = annotBorderSolid; borderWidth = 1; borderDash = NULL; borderDashLength = 0; borderR = 0; borderG = 0; borderB = 1; if (dict->lookup("BS", &obj1)->isDict()) { if (obj1.dictLookup("S", &obj2)->isName()) { if (obj2.isName("S")) { borderType = annotBorderSolid; } else if (obj2.isName("D")) { borderType = annotBorderDashed; } else if (obj2.isName("B")) { borderType = annotBorderBeveled; } else if (obj2.isName("I")) { borderType = annotBorderInset; } else if (obj2.isName("U")) { borderType = annotBorderUnderlined; } } obj2.free(); if (obj1.dictLookup("W", &obj2)->isNum()) { borderWidth = obj2.getNum(); } obj2.free(); if (obj1.dictLookup("D", &obj2)->isArray()) { borderDashLength = obj2.arrayGetLength(); borderDash = (double *)gmallocn(borderDashLength, sizeof(double)); for (i = 0; i < borderDashLength; ++i) { if (obj2.arrayGet(i, &obj3)->isNum()) { borderDash[i] = obj3.getNum(); } else { borderDash[i] = 1; } obj3.free(); } } obj2.free(); } else { obj1.free(); if (dict->lookup("Border", &obj1)->isArray()) { if (obj1.arrayGetLength() >= 3) { if (obj1.arrayGet(2, &obj2)->isNum()) { borderWidth = obj2.getNum(); } obj2.free(); if (obj1.arrayGetLength() >= 4) { if (obj1.arrayGet(3, &obj2)->isArray()) { borderType = annotBorderDashed; borderDashLength = obj2.arrayGetLength(); borderDash = (double *)gmallocn(borderDashLength, sizeof(double)); for (i = 0; i < borderDashLength; ++i) { if (obj2.arrayGet(i, &obj3)->isNum()) { borderDash[i] = obj3.getNum(); } else { borderDash[i] = 1; } obj3.free(); } } else { // Adobe draws no border at all if the last element is of // the wrong type. borderWidth = 0; } obj2.free(); } } } } obj1.free(); if (dict->lookup("C", &obj1)->isArray() && obj1.arrayGetLength() == 3) { if (obj1.arrayGet(0, &obj2)->isNum()) { borderR = obj2.getNum(); } obj1.free(); if (obj1.arrayGet(1, &obj2)->isNum()) { borderG = obj2.getNum(); } obj1.free(); if (obj1.arrayGet(2, &obj2)->isNum()) { borderB = obj2.getNum(); } obj1.free(); } obj1.free(); borderStyle = new AnnotBorderStyle(borderType, borderWidth, borderDash, borderDashLength, borderR, borderG, borderB); //----- get the annotation appearance if (dict->lookup("AP", &apObj)->isDict()) { if (dict->lookup("AS", &asObj)->isName()) { if (apObj.dictLookup("N", &obj1)->isDict()) { if (obj1.dictLookupNF(asObj.getName(), &obj2)->isRef()) { obj2.copy(&appearance); ok = gTrue; } else { obj2.free(); if (obj1.dictLookupNF("Off", &obj2)->isRef()) { obj2.copy(&appearance); } } obj2.free(); } obj1.free(); } else { if (apObj.dictLookupNF("N", &obj1)->isRef()) { obj1.copy(&appearance); } obj1.free(); } asObj.free(); } apObj.free();}Annot::~Annot() { if (type) { delete type; } appearance.free(); if (appearBuf) { delete appearBuf; } if (borderStyle) { delete borderStyle; }}void Annot::generateFieldAppearance(Dict *field, Dict *annot, Dict *acroForm) { Object mkObj, ftObj, appearDict, drObj, obj1, obj2, obj3; Dict *mkDict; MemStream *appearStream; GfxFontDict *fontDict; GBool hasCaption; double w, dx, dy, r; double *dash; GString *caption, *da; GString **text; GBool *selection; int dashLength, ff, quadding, comb, nOptions, topIdx, i, j; // must be a Widget annotation if (type->cmp("Widget")) { return; } appearBuf = new GString(); // get the appearance characteristics (MK) dictionary if (annot->lookup("MK", &mkObj)->isDict()) { mkDict = mkObj.getDict(); } else { mkDict = NULL; } // draw the background if (mkDict) { if (mkDict->lookup("BG", &obj1)->isArray() && obj1.arrayGetLength() > 0) { setColor(obj1.getArray(), gTrue, 0); appearBuf->appendf("0 0 {0:.2f} {1:.2f} re f\n", xMax - xMin, yMax - yMin); } obj1.free(); } // get the field type fieldLookup(field, "FT", &ftObj); // get the field flags (Ff) value if (fieldLookup(field, "Ff", &obj1)->isInt()) { ff = obj1.getInt(); } else { ff = 0; } obj1.free(); // draw the border if (mkDict) { w = borderStyle->getWidth(); if (w > 0) { mkDict->lookup("BC", &obj1); if (!(obj1.isArray() && obj1.arrayGetLength() > 0)) { mkDict->lookup("BG", &obj1); } if (obj1.isArray() && obj1.arrayGetLength() > 0) { dx = xMax - xMin; dy = yMax - yMin; // radio buttons with no caption have a round border hasCaption = mkDict->lookup("CA", &obj2)->isString(); obj2.free(); if (ftObj.isName("Btn") && (ff & fieldFlagRadio) && !hasCaption) { r = 0.5 * (dx < dy ? dx : dy); switch (borderStyle->getType()) { case annotBorderDashed: appearBuf->append("["); borderStyle->getDash(&dash, &dashLength); for (i = 0; i < dashLength; ++i) { appearBuf->appendf(" {0:.2f}", dash[i]); } appearBuf->append("] 0 d\n"); // fall through to the solid case case annotBorderSolid: case annotBorderUnderlined: appearBuf->appendf("{0:.2f} w\n", w); setColor(obj1.getArray(), gFalse, 0); drawCircle(0.5 * dx, 0.5 * dy, r - 0.5 * w, gFalse); break; case annotBorderBeveled: case annotBorderInset: appearBuf->appendf("{0:.2f} w\n", 0.5 * w); setColor(obj1.getArray(), gFalse, 0); drawCircle(0.5 * dx, 0.5 * dy, r - 0.25 * w, gFalse); setColor(obj1.getArray(), gFalse, borderStyle->getType() == annotBorderBeveled ? 1 : -1); drawCircleTopLeft(0.5 * dx, 0.5 * dy, r - 0.75 * w); setColor(obj1.getArray(), gFalse, borderStyle->getType() == annotBorderBeveled ? -1 : 1); drawCircleBottomRight(0.5 * dx, 0.5 * dy, r - 0.75 * w); break; } } else { switch (borderStyle->getType()) { case annotBorderDashed: appearBuf->append("["); borderStyle->getDash(&dash, &dashLength); for (i = 0; i < dashLength; ++i) { appearBuf->appendf(" {0:.2f}", dash[i]); } appearBuf->append("] 0 d\n"); // fall through to the solid case case annotBorderSolid: appearBuf->appendf("{0:.2f} w\n", w); setColor(obj1.getArray(), gFalse, 0); appearBuf->appendf("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re s\n", 0.5 * w, dx - w, dy - w); break; case annotBorderBeveled: case annotBorderInset: setColor(obj1.getArray(), gTrue, borderStyle->getType() == annotBorderBeveled ? 1 : -1); appearBuf->append("0 0 m\n"); appearBuf->appendf("0 {0:.2f} l\n", dy); appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx, dy); appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, dy - w); appearBuf->appendf("{0:.2f} {1:.2f} l\n", w, dy - w); appearBuf->appendf("{0:.2f} {0:.2f} l\n", w); appearBuf->append("f\n"); setColor(obj1.getArray(), gTrue, borderStyle->getType() == annotBorderBeveled ? -1 : 1); appearBuf->append("0 0 m\n"); appearBuf->appendf("{0:.2f} 0 l\n", dx); appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx, dy); appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, dy - w); appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, w); appearBuf->appendf("{0:.2f} {0:.2f} l\n", w); appearBuf->append("f\n"); break; case annotBorderUnderlined: appearBuf->appendf("{0:.2f} w\n", w); setColor(obj1.getArray(), gFalse, 0); appearBuf->appendf("0 0 m {0:.2f} 0 l s\n", dx); break; } // clip to the inside of the border appearBuf->appendf("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re W n\n", w, dx - 2 * w, dy - 2 * w); } } obj1.free(); } } // get the resource dictionary acroForm->lookup("DR", &drObj); // build the font dictionary if (drObj.isDict() && drObj.dictLookup("Font", &obj1)->isDict()) { fontDict = new GfxFontDict(xref, NULL, obj1.getDict()); } else { fontDict = NULL; } obj1.free(); // get the default appearance string if (fieldLookup(field, "DA", &obj1)->isNull()) { obj1.free(); acroForm->lookup("DA", &obj1); } if (obj1.isString()) { da = obj1.getString()->copy(); } else { da = NULL; } obj1.free(); // draw the field contents if (ftObj.isName("Btn")) { caption = NULL; if (mkDict) { if (mkDict->lookup("CA", &obj1)->isString()) { caption = obj1.getString()->copy(); } obj1.free(); } // radio button if (ff & fieldFlagRadio) { //~ Acrobat doesn't draw a caption if there is no AP dict (?) if (fieldLookup(field, "V", &obj1)->isName()) { if (annot->lookup("AS", &obj2)->isName(obj1.getName())) { if (caption) { drawText(caption, da, fontDict, gFalse, 0, fieldQuadCenter, gFalse, gTrue); } else { if (mkDict) { if (mkDict->lookup("BC", &obj3)->isArray() && obj3.arrayGetLength() > 0) { dx = xMax - xMin; dy = yMax - yMin; setColor(obj3.getArray(), gTrue, 0); drawCircle(0.5 * dx, 0.5 * dy, 0.2 * (dx < dy ? dx : dy), gTrue); } obj3.free(); } } } obj2.free(); } obj1.free(); // pushbutton } else if (ff & fieldFlagPushbutton) { if (caption) { drawText(caption, da, fontDict, gFalse, 0, fieldQuadCenter, gFalse, gFalse); } // checkbox } else { // According to the PDF spec the off state must be named "Off", // and the on state can be named anything, but Acrobat apparently // looks for "Yes" and treats anything else as off. if (fieldLookup(field, "V", &obj1)->isName("Yes")) { if (!caption) { caption = new GString("3"); // ZapfDingbats checkmark } drawText(caption, da, fontDict, gFalse, 0, fieldQuadCenter, gFalse, gTrue); } obj1.free(); } if (caption) { delete caption; } } else if (ftObj.isName("Tx")) { //~ value strings can be Unicode if (fieldLookup(field, "V", &obj1)->isString()) { if (fieldLookup(field, "Q", &obj2)->isInt()) { quadding = obj2.getInt(); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -