001: package com.etymon.pjx.util;
002:
003: import java.io.*;
004: import java.util.*;
005: import com.etymon.pj.*;
006: import com.etymon.pj.exception.*;
007: import com.etymon.pj.object.*;
008: import com.etymon.pj.object.pagemark.*;
009: import com.etymon.pjx.*;
010:
011: /**
012: Provides methods for retrieving and modifying various elements of a
013: PDF document.
014: @author Nassib Nassar
015: @deprecated
016: */
017: public class PdfModifier {
018:
019: /**
020: Returns the number of pages in the document.
021: @return the number of pages.
022: @throws IOException
023: @throws PdfFormatException
024: @deprecated Use {@link PdfPageTree#getNumberOfPages()
025: PdfPageTree.getNumberOfPages()}.
026: */
027: public int getPageCount() throws IOException,
028: com.etymon.pjx.PdfFormatException {
029: return new PdfPageTree(_m).getNumberOfPages();
030: }
031:
032: /**
033: A <code>PdfName</code> object representing the name
034: <code>AcroForm</code>.
035: */
036: protected static final PdfName PDFNAME_ACROFORM = new PdfName(
037: "AcroForm");
038:
039: /**
040: A <code>PdfName</code> object representing the name
041: <code>Fields</code>.
042: */
043: protected static final PdfName PDFNAME_FIELDS = new PdfName(
044: "Fields");
045:
046: /**
047: A <code>PdfName</code> object representing the name
048: <code>Kids</code>.
049: */
050: protected static final PdfName PDFNAME_KIDS = new PdfName("Kids");
051:
052: /**
053: A <code>PdfName</code> object representing the name
054: <code>Pages</code>.
055: */
056: protected static final PdfName PDFNAME_PAGES = new PdfName("Pages");
057:
058: /**
059: A <code>PdfName</code> object representing the name
060: <code>Root</code>.
061: */
062: protected static final PdfName PDFNAME_ROOT = new PdfName("Root");
063:
064: /**
065: The manager associated with this document.
066: */
067: protected PdfManager _m;
068:
069: /**
070: Constructs a <code>PdfModifier</code> instance based on a
071: specified <code>PdfManager</code>.
072: */
073: public PdfModifier(PdfManager manager) {
074:
075: _m = manager;
076:
077: }
078:
079: /**
080: Retrieves an indirect reference to the document's catalog.
081: @return the indirect reference.
082: @throws PdfFormatException
083: @deprecated Use {@link PdfCatalog#getCatalog() PdfCatalog.getCatalog()}.
084: */
085: public PdfReference getCatalogReference()
086: throws com.etymon.pjx.PdfFormatException {
087: synchronized (this ) {
088:
089: PdfDictionary trailer = _m.getTrailerDictionary();
090:
091: Map map = trailer.getMap();
092:
093: Object root = map.get(PdfModifier.PDFNAME_ROOT);
094:
095: if (!(root instanceof PdfReference)) {
096: throw new com.etymon.pjx.PdfFormatException(
097: "Catalog dictionary is not an indirect reference.");
098: }
099:
100: return (PdfReference) root;
101: }
102: }
103:
104: /**
105: Retrieves the document's catalog.
106: @return the catalog object.
107: @throws IOException
108: @throws PdfFormatException
109: @deprecated Use {@link PdfCatalog#getCatalog() PdfCatalog.getCatalog()}.
110: */
111: public PdfDictionary getCatalog() throws IOException,
112: com.etymon.pjx.PdfFormatException {
113: synchronized (this ) {
114:
115: PdfReference catalogRef = getCatalogReference();
116:
117: if (catalogRef == null) {
118: return null;
119: }
120:
121: Object catalog = _m.getObjectIndirect(catalogRef);
122:
123: if (!(catalog instanceof PdfDictionary)) {
124: throw new com.etymon.pjx.PdfFormatException(
125: "Catalog is not a dictionary.");
126: }
127:
128: return (PdfDictionary) catalog;
129: }
130: }
131:
132: /**
133: Sets the document's catalog to a specified value.
134: @param catalog the new catalog.
135: @throws PdfFormatException
136: @deprecated Use {@link PdfManager#setObject(PdfObject, int)
137: PdfManager.setObject(PdfObject, int)}.
138: */
139: public void setCatalog(PdfDictionary catalog)
140: throws com.etymon.pjx.PdfFormatException {
141: synchronized (this ) {
142:
143: PdfReference catalogRef = getCatalogReference();
144:
145: if (catalogRef != null) {
146:
147: _m.setObject(catalog, catalogRef.getObjectNumber());
148:
149: } else {
150:
151: // add catalog as a new indirect object
152: int catalogId = _m.addObject(catalog);
153:
154: // add reference to catalog in file
155: // trailer dictionary
156:
157: PdfDictionary trailer = _m.getTrailerDictionary();
158:
159: Map map = trailer.getMap();
160:
161: HashMap h = new HashMap(map.size());
162: h.putAll(map);
163:
164: h.put(PdfModifier.PDFNAME_ROOT, new PdfReference(
165: catalogId, 0));
166:
167: _m.setTrailerDictionary(new PdfDictionary(h));
168: }
169:
170: }
171: }
172:
173: /**
174: Retrieves an indirect reference to the root node of the
175: document's page tree.
176: @return the indirect reference.
177: @throws IOException
178: @throws PdfFormatException
179: @deprecated Use {@link PdfPageTree#getRoot()
180: PdfPageTree.getRoot()}.
181: */
182: public PdfReference getPageTreeRootReference() throws IOException,
183: com.etymon.pjx.PdfFormatException {
184: synchronized (this ) {
185:
186: PdfDictionary catalog = getCatalog();
187:
188: Map map = catalog.getMap();
189:
190: Object pages = map.get(PdfModifier.PDFNAME_PAGES);
191:
192: if (!(pages instanceof PdfReference)) {
193: throw new com.etymon.pjx.PdfFormatException(
194: "Page tree root (Pages) is not an indirect reference.");
195: }
196:
197: return (PdfReference) pages;
198: }
199: }
200:
201: /**
202: Retrieves the root node of the document's page tree.
203: @return the root node object.
204: @throws IOException
205: @throws PdfFormatException
206: @deprecated Use {@link PdfPageTree#getRoot() PdfPageTree.getRoot()}.
207: */
208: public PdfDictionary getPageTreeRoot() throws IOException,
209: com.etymon.pjx.PdfFormatException {
210: synchronized (this ) {
211:
212: PdfReference pageTreeRootRef = getPageTreeRootReference();
213:
214: if (pageTreeRootRef == null) {
215: return null;
216: }
217:
218: Object pageTreeRoot = _m.getObjectIndirect(pageTreeRootRef);
219:
220: if (!(pageTreeRoot instanceof PdfDictionary)) {
221: throw new com.etymon.pjx.PdfFormatException(
222: "Page tree root is not a dictionary.");
223: }
224:
225: return (PdfDictionary) pageTreeRoot;
226: }
227: }
228:
229: /**
230: Sets the root node of the document's page tree to a
231: specified value.
232: @param pageTreeNode the new root node.
233: @throws IOException
234: @throws PdfFormatException
235: @deprecated Use {@link PdfManager#setObject(PdfObject, int)
236: PdfManager.setObject(PdfObject, int)}.
237: */
238: public void setPageTreeRoot(PdfDictionary pageTreeRoot)
239: throws IOException, com.etymon.pjx.PdfFormatException {
240: synchronized (this ) {
241:
242: PdfReference pageTreeRootRef = getPageTreeRootReference();
243:
244: if (pageTreeRootRef != null) {
245:
246: _m.setObject(pageTreeRoot, pageTreeRootRef
247: .getObjectNumber());
248:
249: } else {
250:
251: // add page tree root as a new indirect object
252: int pageTreeRootId = _m.addObject(pageTreeRoot);
253:
254: // add reference to page tree root in catalog
255:
256: PdfDictionary catalog = getCatalog();
257:
258: Map map = catalog.getMap();
259:
260: HashMap h = new HashMap(map.size());
261: h.putAll(map);
262:
263: h.put(PdfModifier.PDFNAME_PAGES, new PdfReference(
264: pageTreeRootId, 0));
265:
266: setCatalog(new PdfDictionary(h));
267: }
268:
269: }
270: }
271:
272: /**
273: @deprecated
274: */
275: private void getFieldsAddField(ArrayList fieldList,
276: PdfReference fieldRef) throws IOException,
277: com.etymon.pjx.PdfFormatException {
278:
279: // resolve field reference
280: PdfDictionary field;
281: try {
282: field = (PdfDictionary) (_m.getObjectIndirect(fieldRef));
283: } catch (ClassCastException e) {
284: throw new com.etymon.pjx.PdfFormatException(
285: "Field object is not a dictionary.");
286: }
287:
288: Map fieldHt = field.getMap();
289:
290: // add the field to the list
291: fieldList.add(field);
292:
293: // check if there are any kids
294: PdfArray kids;
295: try {
296: kids = (PdfArray) (_m
297: .getObjectIndirect((PdfObject) (fieldHt
298: .get(PDFNAME_KIDS))));
299: } catch (ClassCastException e) {
300: throw new com.etymon.pjx.PdfFormatException(
301: "Kids object is not an array.");
302: }
303:
304: // if there are kids, descend the tree
305: if (kids != null) {
306: List kidsV = kids.getList();
307: int kidsV_n = kidsV.size();
308: for (int x = 0; x < kidsV_n; x++) {
309:
310: // get the field object
311: PdfReference fieldRef2;
312: try {
313: fieldRef2 = (PdfReference) (kidsV.get(x));
314: } catch (ClassCastException e) {
315: throw new com.etymon.pjx.PdfFormatException(
316: "Kids array element is not a reference.");
317: }
318:
319: getFieldsAddField(fieldList, fieldRef2);
320:
321: }
322: }
323:
324: }
325:
326: /**
327: This method is provided for compatibility with PJ. It will
328: be transitioned toward a dedicated field class.
329: @throws PdfFormatException
330: @deprecated
331: */
332: public PdfDictionary pjUpdateFieldValue(PdfDictionary origField,
333: PdfDictionary field, String value) throws IOException,
334: com.etymon.pjx.PdfFormatException {
335:
336: synchronized (this ) {
337:
338: try {
339:
340: Map origFieldHt = new HashMap(origField.getMap());
341:
342: Map fieldHt = field.getMap();
343:
344: // store old value for use in search/replace within appeareances stream(s)
345: PdfString oldValue = (PdfString) (fieldHt
346: .get(new PdfName("V")));
347:
348: PdfString valueString = new PdfString(value);
349: origFieldHt.put(new PdfName("V"), valueString);
350: origFieldHt.put(new PdfName("DV"), valueString);
351:
352: // determine quadding
353: PdfInteger q = (PdfInteger) (_m
354: .getObjectIndirect((PdfObject) (fieldHt
355: .get(new PdfName("Q")))));
356: boolean leftJustified = false;
357: boolean centered = false;
358: boolean rightJustified = false;
359: if (q == null) {
360: leftJustified = true;
361: } else {
362: switch (q.getInt()) {
363: case 1:
364: centered = true;
365: break;
366: case 2:
367: rightJustified = true;
368: break;
369: default:
370: leftJustified = true;
371: }
372: }
373:
374: PdfDictionary ap = (PdfDictionary) (_m
375: .getObjectIndirect((PdfObject) (fieldHt
376: .get(new PdfName("AP")))));
377: Map apHt;
378: if (ap == null) {
379: apHt = null;
380: } else {
381: apHt = new HashMap(ap.getMap());
382: PdfObject apnObj = (PdfObject) (apHt
383: .get(new PdfName("N")));
384: int apnId;
385: PdfReference apnRef;
386: PdfObject apn;
387: PdfDictionary apnDict;
388: byte[] apnBuffer;
389: if (apnObj instanceof PdfReference) {
390: // it's an indirect object
391: apnRef = (PdfReference) apnObj;
392: apnId = apnRef.getObjectNumber();
393: apn = _m.getObjectIndirect(apnRef);
394: } else {
395: // if it's not an indirect object, let's make it indirect
396: apnId = _m.addObject(apnObj);
397: apnRef = new PdfReference(apnId, 0);
398: apHt.put(new PdfName("N"), apnRef);
399: apn = apnObj;
400: }
401:
402: // "/C" = center text
403: // this assumes Courier 10 pt; we can add support
404: // for others if needed.
405: // it also assumes a page width of 8.5"; this also could
406: // be adjusted or read from the document.
407:
408: float rectX1 = 0;
409: float rectX2 = 0;
410: float rectWidth = 0;
411: if (centered) {
412: // adjust RECT
413: PdfArray rect = (PdfArray) (fieldHt
414: .get(new PdfName("Rect")));
415: List rectList = rect.getList();
416: rectX1 = ((PdfNumber) rectList.get(0))
417: .getFloat();
418: rectX2 = ((PdfNumber) rectList.get(2))
419: .getFloat();
420: rectWidth = rectX2 - rectX1;
421: }
422:
423: if ((apn != null) && (apn instanceof PdfStream)) {
424: // if centered: remove any text matrix adjustments.
425: // get page mark operators
426: PjStream apnPj = (PjStream) PjxConvert
427: .toPjObject(apn);
428: Vector pmVector = new StreamParser()
429: .parse(apnPj.flateDecompress());
430: if (oldValue != null) {
431: replaceTextData(pmVector, oldValue,
432: valueString);
433: }
434: if (centered) {
435: adjustTextMatrixX(pmVector, rectWidth);
436: }
437: // reconstruct stream from modified pmVector
438: ByteArrayOutputStream baos = new ByteArrayOutputStream();
439: for (int pmX = 0; pmX < pmVector.size(); pmX++) {
440: PageMark pm = (PageMark) (pmVector
441: .elementAt(pmX));
442: try {
443: pm.writePdf(baos);
444: } catch (IOException e) {
445: e.printStackTrace();
446: }
447: }
448: byte[] ba = baos.toByteArray();
449: PjStream temp = new PjStream(apnPj
450: .getStreamDictionary(), ba);
451: _m.setObject(PjxConvert.toPjxObject(temp),
452: apnId);
453: }
454: }
455:
456: if (apHt != null) {
457: origFieldHt.put(new PdfName("AP"),
458: new PdfDictionary(apHt));
459: }
460:
461: return new PdfDictionary(origFieldHt);
462:
463: } catch (com.etymon.pj.exception.PdfFormatException e) {
464: throw new com.etymon.pjx.PdfFormatException(e
465: .getMessage());
466: } catch (com.etymon.pj.exception.InvalidPdfObjectException f) {
467: throw new com.etymon.pjx.PdfFormatException(f
468: .getMessage());
469: }
470: }
471: }
472:
473: // used exclusively by updateFieldValue()
474: /**
475: @deprecated
476: */
477: private static void replaceTextData(Vector pmVector,
478: PdfString oldText, PdfString newText)
479: throws com.etymon.pj.exception.PdfFormatException {
480:
481: // this method replaces text data oldS with newS
482:
483: int pmX = pmVector.size();
484:
485: PjString oldTextPj = (PjString) PjxConvert.toPjObject(oldText);
486: PjString newTextPj = (PjString) PjxConvert.toPjObject(newText);
487:
488: // no particular reason for searching backwards; just
489: // because this was adapted from clearTextMatrixX()
490: while (pmX > 0) {
491:
492: pmX--;
493: PageMark pm = (PageMark) (pmVector.elementAt(pmX));
494:
495: if (pm instanceof XTj) {
496: XTj tj = (XTj) pm;
497: if (tj.getText().equals(oldTextPj)) {
498: XTj newTj = new XTj(newTextPj);
499: pmVector.setElementAt(newTj, pmX);
500: }
501: }
502:
503: }
504: }
505:
506: // used exclusively by updateFieldValue()
507: /**
508: @deprecated
509: */
510: private static void adjustTextMatrixX(Vector pmVector,
511: float rectWidth) {
512: // this method examines the last text matrix in
513: // pmVector and sets the X matrix value in order to
514: // center the text written by the subsequent Tj
515: // operator.
516:
517: int pmX = pmVector.size();
518: float textWidth = 0;
519: float rectCenter = rectWidth / 2;
520:
521: while (pmX > 0) {
522:
523: pmX--;
524: PageMark pm = (PageMark) (pmVector.elementAt(pmX));
525:
526: if (pm instanceof XTj) {
527: XTj tj = (XTj) pm;
528: textWidth = tj.getText().getString().length() * 6;
529: }
530:
531: if (pm instanceof XTm) {
532: float newX = rectCenter - (textWidth / 2);
533: if (newX < 0) {
534: newX = 0;
535: }
536: XTm tm = (XTm) pm;
537: XTm newTm = new XTm(tm.getA(), tm.getB(), tm.getC(), tm
538: .getD(), new PjNumber(newX), tm.getY());
539: pmVector.setElementAt(newTm, pmX);
540: pmX = 0; // Tm found, now we can stop
541: }
542:
543: }
544: }
545:
546: // used exclusively by updateFieldValue()
547: /**
548: @deprecated
549: */
550: private static void clearTextMatrixX(Vector pmVector) {
551: // this method examines the last text matrix in
552: // pmVector and sets the X matrix value to 0.
553:
554: int pmX = pmVector.size();
555:
556: while (pmX > 0) {
557:
558: pmX--;
559: PageMark pm = (PageMark) (pmVector.elementAt(pmX));
560:
561: if (pm instanceof XTm) {
562: XTm tm = (XTm) pm;
563: XTm newTm = new XTm(tm.getA(), tm.getB(), tm.getC(), tm
564: .getD(), PjNumber.ZERO, tm.getY());
565: pmVector.setElementAt(newTm, pmX);
566: pmX = 0; // Tm found, now we can stop
567: }
568:
569: }
570: }
571:
572: // used exclusively by inheritFieldAttributes()
573: /**
574: @deprecated
575: */
576: private void inheritFieldAttributesCollapse(PjName name,
577: Hashtable ht, PjDictionary newNode, PjDictionary parent) {
578: if (ht.get(name) == null) {
579: Object obj = parent.getHashtable().get(name);
580: if (obj != null) {
581: ht.put(name, obj);
582: }
583: }
584: }
585:
586: }
|