annotation.js 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982
  1. /**
  2. * @licstart The following is the entire license notice for the
  3. * Javascript code in this page
  4. *
  5. * Copyright 2020 Mozilla Foundation
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. *
  19. * @licend The above is the entire license notice for the
  20. * Javascript code in this page
  21. */
  22. "use strict";
  23. Object.defineProperty(exports, "__esModule", {
  24. value: true
  25. });
  26. exports.getQuadPoints = getQuadPoints;
  27. exports.MarkupAnnotation = exports.AnnotationFactory = exports.AnnotationBorderStyle = exports.Annotation = void 0;
  28. var _util = require("../shared/util.js");
  29. var _obj = require("./obj.js");
  30. var _core_utils = require("./core_utils.js");
  31. var _default_appearance = require("./default_appearance.js");
  32. var _primitives = require("./primitives.js");
  33. var _colorspace = require("./colorspace.js");
  34. var _operator_list = require("./operator_list.js");
  35. var _stream = require("./stream.js");
  36. var _writer = require("./writer.js");
  37. class AnnotationFactory {
  38. static create(xref, ref, pdfManager, idFactory) {
  39. return pdfManager.ensureCatalog("acroForm").then(acroForm => {
  40. return pdfManager.ensure(this, "_create", [xref, ref, pdfManager, idFactory, acroForm]);
  41. });
  42. }
  43. static _create(xref, ref, pdfManager, idFactory, acroForm) {
  44. const dict = xref.fetchIfRef(ref);
  45. if (!(0, _primitives.isDict)(dict)) {
  46. return undefined;
  47. }
  48. const id = (0, _primitives.isRef)(ref) ? ref.toString() : `annot_${idFactory.createObjId()}`;
  49. let subtype = dict.get("Subtype");
  50. subtype = (0, _primitives.isName)(subtype) ? subtype.name : null;
  51. const parameters = {
  52. xref,
  53. ref,
  54. dict,
  55. subtype,
  56. id,
  57. pdfManager,
  58. acroForm: acroForm instanceof _primitives.Dict ? acroForm : _primitives.Dict.empty
  59. };
  60. switch (subtype) {
  61. case "Link":
  62. return new LinkAnnotation(parameters);
  63. case "Text":
  64. return new TextAnnotation(parameters);
  65. case "Widget":
  66. let fieldType = (0, _core_utils.getInheritableProperty)({
  67. dict,
  68. key: "FT"
  69. });
  70. fieldType = (0, _primitives.isName)(fieldType) ? fieldType.name : null;
  71. switch (fieldType) {
  72. case "Tx":
  73. return new TextWidgetAnnotation(parameters);
  74. case "Btn":
  75. return new ButtonWidgetAnnotation(parameters);
  76. case "Ch":
  77. return new ChoiceWidgetAnnotation(parameters);
  78. }
  79. (0, _util.warn)('Unimplemented widget field type "' + fieldType + '", ' + "falling back to base field type.");
  80. return new WidgetAnnotation(parameters);
  81. case "Popup":
  82. return new PopupAnnotation(parameters);
  83. case "FreeText":
  84. return new FreeTextAnnotation(parameters);
  85. case "Line":
  86. return new LineAnnotation(parameters);
  87. case "Square":
  88. return new SquareAnnotation(parameters);
  89. case "Circle":
  90. return new CircleAnnotation(parameters);
  91. case "PolyLine":
  92. return new PolylineAnnotation(parameters);
  93. case "Polygon":
  94. return new PolygonAnnotation(parameters);
  95. case "Caret":
  96. return new CaretAnnotation(parameters);
  97. case "Ink":
  98. return new InkAnnotation(parameters);
  99. case "Highlight":
  100. return new HighlightAnnotation(parameters);
  101. case "Underline":
  102. return new UnderlineAnnotation(parameters);
  103. case "Squiggly":
  104. return new SquigglyAnnotation(parameters);
  105. case "StrikeOut":
  106. return new StrikeOutAnnotation(parameters);
  107. case "Stamp":
  108. return new StampAnnotation(parameters);
  109. case "FileAttachment":
  110. return new FileAttachmentAnnotation(parameters);
  111. default:
  112. if (!subtype) {
  113. (0, _util.warn)("Annotation is missing the required /Subtype.");
  114. } else {
  115. (0, _util.warn)('Unimplemented annotation type "' + subtype + '", ' + "falling back to base annotation.");
  116. }
  117. return new Annotation(parameters);
  118. }
  119. }
  120. }
  121. exports.AnnotationFactory = AnnotationFactory;
  122. function getQuadPoints(dict, rect) {
  123. if (!dict.has("QuadPoints")) {
  124. return null;
  125. }
  126. const quadPoints = dict.getArray("QuadPoints");
  127. if (!Array.isArray(quadPoints) || quadPoints.length === 0 || quadPoints.length % 8 > 0) {
  128. return null;
  129. }
  130. const quadPointsLists = [];
  131. for (let i = 0, ii = quadPoints.length / 8; i < ii; i++) {
  132. quadPointsLists.push([]);
  133. for (let j = i * 8, jj = i * 8 + 8; j < jj; j += 2) {
  134. const x = quadPoints[j];
  135. const y = quadPoints[j + 1];
  136. if (rect !== null && (x < rect[0] || x > rect[2] || y < rect[1] || y > rect[3])) {
  137. return null;
  138. }
  139. quadPointsLists[i].push({
  140. x,
  141. y
  142. });
  143. }
  144. }
  145. return quadPointsLists.map(quadPointsList => {
  146. const [minX, maxX, minY, maxY] = quadPointsList.reduce(([mX, MX, mY, MY], quadPoint) => [Math.min(mX, quadPoint.x), Math.max(MX, quadPoint.x), Math.min(mY, quadPoint.y), Math.max(MY, quadPoint.y)], [Number.MAX_VALUE, Number.MIN_VALUE, Number.MAX_VALUE, Number.MIN_VALUE]);
  147. return [{
  148. x: minX,
  149. y: maxY
  150. }, {
  151. x: maxX,
  152. y: maxY
  153. }, {
  154. x: minX,
  155. y: minY
  156. }, {
  157. x: maxX,
  158. y: minY
  159. }];
  160. });
  161. }
  162. function getTransformMatrix(rect, bbox, matrix) {
  163. const [minX, minY, maxX, maxY] = _util.Util.getAxialAlignedBoundingBox(bbox, matrix);
  164. if (minX === maxX || minY === maxY) {
  165. return [1, 0, 0, 1, rect[0], rect[1]];
  166. }
  167. const xRatio = (rect[2] - rect[0]) / (maxX - minX);
  168. const yRatio = (rect[3] - rect[1]) / (maxY - minY);
  169. return [xRatio, 0, 0, yRatio, rect[0] - minX * xRatio, rect[1] - minY * yRatio];
  170. }
  171. class Annotation {
  172. constructor(params) {
  173. const dict = params.dict;
  174. this.setContents(dict.get("Contents"));
  175. this.setModificationDate(dict.get("M"));
  176. this.setFlags(dict.get("F"));
  177. this.setRectangle(dict.getArray("Rect"));
  178. this.setColor(dict.getArray("C"));
  179. this.setBorderStyle(dict);
  180. this.setAppearance(dict);
  181. this._streams = [];
  182. if (this.appearance) {
  183. this._streams.push(this.appearance);
  184. }
  185. this.data = {
  186. annotationFlags: this.flags,
  187. borderStyle: this.borderStyle,
  188. color: this.color,
  189. contents: this.contents,
  190. hasAppearance: !!this.appearance,
  191. id: params.id,
  192. modificationDate: this.modificationDate,
  193. rect: this.rectangle,
  194. subtype: params.subtype
  195. };
  196. this._fallbackFontDict = null;
  197. }
  198. _hasFlag(flags, flag) {
  199. return !!(flags & flag);
  200. }
  201. _isViewable(flags) {
  202. return !this._hasFlag(flags, _util.AnnotationFlag.INVISIBLE) && !this._hasFlag(flags, _util.AnnotationFlag.NOVIEW);
  203. }
  204. _isPrintable(flags) {
  205. return this._hasFlag(flags, _util.AnnotationFlag.PRINT) && !this._hasFlag(flags, _util.AnnotationFlag.INVISIBLE);
  206. }
  207. isHidden(annotationStorage) {
  208. const data = annotationStorage && annotationStorage[this.data.id];
  209. if (data && "hidden" in data) {
  210. return data.hidden;
  211. }
  212. return this._hasFlag(this.flags, _util.AnnotationFlag.HIDDEN);
  213. }
  214. get viewable() {
  215. if (this.data.quadPoints === null) {
  216. return false;
  217. }
  218. if (this.flags === 0) {
  219. return true;
  220. }
  221. return this._isViewable(this.flags);
  222. }
  223. get printable() {
  224. if (this.data.quadPoints === null) {
  225. return false;
  226. }
  227. if (this.flags === 0) {
  228. return false;
  229. }
  230. return this._isPrintable(this.flags);
  231. }
  232. setContents(contents) {
  233. this.contents = (0, _util.stringToPDFString)(contents || "");
  234. }
  235. setModificationDate(modificationDate) {
  236. this.modificationDate = (0, _util.isString)(modificationDate) ? modificationDate : null;
  237. }
  238. setFlags(flags) {
  239. this.flags = Number.isInteger(flags) && flags > 0 ? flags : 0;
  240. }
  241. hasFlag(flag) {
  242. return this._hasFlag(this.flags, flag);
  243. }
  244. setRectangle(rectangle) {
  245. if (Array.isArray(rectangle) && rectangle.length === 4) {
  246. this.rectangle = _util.Util.normalizeRect(rectangle);
  247. } else {
  248. this.rectangle = [0, 0, 0, 0];
  249. }
  250. }
  251. setColor(color) {
  252. const rgbColor = new Uint8ClampedArray(3);
  253. if (!Array.isArray(color)) {
  254. this.color = rgbColor;
  255. return;
  256. }
  257. switch (color.length) {
  258. case 0:
  259. this.color = null;
  260. break;
  261. case 1:
  262. _colorspace.ColorSpace.singletons.gray.getRgbItem(color, 0, rgbColor, 0);
  263. this.color = rgbColor;
  264. break;
  265. case 3:
  266. _colorspace.ColorSpace.singletons.rgb.getRgbItem(color, 0, rgbColor, 0);
  267. this.color = rgbColor;
  268. break;
  269. case 4:
  270. _colorspace.ColorSpace.singletons.cmyk.getRgbItem(color, 0, rgbColor, 0);
  271. this.color = rgbColor;
  272. break;
  273. default:
  274. this.color = rgbColor;
  275. break;
  276. }
  277. }
  278. setBorderStyle(borderStyle) {
  279. this.borderStyle = new AnnotationBorderStyle();
  280. if (!(0, _primitives.isDict)(borderStyle)) {
  281. return;
  282. }
  283. if (borderStyle.has("BS")) {
  284. const dict = borderStyle.get("BS");
  285. const dictType = dict.get("Type");
  286. if (!dictType || (0, _primitives.isName)(dictType, "Border")) {
  287. this.borderStyle.setWidth(dict.get("W"), this.rectangle);
  288. this.borderStyle.setStyle(dict.get("S"));
  289. this.borderStyle.setDashArray(dict.getArray("D"));
  290. }
  291. } else if (borderStyle.has("Border")) {
  292. const array = borderStyle.getArray("Border");
  293. if (Array.isArray(array) && array.length >= 3) {
  294. this.borderStyle.setHorizontalCornerRadius(array[0]);
  295. this.borderStyle.setVerticalCornerRadius(array[1]);
  296. this.borderStyle.setWidth(array[2], this.rectangle);
  297. if (array.length === 4) {
  298. this.borderStyle.setDashArray(array[3]);
  299. }
  300. }
  301. } else {
  302. this.borderStyle.setWidth(0);
  303. }
  304. }
  305. setAppearance(dict) {
  306. this.appearance = null;
  307. const appearanceStates = dict.get("AP");
  308. if (!(0, _primitives.isDict)(appearanceStates)) {
  309. return;
  310. }
  311. const normalAppearanceState = appearanceStates.get("N");
  312. if ((0, _primitives.isStream)(normalAppearanceState)) {
  313. this.appearance = normalAppearanceState;
  314. return;
  315. }
  316. if (!(0, _primitives.isDict)(normalAppearanceState)) {
  317. return;
  318. }
  319. const as = dict.get("AS");
  320. if (!(0, _primitives.isName)(as) || !normalAppearanceState.has(as.name)) {
  321. return;
  322. }
  323. this.appearance = normalAppearanceState.get(as.name);
  324. }
  325. loadResources(keys) {
  326. return this.appearance.dict.getAsync("Resources").then(resources => {
  327. if (!resources) {
  328. return undefined;
  329. }
  330. const objectLoader = new _obj.ObjectLoader(resources, keys, resources.xref);
  331. return objectLoader.load().then(function () {
  332. return resources;
  333. });
  334. });
  335. }
  336. getOperatorList(evaluator, task, renderForms, annotationStorage) {
  337. if (!this.appearance) {
  338. return Promise.resolve(new _operator_list.OperatorList());
  339. }
  340. const appearance = this.appearance;
  341. const data = this.data;
  342. const appearanceDict = appearance.dict;
  343. const resourcesPromise = this.loadResources(["ExtGState", "ColorSpace", "Pattern", "Shading", "XObject", "Font"]);
  344. const bbox = appearanceDict.getArray("BBox") || [0, 0, 1, 1];
  345. const matrix = appearanceDict.getArray("Matrix") || [1, 0, 0, 1, 0, 0];
  346. const transform = getTransformMatrix(data.rect, bbox, matrix);
  347. return resourcesPromise.then(resources => {
  348. const opList = new _operator_list.OperatorList();
  349. opList.addOp(_util.OPS.beginAnnotation, [data.rect, transform, matrix]);
  350. return evaluator.getOperatorList({
  351. stream: appearance,
  352. task,
  353. resources,
  354. operatorList: opList,
  355. fallbackFontDict: this._fallbackFontDict
  356. }).then(() => {
  357. opList.addOp(_util.OPS.endAnnotation, []);
  358. this.reset();
  359. return opList;
  360. });
  361. });
  362. }
  363. async save(evaluator, task, annotationStorage) {
  364. return null;
  365. }
  366. getFieldObject() {
  367. return null;
  368. }
  369. reset() {
  370. for (const stream of this._streams) {
  371. stream.reset();
  372. }
  373. }
  374. }
  375. exports.Annotation = Annotation;
  376. class AnnotationBorderStyle {
  377. constructor() {
  378. this.width = 1;
  379. this.style = _util.AnnotationBorderStyleType.SOLID;
  380. this.dashArray = [3];
  381. this.horizontalCornerRadius = 0;
  382. this.verticalCornerRadius = 0;
  383. }
  384. setWidth(width, rect = [0, 0, 0, 0]) {
  385. if ((0, _primitives.isName)(width)) {
  386. this.width = 0;
  387. return;
  388. }
  389. if (Number.isInteger(width)) {
  390. if (width > 0) {
  391. const maxWidth = (rect[2] - rect[0]) / 2;
  392. const maxHeight = (rect[3] - rect[1]) / 2;
  393. if (maxWidth > 0 && maxHeight > 0 && (width > maxWidth || width > maxHeight)) {
  394. (0, _util.warn)(`AnnotationBorderStyle.setWidth - ignoring width: ${width}`);
  395. width = 1;
  396. }
  397. }
  398. this.width = width;
  399. }
  400. }
  401. setStyle(style) {
  402. if (!(0, _primitives.isName)(style)) {
  403. return;
  404. }
  405. switch (style.name) {
  406. case "S":
  407. this.style = _util.AnnotationBorderStyleType.SOLID;
  408. break;
  409. case "D":
  410. this.style = _util.AnnotationBorderStyleType.DASHED;
  411. break;
  412. case "B":
  413. this.style = _util.AnnotationBorderStyleType.BEVELED;
  414. break;
  415. case "I":
  416. this.style = _util.AnnotationBorderStyleType.INSET;
  417. break;
  418. case "U":
  419. this.style = _util.AnnotationBorderStyleType.UNDERLINE;
  420. break;
  421. default:
  422. break;
  423. }
  424. }
  425. setDashArray(dashArray) {
  426. if (Array.isArray(dashArray) && dashArray.length > 0) {
  427. let isValid = true;
  428. let allZeros = true;
  429. for (const element of dashArray) {
  430. const validNumber = +element >= 0;
  431. if (!validNumber) {
  432. isValid = false;
  433. break;
  434. } else if (element > 0) {
  435. allZeros = false;
  436. }
  437. }
  438. if (isValid && !allZeros) {
  439. this.dashArray = dashArray;
  440. } else {
  441. this.width = 0;
  442. }
  443. } else if (dashArray) {
  444. this.width = 0;
  445. }
  446. }
  447. setHorizontalCornerRadius(radius) {
  448. if (Number.isInteger(radius)) {
  449. this.horizontalCornerRadius = radius;
  450. }
  451. }
  452. setVerticalCornerRadius(radius) {
  453. if (Number.isInteger(radius)) {
  454. this.verticalCornerRadius = radius;
  455. }
  456. }
  457. }
  458. exports.AnnotationBorderStyle = AnnotationBorderStyle;
  459. class MarkupAnnotation extends Annotation {
  460. constructor(parameters) {
  461. super(parameters);
  462. const dict = parameters.dict;
  463. if (dict.has("IRT")) {
  464. const rawIRT = dict.getRaw("IRT");
  465. this.data.inReplyTo = (0, _primitives.isRef)(rawIRT) ? rawIRT.toString() : null;
  466. const rt = dict.get("RT");
  467. this.data.replyType = (0, _primitives.isName)(rt) ? rt.name : _util.AnnotationReplyType.REPLY;
  468. }
  469. if (this.data.replyType === _util.AnnotationReplyType.GROUP) {
  470. const parent = dict.get("IRT");
  471. this.data.title = (0, _util.stringToPDFString)(parent.get("T") || "");
  472. this.setContents(parent.get("Contents"));
  473. this.data.contents = this.contents;
  474. if (!parent.has("CreationDate")) {
  475. this.data.creationDate = null;
  476. } else {
  477. this.setCreationDate(parent.get("CreationDate"));
  478. this.data.creationDate = this.creationDate;
  479. }
  480. if (!parent.has("M")) {
  481. this.data.modificationDate = null;
  482. } else {
  483. this.setModificationDate(parent.get("M"));
  484. this.data.modificationDate = this.modificationDate;
  485. }
  486. this.data.hasPopup = parent.has("Popup");
  487. if (!parent.has("C")) {
  488. this.data.color = null;
  489. } else {
  490. this.setColor(parent.getArray("C"));
  491. this.data.color = this.color;
  492. }
  493. } else {
  494. this.data.title = (0, _util.stringToPDFString)(dict.get("T") || "");
  495. this.setCreationDate(dict.get("CreationDate"));
  496. this.data.creationDate = this.creationDate;
  497. this.data.hasPopup = dict.has("Popup");
  498. if (!dict.has("C")) {
  499. this.data.color = null;
  500. }
  501. }
  502. }
  503. setCreationDate(creationDate) {
  504. this.creationDate = (0, _util.isString)(creationDate) ? creationDate : null;
  505. }
  506. _setDefaultAppearance({
  507. xref,
  508. extra,
  509. strokeColor,
  510. fillColor,
  511. blendMode,
  512. pointsCallback
  513. }) {
  514. let minX = Number.MAX_VALUE;
  515. let minY = Number.MAX_VALUE;
  516. let maxX = Number.MIN_VALUE;
  517. let maxY = Number.MIN_VALUE;
  518. const buffer = ["q"];
  519. if (extra) {
  520. buffer.push(extra);
  521. }
  522. if (strokeColor) {
  523. buffer.push(`${strokeColor[0]} ${strokeColor[1]} ${strokeColor[2]} RG`);
  524. }
  525. if (fillColor) {
  526. buffer.push(`${fillColor[0]} ${fillColor[1]} ${fillColor[2]} rg`);
  527. }
  528. for (const points of this.data.quadPoints) {
  529. const [mX, MX, mY, MY] = pointsCallback(buffer, points);
  530. minX = Math.min(minX, mX);
  531. maxX = Math.max(maxX, MX);
  532. minY = Math.min(minY, mY);
  533. maxY = Math.max(maxY, MY);
  534. }
  535. buffer.push("Q");
  536. const formDict = new _primitives.Dict(xref);
  537. const appearanceStreamDict = new _primitives.Dict(xref);
  538. appearanceStreamDict.set("Subtype", _primitives.Name.get("Form"));
  539. const appearanceStream = new _stream.StringStream(buffer.join(" "));
  540. appearanceStream.dict = appearanceStreamDict;
  541. formDict.set("Fm0", appearanceStream);
  542. const gsDict = new _primitives.Dict(xref);
  543. if (blendMode) {
  544. gsDict.set("BM", _primitives.Name.get(blendMode));
  545. }
  546. const stateDict = new _primitives.Dict(xref);
  547. stateDict.set("GS0", gsDict);
  548. const resources = new _primitives.Dict(xref);
  549. resources.set("ExtGState", stateDict);
  550. resources.set("XObject", formDict);
  551. const appearanceDict = new _primitives.Dict(xref);
  552. appearanceDict.set("Resources", resources);
  553. const bbox = this.data.rect = [minX, minY, maxX, maxY];
  554. appearanceDict.set("BBox", bbox);
  555. this.appearance = new _stream.StringStream("/GS0 gs /Fm0 Do");
  556. this.appearance.dict = appearanceDict;
  557. this._streams.push(this.appearance, appearanceStream);
  558. }
  559. }
  560. exports.MarkupAnnotation = MarkupAnnotation;
  561. class WidgetAnnotation extends Annotation {
  562. constructor(params) {
  563. super(params);
  564. const dict = params.dict;
  565. const data = this.data;
  566. this.ref = params.ref;
  567. data.annotationType = _util.AnnotationType.WIDGET;
  568. data.fieldName = this._constructFieldName(dict);
  569. data.actions = (0, _core_utils.collectActions)(params.xref, dict, _util.AnnotationActionEventType);
  570. const fieldValue = (0, _core_utils.getInheritableProperty)({
  571. dict,
  572. key: "V",
  573. getArray: true
  574. });
  575. data.fieldValue = this._decodeFormValue(fieldValue);
  576. const defaultFieldValue = (0, _core_utils.getInheritableProperty)({
  577. dict,
  578. key: "DV",
  579. getArray: true
  580. });
  581. data.defaultFieldValue = this._decodeFormValue(defaultFieldValue);
  582. data.alternativeText = (0, _util.stringToPDFString)(dict.get("TU") || "");
  583. const defaultAppearance = (0, _core_utils.getInheritableProperty)({
  584. dict,
  585. key: "DA"
  586. }) || params.acroForm.get("DA") || "";
  587. data.defaultAppearance = (0, _util.isString)(defaultAppearance) ? defaultAppearance : "";
  588. data.defaultAppearanceData = (0, _default_appearance.parseDefaultAppearance)(data.defaultAppearance);
  589. const fieldType = (0, _core_utils.getInheritableProperty)({
  590. dict,
  591. key: "FT"
  592. });
  593. data.fieldType = (0, _primitives.isName)(fieldType) ? fieldType.name : null;
  594. const localResources = (0, _core_utils.getInheritableProperty)({
  595. dict,
  596. key: "DR"
  597. });
  598. const acroFormResources = params.acroForm.get("DR");
  599. const appearanceResources = this.appearance && this.appearance.dict.get("Resources");
  600. this._fieldResources = {
  601. localResources,
  602. acroFormResources,
  603. appearanceResources,
  604. mergedResources: _primitives.Dict.merge({
  605. xref: params.xref,
  606. dictArray: [localResources, appearanceResources, acroFormResources],
  607. mergeSubDicts: true
  608. })
  609. };
  610. data.fieldFlags = (0, _core_utils.getInheritableProperty)({
  611. dict,
  612. key: "Ff"
  613. });
  614. if (!Number.isInteger(data.fieldFlags) || data.fieldFlags < 0) {
  615. data.fieldFlags = 0;
  616. }
  617. data.readOnly = this.hasFieldFlag(_util.AnnotationFieldFlag.READONLY);
  618. data.hidden = this._hasFlag(data.annotationFlags, _util.AnnotationFlag.HIDDEN);
  619. if (data.fieldType === "Sig") {
  620. data.fieldValue = null;
  621. this.setFlags(_util.AnnotationFlag.HIDDEN);
  622. data.hidden = true;
  623. }
  624. }
  625. _constructFieldName(dict) {
  626. if (!dict.has("T") && !dict.has("Parent")) {
  627. (0, _util.warn)("Unknown field name, falling back to empty field name.");
  628. return "";
  629. }
  630. if (!dict.has("Parent")) {
  631. return (0, _util.stringToPDFString)(dict.get("T"));
  632. }
  633. const fieldName = [];
  634. if (dict.has("T")) {
  635. fieldName.unshift((0, _util.stringToPDFString)(dict.get("T")));
  636. }
  637. let loopDict = dict;
  638. while (loopDict.has("Parent")) {
  639. loopDict = loopDict.get("Parent");
  640. if (!(0, _primitives.isDict)(loopDict)) {
  641. break;
  642. }
  643. if (loopDict.has("T")) {
  644. fieldName.unshift((0, _util.stringToPDFString)(loopDict.get("T")));
  645. }
  646. }
  647. return fieldName.join(".");
  648. }
  649. _decodeFormValue(formValue) {
  650. if (Array.isArray(formValue)) {
  651. return formValue.filter(item => (0, _util.isString)(item)).map(item => (0, _util.stringToPDFString)(item));
  652. } else if ((0, _primitives.isName)(formValue)) {
  653. return (0, _util.stringToPDFString)(formValue.name);
  654. } else if ((0, _util.isString)(formValue)) {
  655. return (0, _util.stringToPDFString)(formValue);
  656. }
  657. return null;
  658. }
  659. hasFieldFlag(flag) {
  660. return !!(this.data.fieldFlags & flag);
  661. }
  662. getOperatorList(evaluator, task, renderForms, annotationStorage) {
  663. if (renderForms) {
  664. return Promise.resolve(new _operator_list.OperatorList());
  665. }
  666. if (!this._hasText) {
  667. return super.getOperatorList(evaluator, task, renderForms, annotationStorage);
  668. }
  669. return this._getAppearance(evaluator, task, annotationStorage).then(content => {
  670. if (this.appearance && content === null) {
  671. return super.getOperatorList(evaluator, task, renderForms, annotationStorage);
  672. }
  673. const operatorList = new _operator_list.OperatorList();
  674. if (!this.data.defaultAppearance || content === null) {
  675. return operatorList;
  676. }
  677. const matrix = [1, 0, 0, 1, 0, 0];
  678. const bbox = [0, 0, this.data.rect[2] - this.data.rect[0], this.data.rect[3] - this.data.rect[1]];
  679. const transform = getTransformMatrix(this.data.rect, bbox, matrix);
  680. operatorList.addOp(_util.OPS.beginAnnotation, [this.data.rect, transform, matrix]);
  681. const stream = new _stream.StringStream(content);
  682. return evaluator.getOperatorList({
  683. stream,
  684. task,
  685. resources: this._fieldResources.mergedResources,
  686. operatorList
  687. }).then(function () {
  688. operatorList.addOp(_util.OPS.endAnnotation, []);
  689. return operatorList;
  690. });
  691. });
  692. }
  693. async save(evaluator, task, annotationStorage) {
  694. const value = annotationStorage[this.data.id] && annotationStorage[this.data.id].value;
  695. if (value === this.data.fieldValue || value === undefined) {
  696. return null;
  697. }
  698. let appearance = await this._getAppearance(evaluator, task, annotationStorage);
  699. if (appearance === null) {
  700. return null;
  701. }
  702. const {
  703. xref
  704. } = evaluator;
  705. const dict = xref.fetchIfRef(this.ref);
  706. if (!(0, _primitives.isDict)(dict)) {
  707. return null;
  708. }
  709. const bbox = [0, 0, this.data.rect[2] - this.data.rect[0], this.data.rect[3] - this.data.rect[1]];
  710. const xfa = {
  711. path: (0, _util.stringToPDFString)(dict.get("T") || ""),
  712. value
  713. };
  714. const newRef = xref.getNewRef();
  715. const AP = new _primitives.Dict(xref);
  716. AP.set("N", newRef);
  717. const encrypt = xref.encrypt;
  718. let originalTransform = null;
  719. let newTransform = null;
  720. if (encrypt) {
  721. originalTransform = encrypt.createCipherTransform(this.ref.num, this.ref.gen);
  722. newTransform = encrypt.createCipherTransform(newRef.num, newRef.gen);
  723. appearance = newTransform.encryptString(appearance);
  724. }
  725. dict.set("V", (0, _util.isAscii)(value) ? value : (0, _util.stringToUTF16BEString)(value));
  726. dict.set("AP", AP);
  727. dict.set("M", `D:${(0, _util.getModificationDate)()}`);
  728. const appearanceDict = new _primitives.Dict(xref);
  729. appearanceDict.set("Length", appearance.length);
  730. appearanceDict.set("Subtype", _primitives.Name.get("Form"));
  731. appearanceDict.set("Resources", this._getSaveFieldResources(xref));
  732. appearanceDict.set("BBox", bbox);
  733. const bufferOriginal = [`${this.ref.num} ${this.ref.gen} obj\n`];
  734. (0, _writer.writeDict)(dict, bufferOriginal, originalTransform);
  735. bufferOriginal.push("\nendobj\n");
  736. const bufferNew = [`${newRef.num} ${newRef.gen} obj\n`];
  737. (0, _writer.writeDict)(appearanceDict, bufferNew, newTransform);
  738. bufferNew.push(" stream\n");
  739. bufferNew.push(appearance);
  740. bufferNew.push("\nendstream\nendobj\n");
  741. return [{
  742. ref: this.ref,
  743. data: bufferOriginal.join(""),
  744. xfa
  745. }, {
  746. ref: newRef,
  747. data: bufferNew.join(""),
  748. xfa: null
  749. }];
  750. }
  751. async _getAppearance(evaluator, task, annotationStorage) {
  752. const isPassword = this.hasFieldFlag(_util.AnnotationFieldFlag.PASSWORD);
  753. if (!annotationStorage || isPassword) {
  754. return null;
  755. }
  756. const value = annotationStorage[this.data.id] && annotationStorage[this.data.id].value;
  757. if (value === undefined) {
  758. return null;
  759. }
  760. if (value === "") {
  761. return "";
  762. }
  763. const defaultPadding = 2;
  764. const hPadding = defaultPadding;
  765. const totalHeight = this.data.rect[3] - this.data.rect[1];
  766. const totalWidth = this.data.rect[2] - this.data.rect[0];
  767. if (!this.data.defaultAppearance) {
  768. this.data.defaultAppearance = "/Helvetica 0 Tf 0 g";
  769. this.data.defaultAppearanceData = (0, _default_appearance.parseDefaultAppearance)(this.data.defaultAppearance);
  770. }
  771. const font = await this._getFontData(evaluator, task);
  772. const fontSize = this._computeFontSize(font, totalHeight);
  773. let descent = font.descent;
  774. if (isNaN(descent)) {
  775. descent = 0;
  776. }
  777. const vPadding = defaultPadding + Math.abs(descent) * fontSize;
  778. const defaultAppearance = this.data.defaultAppearance;
  779. const alignment = this.data.textAlignment;
  780. if (this.data.multiLine) {
  781. return this._getMultilineAppearance(defaultAppearance, value, font, fontSize, totalWidth, totalHeight, alignment, hPadding, vPadding);
  782. }
  783. const encodedString = font.encodeString(value).join("");
  784. if (this.data.comb) {
  785. return this._getCombAppearance(defaultAppearance, font, encodedString, totalWidth, hPadding, vPadding);
  786. }
  787. if (alignment === 0 || alignment > 2) {
  788. return "/Tx BMC q BT " + defaultAppearance + ` 1 0 0 1 ${hPadding} ${vPadding} Tm (${(0, _util.escapeString)(encodedString)}) Tj` + " ET Q EMC";
  789. }
  790. const renderedText = this._renderText(encodedString, font, fontSize, totalWidth, alignment, hPadding, vPadding);
  791. return "/Tx BMC q BT " + defaultAppearance + ` 1 0 0 1 0 0 Tm ${renderedText}` + " ET Q EMC";
  792. }
  793. async _getFontData(evaluator, task) {
  794. const operatorList = new _operator_list.OperatorList();
  795. const initialState = {
  796. font: null,
  797. clone() {
  798. return this;
  799. }
  800. };
  801. const {
  802. fontName,
  803. fontSize
  804. } = this.data.defaultAppearanceData;
  805. await evaluator.handleSetFont(this._fieldResources.mergedResources, [fontName, fontSize], null, operatorList, task, initialState, null);
  806. return initialState.font;
  807. }
  808. _computeFontSize(font, height) {
  809. let fontSize = this.data.defaultAppearanceData.fontSize;
  810. if (!fontSize) {
  811. const {
  812. fontColor,
  813. fontName
  814. } = this.data.defaultAppearanceData;
  815. let capHeight;
  816. if (font.capHeight) {
  817. capHeight = font.capHeight;
  818. } else {
  819. const glyphs = font.charsToGlyphs(font.encodeString("M").join(""));
  820. if (glyphs.length === 1 && glyphs[0].width) {
  821. const em = glyphs[0].width / 1000;
  822. capHeight = 0.7 * em;
  823. } else {
  824. capHeight = 0.7;
  825. }
  826. }
  827. fontSize = Math.max(1, Math.floor(height / (1.5 * capHeight)));
  828. this.data.defaultAppearance = (0, _default_appearance.createDefaultAppearance)({
  829. fontSize,
  830. fontName,
  831. fontColor
  832. });
  833. }
  834. return fontSize;
  835. }
  836. _renderText(text, font, fontSize, totalWidth, alignment, hPadding, vPadding) {
  837. const glyphs = font.charsToGlyphs(text);
  838. const scale = fontSize / 1000;
  839. let width = 0;
  840. for (const glyph of glyphs) {
  841. width += glyph.width * scale;
  842. }
  843. let shift;
  844. if (alignment === 1) {
  845. shift = (totalWidth - width) / 2;
  846. } else if (alignment === 2) {
  847. shift = totalWidth - width - hPadding;
  848. } else {
  849. shift = hPadding;
  850. }
  851. shift = shift.toFixed(2);
  852. vPadding = vPadding.toFixed(2);
  853. return `${shift} ${vPadding} Td (${(0, _util.escapeString)(text)}) Tj`;
  854. }
  855. _getSaveFieldResources(xref) {
  856. const {
  857. localResources,
  858. appearanceResources,
  859. acroFormResources
  860. } = this._fieldResources;
  861. const fontNameStr = this.data.defaultAppearanceData && this.data.defaultAppearanceData.fontName.name;
  862. if (!fontNameStr) {
  863. return localResources || _primitives.Dict.empty;
  864. }
  865. for (const resources of [localResources, appearanceResources]) {
  866. if (resources instanceof _primitives.Dict) {
  867. const localFont = resources.get("Font");
  868. if (localFont instanceof _primitives.Dict && localFont.has(fontNameStr)) {
  869. return resources;
  870. }
  871. }
  872. }
  873. if (acroFormResources instanceof _primitives.Dict) {
  874. const acroFormFont = acroFormResources.get("Font");
  875. if (acroFormFont instanceof _primitives.Dict && acroFormFont.has(fontNameStr)) {
  876. const subFontDict = new _primitives.Dict(xref);
  877. subFontDict.set(fontNameStr, acroFormFont.getRaw(fontNameStr));
  878. const subResourcesDict = new _primitives.Dict(xref);
  879. subResourcesDict.set("Font", subFontDict);
  880. return _primitives.Dict.merge({
  881. xref,
  882. dictArray: [subResourcesDict, localResources],
  883. mergeSubDicts: true
  884. });
  885. }
  886. }
  887. return localResources || _primitives.Dict.empty;
  888. }
  889. getFieldObject() {
  890. if (this.data.fieldType === "Sig") {
  891. return {
  892. id: this.data.id,
  893. value: null,
  894. type: "signature"
  895. };
  896. }
  897. return null;
  898. }
  899. }
  900. class TextWidgetAnnotation extends WidgetAnnotation {
  901. constructor(params) {
  902. super(params);
  903. this._hasText = true;
  904. const dict = params.dict;
  905. if (!(0, _util.isString)(this.data.fieldValue)) {
  906. this.data.fieldValue = "";
  907. }
  908. let alignment = (0, _core_utils.getInheritableProperty)({
  909. dict,
  910. key: "Q"
  911. });
  912. if (!Number.isInteger(alignment) || alignment < 0 || alignment > 2) {
  913. alignment = null;
  914. }
  915. this.data.textAlignment = alignment;
  916. let maximumLength = (0, _core_utils.getInheritableProperty)({
  917. dict,
  918. key: "MaxLen"
  919. });
  920. if (!Number.isInteger(maximumLength) || maximumLength < 0) {
  921. maximumLength = null;
  922. }
  923. this.data.maxLen = maximumLength;
  924. this.data.multiLine = this.hasFieldFlag(_util.AnnotationFieldFlag.MULTILINE);
  925. this.data.comb = this.hasFieldFlag(_util.AnnotationFieldFlag.COMB) && !this.hasFieldFlag(_util.AnnotationFieldFlag.MULTILINE) && !this.hasFieldFlag(_util.AnnotationFieldFlag.PASSWORD) && !this.hasFieldFlag(_util.AnnotationFieldFlag.FILESELECT) && this.data.maxLen !== null;
  926. }
  927. _getCombAppearance(defaultAppearance, font, text, width, hPadding, vPadding) {
  928. const combWidth = (width / this.data.maxLen).toFixed(2);
  929. const buf = [];
  930. const positions = font.getCharPositions(text);
  931. for (const [start, end] of positions) {
  932. buf.push(`(${(0, _util.escapeString)(text.substring(start, end))}) Tj`);
  933. }
  934. const renderedComb = buf.join(` ${combWidth} 0 Td `);
  935. return "/Tx BMC q BT " + defaultAppearance + ` 1 0 0 1 ${hPadding} ${vPadding} Tm ${renderedComb}` + " ET Q EMC";
  936. }
  937. _getMultilineAppearance(defaultAppearance, text, font, fontSize, width, height, alignment, hPadding, vPadding) {
  938. const lines = text.split(/\r\n|\r|\n/);
  939. const buf = [];
  940. const totalWidth = width - 2 * hPadding;
  941. for (const line of lines) {
  942. const chunks = this._splitLine(line, font, fontSize, totalWidth);
  943. for (const chunk of chunks) {
  944. const padding = buf.length === 0 ? hPadding : 0;
  945. buf.push(this._renderText(chunk, font, fontSize, width, alignment, padding, -fontSize));
  946. }
  947. }
  948. const renderedText = buf.join("\n");
  949. return "/Tx BMC q BT " + defaultAppearance + ` 1 0 0 1 0 ${height} Tm ${renderedText}` + " ET Q EMC";
  950. }
  951. _splitLine(line, font, fontSize, width) {
  952. line = font.encodeString(line).join("");
  953. const glyphs = font.charsToGlyphs(line);
  954. if (glyphs.length <= 1) {
  955. return [line];
  956. }
  957. const positions = font.getCharPositions(line);
  958. const scale = fontSize / 1000;
  959. const chunks = [];
  960. let lastSpacePosInStringStart = -1,
  961. lastSpacePosInStringEnd = -1,
  962. lastSpacePos = -1,
  963. startChunk = 0,
  964. currentWidth = 0;
  965. for (let i = 0, ii = glyphs.length; i < ii; i++) {
  966. const [start, end] = positions[i];
  967. const glyph = glyphs[i];
  968. const glyphWidth = glyph.width * scale;
  969. if (glyph.unicode === " ") {
  970. if (currentWidth + glyphWidth > width) {
  971. chunks.push(line.substring(startChunk, start));
  972. startChunk = start;
  973. currentWidth = glyphWidth;
  974. lastSpacePosInStringStart = -1;
  975. lastSpacePos = -1;
  976. } else {
  977. currentWidth += glyphWidth;
  978. lastSpacePosInStringStart = start;
  979. lastSpacePosInStringEnd = end;
  980. lastSpacePos = i;
  981. }
  982. } else {
  983. if (currentWidth + glyphWidth > width) {
  984. if (lastSpacePosInStringStart !== -1) {
  985. chunks.push(line.substring(startChunk, lastSpacePosInStringEnd));
  986. startChunk = lastSpacePosInStringEnd;
  987. i = lastSpacePos + 1;
  988. lastSpacePosInStringStart = -1;
  989. currentWidth = 0;
  990. } else {
  991. chunks.push(line.substring(startChunk, start));
  992. startChunk = start;
  993. currentWidth = glyphWidth;
  994. }
  995. } else {
  996. currentWidth += glyphWidth;
  997. }
  998. }
  999. }
  1000. if (startChunk < line.length) {
  1001. chunks.push(line.substring(startChunk, line.length));
  1002. }
  1003. return chunks;
  1004. }
  1005. getFieldObject() {
  1006. return {
  1007. id: this.data.id,
  1008. value: this.data.fieldValue,
  1009. defaultValue: this.data.defaultFieldValue,
  1010. multiline: this.data.multiLine,
  1011. password: this.hasFieldFlag(_util.AnnotationFieldFlag.PASSWORD),
  1012. charLimit: this.data.maxLen,
  1013. comb: this.data.comb,
  1014. editable: !this.data.readOnly,
  1015. hidden: this.data.hidden,
  1016. name: this.data.fieldName,
  1017. rect: this.data.rect,
  1018. actions: this.data.actions,
  1019. type: "text"
  1020. };
  1021. }
  1022. }
  1023. class ButtonWidgetAnnotation extends WidgetAnnotation {
  1024. constructor(params) {
  1025. super(params);
  1026. this.checkedAppearance = null;
  1027. this.uncheckedAppearance = null;
  1028. this.data.checkBox = !this.hasFieldFlag(_util.AnnotationFieldFlag.RADIO) && !this.hasFieldFlag(_util.AnnotationFieldFlag.PUSHBUTTON);
  1029. this.data.radioButton = this.hasFieldFlag(_util.AnnotationFieldFlag.RADIO) && !this.hasFieldFlag(_util.AnnotationFieldFlag.PUSHBUTTON);
  1030. this.data.pushButton = this.hasFieldFlag(_util.AnnotationFieldFlag.PUSHBUTTON);
  1031. this.data.isTooltipOnly = false;
  1032. if (this.data.checkBox) {
  1033. this._processCheckBox(params);
  1034. } else if (this.data.radioButton) {
  1035. this._processRadioButton(params);
  1036. } else if (this.data.pushButton) {
  1037. this._processPushButton(params);
  1038. } else {
  1039. (0, _util.warn)("Invalid field flags for button widget annotation");
  1040. }
  1041. }
  1042. getOperatorList(evaluator, task, renderForms, annotationStorage) {
  1043. if (this.data.pushButton) {
  1044. return super.getOperatorList(evaluator, task, false, annotationStorage);
  1045. }
  1046. if (annotationStorage) {
  1047. const value = annotationStorage[this.data.id] && annotationStorage[this.data.id].value;
  1048. if (value === undefined) {
  1049. return super.getOperatorList(evaluator, task, renderForms, annotationStorage);
  1050. }
  1051. let appearance;
  1052. if (value) {
  1053. appearance = this.checkedAppearance;
  1054. } else {
  1055. appearance = this.uncheckedAppearance;
  1056. }
  1057. if (appearance) {
  1058. const savedAppearance = this.appearance;
  1059. this.appearance = appearance;
  1060. const operatorList = super.getOperatorList(evaluator, task, renderForms, annotationStorage);
  1061. this.appearance = savedAppearance;
  1062. return operatorList;
  1063. }
  1064. return Promise.resolve(new _operator_list.OperatorList());
  1065. }
  1066. return super.getOperatorList(evaluator, task, renderForms, annotationStorage);
  1067. }
  1068. async save(evaluator, task, annotationStorage) {
  1069. if (this.data.checkBox) {
  1070. return this._saveCheckbox(evaluator, task, annotationStorage);
  1071. }
  1072. if (this.data.radioButton) {
  1073. return this._saveRadioButton(evaluator, task, annotationStorage);
  1074. }
  1075. return null;
  1076. }
  1077. async _saveCheckbox(evaluator, task, annotationStorage) {
  1078. const value = annotationStorage[this.data.id] && annotationStorage[this.data.id].value;
  1079. if (value === undefined) {
  1080. return null;
  1081. }
  1082. const defaultValue = this.data.fieldValue && this.data.fieldValue !== "Off";
  1083. if (defaultValue === value) {
  1084. return null;
  1085. }
  1086. const dict = evaluator.xref.fetchIfRef(this.ref);
  1087. if (!(0, _primitives.isDict)(dict)) {
  1088. return null;
  1089. }
  1090. const xfa = {
  1091. path: (0, _util.stringToPDFString)(dict.get("T") || ""),
  1092. value: value ? this.data.exportValue : ""
  1093. };
  1094. const name = _primitives.Name.get(value ? this.data.exportValue : "Off");
  1095. dict.set("V", name);
  1096. dict.set("AS", name);
  1097. dict.set("M", `D:${(0, _util.getModificationDate)()}`);
  1098. const encrypt = evaluator.xref.encrypt;
  1099. let originalTransform = null;
  1100. if (encrypt) {
  1101. originalTransform = encrypt.createCipherTransform(this.ref.num, this.ref.gen);
  1102. }
  1103. const buffer = [`${this.ref.num} ${this.ref.gen} obj\n`];
  1104. (0, _writer.writeDict)(dict, buffer, originalTransform);
  1105. buffer.push("\nendobj\n");
  1106. return [{
  1107. ref: this.ref,
  1108. data: buffer.join(""),
  1109. xfa
  1110. }];
  1111. }
  1112. async _saveRadioButton(evaluator, task, annotationStorage) {
  1113. const value = annotationStorage[this.data.id] && annotationStorage[this.data.id].value;
  1114. if (value === undefined) {
  1115. return null;
  1116. }
  1117. const defaultValue = this.data.fieldValue === this.data.buttonValue;
  1118. if (defaultValue === value) {
  1119. return null;
  1120. }
  1121. const dict = evaluator.xref.fetchIfRef(this.ref);
  1122. if (!(0, _primitives.isDict)(dict)) {
  1123. return null;
  1124. }
  1125. const xfa = {
  1126. path: (0, _util.stringToPDFString)(dict.get("T") || ""),
  1127. value: value ? this.data.buttonValue : ""
  1128. };
  1129. const name = _primitives.Name.get(value ? this.data.buttonValue : "Off");
  1130. let parentBuffer = null;
  1131. const encrypt = evaluator.xref.encrypt;
  1132. if (value) {
  1133. if ((0, _primitives.isRef)(this.parent)) {
  1134. const parent = evaluator.xref.fetch(this.parent);
  1135. let parentTransform = null;
  1136. if (encrypt) {
  1137. parentTransform = encrypt.createCipherTransform(this.parent.num, this.parent.gen);
  1138. }
  1139. parent.set("V", name);
  1140. parentBuffer = [`${this.parent.num} ${this.parent.gen} obj\n`];
  1141. (0, _writer.writeDict)(parent, parentBuffer, parentTransform);
  1142. parentBuffer.push("\nendobj\n");
  1143. } else if ((0, _primitives.isDict)(this.parent)) {
  1144. this.parent.set("V", name);
  1145. }
  1146. }
  1147. dict.set("AS", name);
  1148. dict.set("M", `D:${(0, _util.getModificationDate)()}`);
  1149. let originalTransform = null;
  1150. if (encrypt) {
  1151. originalTransform = encrypt.createCipherTransform(this.ref.num, this.ref.gen);
  1152. }
  1153. const buffer = [`${this.ref.num} ${this.ref.gen} obj\n`];
  1154. (0, _writer.writeDict)(dict, buffer, originalTransform);
  1155. buffer.push("\nendobj\n");
  1156. const newRefs = [{
  1157. ref: this.ref,
  1158. data: buffer.join(""),
  1159. xfa
  1160. }];
  1161. if (parentBuffer !== null) {
  1162. newRefs.push({
  1163. ref: this.parent,
  1164. data: parentBuffer.join(""),
  1165. xfa: null
  1166. });
  1167. }
  1168. return newRefs;
  1169. }
  1170. _processCheckBox(params) {
  1171. const customAppearance = params.dict.get("AP");
  1172. if (!(0, _primitives.isDict)(customAppearance)) {
  1173. return;
  1174. }
  1175. const normalAppearance = customAppearance.get("N");
  1176. if (!(0, _primitives.isDict)(normalAppearance)) {
  1177. return;
  1178. }
  1179. const exportValues = normalAppearance.getKeys();
  1180. if (!exportValues.includes("Off")) {
  1181. exportValues.push("Off");
  1182. }
  1183. if (exportValues.length !== 2) {
  1184. return;
  1185. }
  1186. this.data.exportValue = exportValues[0] === "Off" ? exportValues[1] : exportValues[0];
  1187. this.checkedAppearance = normalAppearance.get(this.data.exportValue);
  1188. this.uncheckedAppearance = normalAppearance.get("Off") || null;
  1189. this._streams.push(this.checkedAppearance);
  1190. if (this.uncheckedAppearance) {
  1191. this._streams.push(this.uncheckedAppearance);
  1192. }
  1193. this._fallbackFontDict = this.fallbackFontDict;
  1194. }
  1195. _processRadioButton(params) {
  1196. this.data.fieldValue = this.data.buttonValue = null;
  1197. const fieldParent = params.dict.get("Parent");
  1198. if ((0, _primitives.isDict)(fieldParent)) {
  1199. this.parent = params.dict.getRaw("Parent");
  1200. const fieldParentValue = fieldParent.get("V");
  1201. if ((0, _primitives.isName)(fieldParentValue)) {
  1202. this.data.fieldValue = this._decodeFormValue(fieldParentValue);
  1203. }
  1204. }
  1205. const appearanceStates = params.dict.get("AP");
  1206. if (!(0, _primitives.isDict)(appearanceStates)) {
  1207. return;
  1208. }
  1209. const normalAppearance = appearanceStates.get("N");
  1210. if (!(0, _primitives.isDict)(normalAppearance)) {
  1211. return;
  1212. }
  1213. for (const key of normalAppearance.getKeys()) {
  1214. if (key !== "Off") {
  1215. this.data.buttonValue = this._decodeFormValue(key);
  1216. break;
  1217. }
  1218. }
  1219. this.checkedAppearance = normalAppearance.get(this.data.buttonValue);
  1220. this.uncheckedAppearance = normalAppearance.get("Off") || null;
  1221. this._streams.push(this.checkedAppearance);
  1222. if (this.uncheckedAppearance) {
  1223. this._streams.push(this.uncheckedAppearance);
  1224. }
  1225. this._fallbackFontDict = this.fallbackFontDict;
  1226. }
  1227. _processPushButton(params) {
  1228. if (!params.dict.has("A") && !params.dict.has("AA") && !this.data.alternativeText) {
  1229. (0, _util.warn)("Push buttons without action dictionaries are not supported");
  1230. return;
  1231. }
  1232. this.data.isTooltipOnly = !params.dict.has("A") && !params.dict.has("AA");
  1233. _obj.Catalog.parseDestDictionary({
  1234. destDict: params.dict,
  1235. resultObj: this.data,
  1236. docBaseUrl: params.pdfManager.docBaseUrl
  1237. });
  1238. }
  1239. getFieldObject() {
  1240. let type = "button";
  1241. let exportValues;
  1242. if (this.data.checkBox) {
  1243. type = "checkbox";
  1244. exportValues = this.data.exportValue;
  1245. } else if (this.data.radioButton) {
  1246. type = "radiobutton";
  1247. exportValues = this.data.buttonValue;
  1248. }
  1249. return {
  1250. id: this.data.id,
  1251. value: this.data.fieldValue || "Off",
  1252. defaultValue: this.data.defaultFieldValue,
  1253. exportValues,
  1254. editable: !this.data.readOnly,
  1255. name: this.data.fieldName,
  1256. rect: this.data.rect,
  1257. hidden: this.data.hidden,
  1258. actions: this.data.actions,
  1259. type
  1260. };
  1261. }
  1262. get fallbackFontDict() {
  1263. const dict = new _primitives.Dict();
  1264. dict.set("BaseFont", _primitives.Name.get("ZapfDingbats"));
  1265. dict.set("Type", _primitives.Name.get("FallbackType"));
  1266. dict.set("Subtype", _primitives.Name.get("FallbackType"));
  1267. dict.set("Encoding", _primitives.Name.get("ZapfDingbatsEncoding"));
  1268. return (0, _util.shadow)(this, "fallbackFontDict", dict);
  1269. }
  1270. }
  1271. class ChoiceWidgetAnnotation extends WidgetAnnotation {
  1272. constructor(params) {
  1273. super(params);
  1274. this.data.options = [];
  1275. const options = (0, _core_utils.getInheritableProperty)({
  1276. dict: params.dict,
  1277. key: "Opt"
  1278. });
  1279. if (Array.isArray(options)) {
  1280. const xref = params.xref;
  1281. for (let i = 0, ii = options.length; i < ii; i++) {
  1282. const option = xref.fetchIfRef(options[i]);
  1283. const isOptionArray = Array.isArray(option);
  1284. this.data.options[i] = {
  1285. exportValue: this._decodeFormValue(isOptionArray ? xref.fetchIfRef(option[0]) : option),
  1286. displayValue: this._decodeFormValue(isOptionArray ? xref.fetchIfRef(option[1]) : option)
  1287. };
  1288. }
  1289. }
  1290. if ((0, _util.isString)(this.data.fieldValue)) {
  1291. this.data.fieldValue = [this.data.fieldValue];
  1292. } else if (!this.data.fieldValue) {
  1293. this.data.fieldValue = [];
  1294. }
  1295. this.data.combo = this.hasFieldFlag(_util.AnnotationFieldFlag.COMBO);
  1296. this.data.multiSelect = this.hasFieldFlag(_util.AnnotationFieldFlag.MULTISELECT);
  1297. this._hasText = true;
  1298. }
  1299. getFieldObject() {
  1300. const type = this.data.combo ? "combobox" : "listbox";
  1301. const value = this.data.fieldValue.length > 0 ? this.data.fieldValue[0] : null;
  1302. return {
  1303. id: this.data.id,
  1304. value,
  1305. defaultValue: this.data.defaultFieldValue,
  1306. editable: !this.data.readOnly,
  1307. name: this.data.fieldName,
  1308. rect: this.data.rect,
  1309. numItems: this.data.fieldValue.length,
  1310. multipleSelection: this.data.multiSelect,
  1311. hidden: this.data.hidden,
  1312. actions: this.data.actions,
  1313. type
  1314. };
  1315. }
  1316. }
  1317. class TextAnnotation extends MarkupAnnotation {
  1318. constructor(parameters) {
  1319. const DEFAULT_ICON_SIZE = 22;
  1320. super(parameters);
  1321. const dict = parameters.dict;
  1322. this.data.annotationType = _util.AnnotationType.TEXT;
  1323. if (this.data.hasAppearance) {
  1324. this.data.name = "NoIcon";
  1325. } else {
  1326. this.data.rect[1] = this.data.rect[3] - DEFAULT_ICON_SIZE;
  1327. this.data.rect[2] = this.data.rect[0] + DEFAULT_ICON_SIZE;
  1328. this.data.name = dict.has("Name") ? dict.get("Name").name : "Note";
  1329. }
  1330. if (dict.has("State")) {
  1331. this.data.state = dict.get("State") || null;
  1332. this.data.stateModel = dict.get("StateModel") || null;
  1333. } else {
  1334. this.data.state = null;
  1335. this.data.stateModel = null;
  1336. }
  1337. }
  1338. }
  1339. class LinkAnnotation extends Annotation {
  1340. constructor(params) {
  1341. super(params);
  1342. this.data.annotationType = _util.AnnotationType.LINK;
  1343. const quadPoints = getQuadPoints(params.dict, this.rectangle);
  1344. if (quadPoints) {
  1345. this.data.quadPoints = quadPoints;
  1346. }
  1347. _obj.Catalog.parseDestDictionary({
  1348. destDict: params.dict,
  1349. resultObj: this.data,
  1350. docBaseUrl: params.pdfManager.docBaseUrl
  1351. });
  1352. }
  1353. }
  1354. class PopupAnnotation extends Annotation {
  1355. constructor(parameters) {
  1356. super(parameters);
  1357. this.data.annotationType = _util.AnnotationType.POPUP;
  1358. let parentItem = parameters.dict.get("Parent");
  1359. if (!parentItem) {
  1360. (0, _util.warn)("Popup annotation has a missing or invalid parent annotation.");
  1361. return;
  1362. }
  1363. const parentSubtype = parentItem.get("Subtype");
  1364. this.data.parentType = (0, _primitives.isName)(parentSubtype) ? parentSubtype.name : null;
  1365. const rawParent = parameters.dict.getRaw("Parent");
  1366. this.data.parentId = (0, _primitives.isRef)(rawParent) ? rawParent.toString() : null;
  1367. const parentRect = parentItem.getArray("Rect");
  1368. if (Array.isArray(parentRect) && parentRect.length === 4) {
  1369. this.data.parentRect = _util.Util.normalizeRect(parentRect);
  1370. } else {
  1371. this.data.parentRect = [0, 0, 0, 0];
  1372. }
  1373. const rt = parentItem.get("RT");
  1374. if ((0, _primitives.isName)(rt, _util.AnnotationReplyType.GROUP)) {
  1375. parentItem = parentItem.get("IRT");
  1376. }
  1377. if (!parentItem.has("M")) {
  1378. this.data.modificationDate = null;
  1379. } else {
  1380. this.setModificationDate(parentItem.get("M"));
  1381. this.data.modificationDate = this.modificationDate;
  1382. }
  1383. if (!parentItem.has("C")) {
  1384. this.data.color = null;
  1385. } else {
  1386. this.setColor(parentItem.getArray("C"));
  1387. this.data.color = this.color;
  1388. }
  1389. if (!this.viewable) {
  1390. const parentFlags = parentItem.get("F");
  1391. if (this._isViewable(parentFlags)) {
  1392. this.setFlags(parentFlags);
  1393. }
  1394. }
  1395. this.data.title = (0, _util.stringToPDFString)(parentItem.get("T") || "");
  1396. this.data.contents = (0, _util.stringToPDFString)(parentItem.get("Contents") || "");
  1397. }
  1398. }
  1399. class FreeTextAnnotation extends MarkupAnnotation {
  1400. constructor(parameters) {
  1401. super(parameters);
  1402. this.data.annotationType = _util.AnnotationType.FREETEXT;
  1403. }
  1404. }
  1405. class LineAnnotation extends MarkupAnnotation {
  1406. constructor(parameters) {
  1407. super(parameters);
  1408. this.data.annotationType = _util.AnnotationType.LINE;
  1409. this.data.lineCoordinates = _util.Util.normalizeRect(parameters.dict.getArray("L"));
  1410. }
  1411. }
  1412. class SquareAnnotation extends MarkupAnnotation {
  1413. constructor(parameters) {
  1414. super(parameters);
  1415. this.data.annotationType = _util.AnnotationType.SQUARE;
  1416. }
  1417. }
  1418. class CircleAnnotation extends MarkupAnnotation {
  1419. constructor(parameters) {
  1420. super(parameters);
  1421. this.data.annotationType = _util.AnnotationType.CIRCLE;
  1422. }
  1423. }
  1424. class PolylineAnnotation extends MarkupAnnotation {
  1425. constructor(parameters) {
  1426. super(parameters);
  1427. this.data.annotationType = _util.AnnotationType.POLYLINE;
  1428. this.data.vertices = [];
  1429. const rawVertices = parameters.dict.getArray("Vertices");
  1430. if (!Array.isArray(rawVertices)) {
  1431. return;
  1432. }
  1433. for (let i = 0, ii = rawVertices.length; i < ii; i += 2) {
  1434. this.data.vertices.push({
  1435. x: rawVertices[i],
  1436. y: rawVertices[i + 1]
  1437. });
  1438. }
  1439. }
  1440. }
  1441. class PolygonAnnotation extends PolylineAnnotation {
  1442. constructor(parameters) {
  1443. super(parameters);
  1444. this.data.annotationType = _util.AnnotationType.POLYGON;
  1445. }
  1446. }
  1447. class CaretAnnotation extends MarkupAnnotation {
  1448. constructor(parameters) {
  1449. super(parameters);
  1450. this.data.annotationType = _util.AnnotationType.CARET;
  1451. }
  1452. }
  1453. class InkAnnotation extends MarkupAnnotation {
  1454. constructor(parameters) {
  1455. super(parameters);
  1456. this.data.annotationType = _util.AnnotationType.INK;
  1457. this.data.inkLists = [];
  1458. const rawInkLists = parameters.dict.getArray("InkList");
  1459. if (!Array.isArray(rawInkLists)) {
  1460. return;
  1461. }
  1462. const xref = parameters.xref;
  1463. for (let i = 0, ii = rawInkLists.length; i < ii; ++i) {
  1464. this.data.inkLists.push([]);
  1465. for (let j = 0, jj = rawInkLists[i].length; j < jj; j += 2) {
  1466. this.data.inkLists[i].push({
  1467. x: xref.fetchIfRef(rawInkLists[i][j]),
  1468. y: xref.fetchIfRef(rawInkLists[i][j + 1])
  1469. });
  1470. }
  1471. }
  1472. }
  1473. }
  1474. class HighlightAnnotation extends MarkupAnnotation {
  1475. constructor(parameters) {
  1476. super(parameters);
  1477. this.data.annotationType = _util.AnnotationType.HIGHLIGHT;
  1478. const quadPoints = this.data.quadPoints = getQuadPoints(parameters.dict, null);
  1479. if (quadPoints) {
  1480. if (!this.appearance) {
  1481. const fillColor = this.color ? Array.from(this.color).map(c => c / 255) : [1, 1, 0];
  1482. this._setDefaultAppearance({
  1483. xref: parameters.xref,
  1484. fillColor,
  1485. blendMode: "Multiply",
  1486. pointsCallback: (buffer, points) => {
  1487. buffer.push(`${points[0].x} ${points[0].y} m`);
  1488. buffer.push(`${points[1].x} ${points[1].y} l`);
  1489. buffer.push(`${points[3].x} ${points[3].y} l`);
  1490. buffer.push(`${points[2].x} ${points[2].y} l`);
  1491. buffer.push("f");
  1492. return [points[0].x, points[1].x, points[3].y, points[1].y];
  1493. }
  1494. });
  1495. }
  1496. } else {
  1497. this.data.hasPopup = false;
  1498. }
  1499. }
  1500. }
  1501. class UnderlineAnnotation extends MarkupAnnotation {
  1502. constructor(parameters) {
  1503. super(parameters);
  1504. this.data.annotationType = _util.AnnotationType.UNDERLINE;
  1505. const quadPoints = this.data.quadPoints = getQuadPoints(parameters.dict, null);
  1506. if (quadPoints) {
  1507. if (!this.appearance) {
  1508. const strokeColor = this.color ? Array.from(this.color).map(c => c / 255) : [0, 0, 0];
  1509. this._setDefaultAppearance({
  1510. xref: parameters.xref,
  1511. extra: "[] 0 d 1 w",
  1512. strokeColor,
  1513. pointsCallback: (buffer, points) => {
  1514. buffer.push(`${points[2].x} ${points[2].y} m`);
  1515. buffer.push(`${points[3].x} ${points[3].y} l`);
  1516. buffer.push("S");
  1517. return [points[0].x, points[1].x, points[3].y, points[1].y];
  1518. }
  1519. });
  1520. }
  1521. } else {
  1522. this.data.hasPopup = false;
  1523. }
  1524. }
  1525. }
  1526. class SquigglyAnnotation extends MarkupAnnotation {
  1527. constructor(parameters) {
  1528. super(parameters);
  1529. this.data.annotationType = _util.AnnotationType.SQUIGGLY;
  1530. const quadPoints = this.data.quadPoints = getQuadPoints(parameters.dict, null);
  1531. if (quadPoints) {
  1532. if (!this.appearance) {
  1533. const strokeColor = this.color ? Array.from(this.color).map(c => c / 255) : [0, 0, 0];
  1534. this._setDefaultAppearance({
  1535. xref: parameters.xref,
  1536. extra: "[] 0 d 1 w",
  1537. strokeColor,
  1538. pointsCallback: (buffer, points) => {
  1539. const dy = (points[0].y - points[2].y) / 6;
  1540. let shift = dy;
  1541. let x = points[2].x;
  1542. const y = points[2].y;
  1543. const xEnd = points[3].x;
  1544. buffer.push(`${x} ${y + shift} m`);
  1545. do {
  1546. x += 2;
  1547. shift = shift === 0 ? dy : 0;
  1548. buffer.push(`${x} ${y + shift} l`);
  1549. } while (x < xEnd);
  1550. buffer.push("S");
  1551. return [points[2].x, xEnd, y - 2 * dy, y + 2 * dy];
  1552. }
  1553. });
  1554. }
  1555. } else {
  1556. this.data.hasPopup = false;
  1557. }
  1558. }
  1559. }
  1560. class StrikeOutAnnotation extends MarkupAnnotation {
  1561. constructor(parameters) {
  1562. super(parameters);
  1563. this.data.annotationType = _util.AnnotationType.STRIKEOUT;
  1564. const quadPoints = this.data.quadPoints = getQuadPoints(parameters.dict, null);
  1565. if (quadPoints) {
  1566. if (!this.appearance) {
  1567. const strokeColor = this.color ? Array.from(this.color).map(c => c / 255) : [0, 0, 0];
  1568. this._setDefaultAppearance({
  1569. xref: parameters.xref,
  1570. extra: "[] 0 d 1 w",
  1571. strokeColor,
  1572. pointsCallback: (buffer, points) => {
  1573. buffer.push(`${(points[0].x + points[2].x) / 2}` + ` ${(points[0].y + points[2].y) / 2} m`);
  1574. buffer.push(`${(points[1].x + points[3].x) / 2}` + ` ${(points[1].y + points[3].y) / 2} l`);
  1575. buffer.push("S");
  1576. return [points[0].x, points[1].x, points[3].y, points[1].y];
  1577. }
  1578. });
  1579. }
  1580. } else {
  1581. this.data.hasPopup = false;
  1582. }
  1583. }
  1584. }
  1585. class StampAnnotation extends MarkupAnnotation {
  1586. constructor(parameters) {
  1587. super(parameters);
  1588. this.data.annotationType = _util.AnnotationType.STAMP;
  1589. }
  1590. }
  1591. class FileAttachmentAnnotation extends MarkupAnnotation {
  1592. constructor(parameters) {
  1593. super(parameters);
  1594. const file = new _obj.FileSpec(parameters.dict.get("FS"), parameters.xref);
  1595. this.data.annotationType = _util.AnnotationType.FILEATTACHMENT;
  1596. this.data.file = file.serializable;
  1597. }
  1598. }