1 47 package com.lowagie.text.pdf; 48 49 import java.io.IOException ; 50 import java.io.OutputStream ; 51 import java.util.ArrayList ; 52 import java.util.HashMap ; 53 import java.util.HashSet ; 54 import java.util.Iterator ; 55 import java.util.List ; 56 import java.util.Map ; 57 58 import com.lowagie.text.DocumentException; 59 import com.lowagie.text.ExceptionConverter; 60 import com.lowagie.text.Image; 61 import com.lowagie.text.Rectangle; 62 import com.lowagie.text.pdf.collection.PdfCollection; 63 import com.lowagie.text.pdf.interfaces.PdfViewerPreferences; 64 import com.lowagie.text.pdf.internal.PdfViewerPreferencesImp; 65 66 class PdfStamperImp extends PdfWriter { 67 HashMap readers2intrefs = new HashMap (); 68 HashMap readers2file = new HashMap (); 69 RandomAccessFileOrArray file; 70 PdfReader reader; 71 IntHashtable myXref = new IntHashtable(); 72 73 HashMap pagesToContent = new HashMap (); 74 boolean closed = false; 75 76 private boolean rotateContents = true; 77 protected AcroFields acroFields; 78 protected boolean flat = false; 79 protected boolean flatFreeText = false; 80 protected int namePtr[] = {0}; 81 protected boolean namedAsNames; 82 protected List newBookmarks; 83 protected HashSet partialFlattening = new HashSet (); 84 protected boolean useVp = false; 85 protected PdfViewerPreferencesImp viewerPreferences = new PdfViewerPreferencesImp(); 86 protected HashMap fieldTemplates = new HashMap (); 87 protected boolean fieldsAdded = false; 88 protected int sigFlags = 0; 89 protected boolean append; 90 protected IntHashtable marked; 91 protected int initialXrefSize; 92 protected PdfAction openAction; 93 94 103 PdfStamperImp(PdfReader reader, OutputStream os, char pdfVersion, boolean append) throws DocumentException, IOException { 104 super(new PdfDocument(), os); 105 if (!reader.isOpenedWithFullPermissions()) 106 throw new IllegalArgumentException ("PdfReader not opened with owner password"); 107 if (reader.isTampered()) 108 throw new DocumentException("The original document was reused. Read it again from file."); 109 reader.setTampered(true); 110 this.reader = reader; 111 file = reader.getSafeFile(); 112 this.append = append; 113 if (append) { 114 if (reader.isRebuilt()) 115 throw new DocumentException("Append mode requires a document without errors even if recovery was possible."); 116 if (reader.isEncrypted()) 117 crypto = new PdfEncryption(reader.getDecrypt()); 118 pdf_version.setAppendmode(true); 119 file.reOpen(); 120 byte buf[] = new byte[8192]; 121 int n; 122 while ((n = file.read(buf)) > 0) 123 this.os.write(buf, 0, n); 124 file.close(); 125 prevxref = reader.getLastXref(); 126 reader.setAppendable(true); 127 } 128 else { 129 if (pdfVersion == 0) 130 super.setPdfVersion(reader.getPdfVersion()); 131 else 132 super.setPdfVersion(pdfVersion); 133 } 134 super.open(); 135 pdf.addWriter(this); 136 if (append) { 137 body.setRefnum(reader.getXrefSize()); 138 marked = new IntHashtable(); 139 if (reader.isNewXrefType()) 140 fullCompression = true; 141 if (reader.isHybridXref()) 142 fullCompression = false; 143 } 144 initialXrefSize = reader.getXrefSize(); 145 } 146 147 void close(HashMap moreInfo) throws IOException { 148 if (closed) 149 return; 150 if (useVp) { 151 reader.setViewerPreferences(viewerPreferences); 152 markUsed(reader.getTrailer().get(PdfName.ROOT)); 153 } 154 if (flat) 155 flatFields(); 156 if (flatFreeText) 157 flatFreeTextFields(); 158 addFieldResources(); 159 PdfDictionary acroForm = (PdfDictionary)PdfReader.getPdfObject(reader.getCatalog().get(PdfName.ACROFORM), reader.getCatalog()); 160 if (acroFields != null && acroFields.getXfa().isChanged()) { 161 markUsed(acroForm); 162 if (!flat) 163 acroFields.getXfa().setXfa(this); 164 } 165 if (sigFlags != 0) { 166 if (acroForm != null) { 167 acroForm.put(PdfName.SIGFLAGS, new PdfNumber(sigFlags)); 168 markUsed(acroForm); 169 } 170 } 171 closed = true; 172 addSharedObjectsToBody(); 173 setOutlines(); 174 setJavaScript(); 175 addFileAttachments(); 176 PdfDictionary catalog = reader.getCatalog(); 177 if (openAction != null) { 178 catalog.put(PdfName.OPENACTION, openAction); 179 } 180 byte[] altMetadata = xmpMetadata; 181 if (altMetadata == null) { 182 PdfObject xmpo = PdfReader.getPdfObject(catalog.get(PdfName.METADATA)); 183 if (xmpo != null && xmpo.isStream()) { 184 altMetadata = PdfReader.getStreamBytesRaw((PRStream)xmpo); 185 PdfReader.killIndirect(xmpo); 186 } 187 } 188 if (altMetadata != null) { 190 PdfStream xmp = new PdfStream(altMetadata); 191 xmp.put(PdfName.TYPE, PdfName.METADATA); 192 xmp.put(PdfName.SUBTYPE, PdfName.XML); 193 if (crypto != null && !crypto.isMetadataEncrypted()) { 194 PdfArray ar = new PdfArray(); 195 ar.add(PdfName.CRYPT); 196 xmp.put(PdfName.FILTER, ar); 197 } 198 catalog.put(PdfName.METADATA, body.add(xmp).getIndirectReference()); 199 markUsed(catalog); 200 } 201 PRIndirectReference iInfo = null; 202 try { 203 file.reOpen(); 204 alterContents(); 205 iInfo = (PRIndirectReference)reader.trailer.get(PdfName.INFO); 206 int skip = -1; 207 if (iInfo != null) 208 skip = iInfo.getNumber(); 209 int rootN = ((PRIndirectReference)reader.trailer.get(PdfName.ROOT)).getNumber(); 210 if (append) { 211 int keys[] = marked.getKeys(); 212 for (int k = 0; k < keys.length; ++k) { 213 int j = keys[k]; 214 PdfObject obj = reader.getPdfObjectRelease(j); 215 if (obj != null && skip != j && j < initialXrefSize) { 216 addToBody(obj, j, j != rootN); 217 } 218 } 219 for (int k = initialXrefSize; k < reader.getXrefSize(); ++k) { 220 PdfObject obj = reader.getPdfObject(k); 221 if (obj != null) { 222 addToBody(obj, getNewObjectNumber(reader, k, 0)); 223 } 224 } 225 } 226 else { 227 for (int k = 1; k < reader.getXrefSize(); ++k) { 228 PdfObject obj = reader.getPdfObjectRelease(k); 229 if (obj != null && skip != k) { 230 addToBody(obj, getNewObjectNumber(reader, k, 0), k != rootN); 231 } 232 } 233 } 234 } 235 finally { 236 try { 237 file.close(); 238 } 239 catch (Exception e) { 240 } 242 } 243 PdfIndirectReference encryption = null; 244 PdfObject fileID = null; 245 if (crypto != null) { 246 if (append) { 247 encryption = reader.getCryptoRef(); 248 } 249 else { 250 PdfIndirectObject encryptionObject = addToBody(crypto.getEncryptionDictionary(), false); 251 encryption = encryptionObject.getIndirectReference(); 252 } 253 fileID = crypto.getFileID(); 254 } 255 else 256 fileID = PdfEncryption.createInfoId(PdfEncryption.createDocumentId()); 257 PRIndirectReference iRoot = (PRIndirectReference)reader.trailer.get(PdfName.ROOT); 258 PdfIndirectReference root = new PdfIndirectReference(0, getNewObjectNumber(reader, iRoot.getNumber(), 0)); 259 PdfIndirectReference info = null; 260 PdfDictionary oldInfo = (PdfDictionary)PdfReader.getPdfObject(iInfo); 261 PdfDictionary newInfo = new PdfDictionary(); 262 if (oldInfo != null) { 263 for (Iterator i = oldInfo.getKeys().iterator(); i.hasNext();) { 264 PdfName key = (PdfName)i.next(); 265 PdfObject value = PdfReader.getPdfObject(oldInfo.get(key)); 266 newInfo.put(key, value); 267 } 268 } 269 if (moreInfo != null) { 270 for (Iterator i = moreInfo.entrySet().iterator(); i.hasNext();) { 271 Map.Entry entry = (Map.Entry ) i.next(); 272 String key = (String ) entry.getKey(); 273 PdfName keyName = new PdfName(key); 274 String value = (String ) entry.getValue(); 275 if (value == null) 276 newInfo.remove(keyName); 277 else 278 newInfo.put(keyName, new PdfString(value, PdfObject.TEXT_UNICODE)); 279 } 280 } 281 if (append) { 282 if (iInfo == null) 283 info = addToBody(newInfo, false).getIndirectReference(); 284 else 285 info = addToBody(newInfo, iInfo.getNumber(), false).getIndirectReference(); 286 } 287 else { 288 if (!newInfo.getKeys().isEmpty()) 289 info = addToBody(newInfo, false).getIndirectReference(); 290 } 291 body.writeCrossReferenceTable(os, root, info, encryption, fileID, prevxref); 293 if (fullCompression) { 294 os.write(getISOBytes("startxref\n")); 295 os.write(getISOBytes(String.valueOf(body.offset()))); 296 os.write(getISOBytes("\n%%EOF\n")); 297 } 298 else { 299 PdfTrailer trailer = new PdfTrailer(body.size(), 300 body.offset(), 301 root, 302 info, 303 encryption, 304 fileID, prevxref); 305 trailer.toPdf(this, os); 306 } 307 os.flush(); 308 if (isCloseStream()) 309 os.close(); 310 reader.close(); 311 } 312 313 void applyRotation(PdfDictionary pageN, ByteBuffer out) { 314 if (!rotateContents) 315 return; 316 Rectangle page = reader.getPageSizeWithRotation(pageN); 317 int rotation = page.getRotation(); 318 switch (rotation) { 319 case 90: 320 out.append(PdfContents.ROTATE90); 321 out.append(page.getTop()); 322 out.append(' ').append('0').append(PdfContents.ROTATEFINAL); 323 break; 324 case 180: 325 out.append(PdfContents.ROTATE180); 326 out.append(page.getRight()); 327 out.append(' '); 328 out.append(page.getTop()); 329 out.append(PdfContents.ROTATEFINAL); 330 break; 331 case 270: 332 out.append(PdfContents.ROTATE270); 333 out.append('0').append(' '); 334 out.append(page.getRight()); 335 out.append(PdfContents.ROTATEFINAL); 336 break; 337 } 338 } 339 340 void alterContents() throws IOException { 341 for (Iterator i = pagesToContent.values().iterator(); i.hasNext();) { 342 PageStamp ps = (PageStamp)i.next(); 343 PdfDictionary pageN = ps.pageN; 344 markUsed(pageN); 345 PdfArray ar = null; 346 PdfObject content = PdfReader.getPdfObject(pageN.get(PdfName.CONTENTS), pageN); 347 if (content == null) { 348 ar = new PdfArray(); 349 pageN.put(PdfName.CONTENTS, ar); 350 } 351 else if (content.isArray()) { 352 ar = (PdfArray)content; 353 markUsed(ar); 354 } 355 else if (content.isStream()) { 356 ar = new PdfArray(); 357 ar.add(pageN.get(PdfName.CONTENTS)); 358 pageN.put(PdfName.CONTENTS, ar); 359 } 360 else { 361 ar = new PdfArray(); 362 pageN.put(PdfName.CONTENTS, ar); 363 } 364 ByteBuffer out = new ByteBuffer(); 365 if (ps.under != null) { 366 out.append(PdfContents.SAVESTATE); 367 applyRotation(pageN, out); 368 out.append(ps.under.getInternalBuffer()); 369 out.append(PdfContents.RESTORESTATE); 370 } 371 if (ps.over != null) 372 out.append(PdfContents.SAVESTATE); 373 PdfStream stream = new PdfStream(out.toByteArray()); 374 try{stream.flateCompress();}catch(Exception e){throw new ExceptionConverter(e);} 375 ar.addFirst(addToBody(stream).getIndirectReference()); 376 out.reset(); 377 if (ps.over != null) { 378 out.append(' '); 379 out.append(PdfContents.RESTORESTATE); 380 out.append(PdfContents.SAVESTATE); 381 applyRotation(pageN, out); 382 out.append(ps.over.getInternalBuffer()); 383 out.append(PdfContents.RESTORESTATE); 384 stream = new PdfStream(out.toByteArray()); 385 try{stream.flateCompress();}catch(Exception e){throw new ExceptionConverter(e);} 386 ar.add(addToBody(stream).getIndirectReference()); 387 } 388 alterResources(ps); 389 } 390 } 391 392 void alterResources(PageStamp ps) { 393 ps.pageN.put(PdfName.RESOURCES, ps.pageResources.getResources()); 394 } 395 396 protected int getNewObjectNumber(PdfReader reader, int number, int generation) { 397 IntHashtable ref = (IntHashtable)readers2intrefs.get(reader); 398 if (ref != null) { 399 int n = ref.get(number); 400 if (n == 0) { 401 n = getIndirectReferenceNumber(); 402 ref.put(number, n); 403 } 404 return n; 405 } 406 if (currentPdfReaderInstance == null) { 407 if (append && number < initialXrefSize) 408 return number; 409 int n = myXref.get(number); 410 if (n == 0) { 411 n = getIndirectReferenceNumber(); 412 myXref.put(number, n); 413 } 414 return n; 415 } 416 else 417 return currentPdfReaderInstance.getNewObjectNumber(number, generation); 418 } 419 420 RandomAccessFileOrArray getReaderFile(PdfReader reader) { 421 if (readers2intrefs.containsKey(reader)) { 422 RandomAccessFileOrArray raf = (RandomAccessFileOrArray)readers2file.get(reader); 423 if (raf != null) 424 return raf; 425 return reader.getSafeFile(); 426 } 427 if (currentPdfReaderInstance == null) 428 return file; 429 else 430 return currentPdfReaderInstance.getReaderFile(); 431 } 432 433 438 public void registerReader(PdfReader reader, boolean openFile) throws IOException { 439 if (readers2intrefs.containsKey(reader)) 440 return; 441 readers2intrefs.put(reader, new IntHashtable()); 442 if (openFile) { 443 RandomAccessFileOrArray raf = reader.getSafeFile(); 444 readers2file.put(reader, raf); 445 raf.reOpen(); 446 } 447 } 448 449 452 public void unRegisterReader(PdfReader reader) { 453 if (!readers2intrefs.containsKey(reader)) 454 return; 455 readers2intrefs.remove(reader); 456 RandomAccessFileOrArray raf = (RandomAccessFileOrArray)readers2file.get(reader); 457 if (raf == null) 458 return; 459 readers2file.remove(reader); 460 try{raf.close();}catch(Exception e){} 461 } 462 463 static void findAllObjects(PdfReader reader, PdfObject obj, IntHashtable hits) { 464 if (obj == null) 465 return; 466 switch (obj.type()) { 467 case PdfObject.INDIRECT: 468 PRIndirectReference iref = (PRIndirectReference)obj; 469 if (reader != iref.getReader()) 470 return; 471 if (hits.containsKey(iref.getNumber())) 472 return; 473 hits.put(iref.getNumber(), 1); 474 findAllObjects(reader, PdfReader.getPdfObject(obj), hits); 475 return; 476 case PdfObject.ARRAY: 477 ArrayList lst = ((PdfArray)obj).getArrayList(); 478 for (int k = 0; k < lst.size(); ++k) { 479 findAllObjects(reader, (PdfObject)lst.get(k), hits); 480 } 481 return; 482 case PdfObject.DICTIONARY: 483 case PdfObject.STREAM: 484 PdfDictionary dic = (PdfDictionary)obj; 485 for (Iterator it = dic.getKeys().iterator(); it.hasNext();) { 486 PdfName name = (PdfName)it.next(); 487 findAllObjects(reader, dic.get(name), hits); 488 } 489 return; 490 } 491 } 492 493 497 public void addComments(FdfReader fdf) throws IOException { 498 if (readers2intrefs.containsKey(fdf)) 499 return; 500 PdfDictionary catalog = fdf.getCatalog(); 501 catalog = (PdfDictionary)PdfReader.getPdfObject(catalog.get(PdfName.FDF)); 502 if (catalog == null) 503 return; 504 PdfArray annots = (PdfArray)PdfReader.getPdfObject(catalog.get(PdfName.ANNOTS)); 505 if (annots == null || annots.size() == 0) 506 return; 507 registerReader(fdf, false); 508 IntHashtable hits = new IntHashtable(); 509 HashMap irt = new HashMap (); 510 ArrayList an = new ArrayList (); 511 ArrayList ar = annots.getArrayList(); 512 for (int k = 0; k < ar.size(); ++k) { 513 PdfObject obj = (PdfObject)ar.get(k); 514 PdfDictionary annot = (PdfDictionary)PdfReader.getPdfObject(obj); 515 PdfNumber page = (PdfNumber)PdfReader.getPdfObject(annot.get(PdfName.PAGE)); 516 if (page == null || page.intValue() >= reader.getNumberOfPages()) 517 continue; 518 findAllObjects(fdf, obj, hits); 519 an.add(obj); 520 if (obj.type() == PdfObject.INDIRECT) { 521 PdfObject nm = PdfReader.getPdfObject(annot.get(PdfName.NM)); 522 if (nm != null && nm.type() == PdfObject.STRING) 523 irt.put(nm.toString(), obj); 524 } 525 } 526 int arhits[] = hits.getKeys(); 527 for (int k = 0; k < arhits.length; ++k) { 528 int n = arhits[k]; 529 PdfObject obj = fdf.getPdfObject(n); 530 if (obj.type() == PdfObject.DICTIONARY) { 531 PdfObject str = PdfReader.getPdfObject(((PdfDictionary)obj).get(PdfName.IRT)); 532 if (str != null && str.type() == PdfObject.STRING) { 533 PdfObject i = (PdfObject)irt.get(str.toString()); 534 if (i != null) { 535 PdfDictionary dic2 = new PdfDictionary(); 536 dic2.merge((PdfDictionary)obj); 537 dic2.put(PdfName.IRT, i); 538 obj = dic2; 539 } 540 } 541 } 542 addToBody(obj, getNewObjectNumber(fdf, n, 0)); 543 } 544 for (int k = 0; k < an.size(); ++k) { 545 PdfObject obj = (PdfObject)an.get(k); 546 PdfDictionary annot = (PdfDictionary)PdfReader.getPdfObject(obj); 547 PdfNumber page = (PdfNumber)PdfReader.getPdfObject(annot.get(PdfName.PAGE)); 548 PdfDictionary dic = reader.getPageN(page.intValue() + 1); 549 PdfArray annotsp = (PdfArray)PdfReader.getPdfObject(dic.get(PdfName.ANNOTS), dic); 550 if (annotsp == null) { 551 annotsp = new PdfArray(); 552 dic.put(PdfName.ANNOTS, annotsp); 553 markUsed(dic); 554 } 555 markUsed(annotsp); 556 annotsp.add(obj); 557 } 558 } 559 560 PageStamp getPageStamp(int pageNum) { 561 PdfDictionary pageN = reader.getPageN(pageNum); 562 PageStamp ps = (PageStamp)pagesToContent.get(pageN); 563 if (ps == null) { 564 ps = new PageStamp(this, reader, pageN); 565 pagesToContent.put(pageN, ps); 566 } 567 return ps; 568 } 569 570 PdfContentByte getUnderContent(int pageNum) { 571 if (pageNum < 1 || pageNum > reader.getNumberOfPages()) 572 return null; 573 PageStamp ps = getPageStamp(pageNum); 574 if (ps.under == null) 575 ps.under = new StampContent(this, ps); 576 return ps.under; 577 } 578 579 PdfContentByte getOverContent(int pageNum) { 580 if (pageNum < 1 || pageNum > reader.getNumberOfPages()) 581 return null; 582 PageStamp ps = getPageStamp(pageNum); 583 if (ps.over == null) 584 ps.over = new StampContent(this, ps); 585 return ps.over; 586 } 587 588 void correctAcroFieldPages(int page) { 589 if (acroFields == null) 590 return; 591 if (page > reader.getNumberOfPages()) 592 return; 593 HashMap fields = acroFields.getFields(); 594 for (Iterator it = fields.values().iterator(); it.hasNext();) { 595 AcroFields.Item item = (AcroFields.Item)it.next(); 596 ArrayList pages = item.page; 597 for (int k = 0; k < pages.size(); ++k) { 598 int p = ((Integer )pages.get(k)).intValue(); 599 if (p >= page) 600 pages.set(k, new Integer (p + 1)); 601 } 602 } 603 } 604 605 void insertPage(int pageNumber, Rectangle mediabox) { 606 Rectangle media = new Rectangle(mediabox); 607 int rotation = media.getRotation() % 360; 608 PdfDictionary page = new PdfDictionary(PdfName.PAGE); 609 PdfDictionary resources = new PdfDictionary(); 610 PdfArray procset = new PdfArray(); 611 procset.add(PdfName.PDF); 612 procset.add(PdfName.TEXT); 613 procset.add(PdfName.IMAGEB); 614 procset.add(PdfName.IMAGEC); 615 procset.add(PdfName.IMAGEI); 616 resources.put(PdfName.PROCSET, procset); 617 page.put(PdfName.RESOURCES, resources); 618 page.put(PdfName.ROTATE, new PdfNumber(rotation)); 619 page.put(PdfName.MEDIABOX, new PdfRectangle(media, rotation)); 620 PRIndirectReference pref = reader.addPdfObject(page); 621 PdfDictionary parent; 622 PRIndirectReference parentRef; 623 if (pageNumber > reader.getNumberOfPages()) { 624 PdfDictionary lastPage = reader.getPageNRelease(reader.getNumberOfPages()); 625 parentRef = (PRIndirectReference)lastPage.get(PdfName.PARENT); 626 parentRef = new PRIndirectReference(reader, parentRef.getNumber()); 627 parent = (PdfDictionary)PdfReader.getPdfObject(parentRef); 628 PdfArray kids = (PdfArray)PdfReader.getPdfObject(parent.get(PdfName.KIDS), parent); 629 kids.add(pref); 630 markUsed(kids); 631 reader.pageRefs.insertPage(pageNumber, pref); 632 } 633 else { 634 if (pageNumber < 1) 635 pageNumber = 1; 636 PdfDictionary firstPage = reader.getPageN(pageNumber); 637 PRIndirectReference firstPageRef = reader.getPageOrigRef(pageNumber); 638 reader.releasePage(pageNumber); 639 parentRef = (PRIndirectReference)firstPage.get(PdfName.PARENT); 640 parentRef = new PRIndirectReference(reader, parentRef.getNumber()); 641 parent = (PdfDictionary)PdfReader.getPdfObject(parentRef); 642 PdfArray kids = (PdfArray)PdfReader.getPdfObject(parent.get(PdfName.KIDS), parent); 643 ArrayList ar = kids.getArrayList(); 644 int len = ar.size(); 645 int num = firstPageRef.getNumber(); 646 for (int k = 0; k < len; ++k) { 647 PRIndirectReference cur = (PRIndirectReference)ar.get(k); 648 if (num == cur.getNumber()) { 649 ar.add(k, pref); 650 break; 651 } 652 } 653 if (len == ar.size()) 654 throw new RuntimeException ("Internal inconsistence."); 655 markUsed(kids); 656 reader.pageRefs.insertPage(pageNumber, pref); 657 correctAcroFieldPages(pageNumber); 658 } 659 page.put(PdfName.PARENT, parentRef); 660 while (parent != null) { 661 markUsed(parent); 662 PdfNumber count = (PdfNumber)PdfReader.getPdfObjectRelease(parent.get(PdfName.COUNT)); 663 parent.put(PdfName.COUNT, new PdfNumber(count.intValue() + 1)); 664 parent = (PdfDictionary)PdfReader.getPdfObject(parent.get(PdfName.PARENT)); 665 } 666 } 667 668 672 boolean isRotateContents() { 673 return this.rotateContents; 674 } 675 676 680 void setRotateContents(boolean rotateContents) { 681 this.rotateContents = rotateContents; 682 } 683 684 boolean isContentWritten() { 685 return body.size() > 1; 686 } 687 688 AcroFields getAcroFields() { 689 if (acroFields == null) { 690 acroFields = new AcroFields(reader, this); 691 } 692 return acroFields; 693 } 694 695 void setFormFlattening(boolean flat) { 696 this.flat = flat; 697 } 698 699 void setFreeTextFlattening(boolean flat) { 700 this.flatFreeText = flat; 701 } 702 703 boolean partialFormFlattening(String name) { 704 getAcroFields(); 705 if (acroFields.getXfa().isXfaPresent()) 706 throw new UnsupportedOperationException ("Partial form flattening is not supported with XFA forms."); 707 if (!acroFields.getFields().containsKey(name)) 708 return false; 709 partialFlattening.add(name); 710 return true; 711 } 712 713 void flatFields() { 714 if (append) 715 throw new IllegalArgumentException ("Field flattening is not supported in append mode."); 716 getAcroFields(); 717 HashMap fields = acroFields.getFields(); 718 if (fieldsAdded && partialFlattening.isEmpty()) { 719 for (Iterator i = fields.keySet().iterator(); i.hasNext();) { 720 partialFlattening.add(i.next()); 721 } 722 } 723 PdfDictionary acroForm = (PdfDictionary)PdfReader.getPdfObject(reader.getCatalog().get(PdfName.ACROFORM)); 724 ArrayList acroFds = null; 725 if (acroForm != null) { 726 PdfArray array = (PdfArray)PdfReader.getPdfObject(acroForm.get(PdfName.FIELDS), acroForm); 727 if (array != null) 728 acroFds = array.getArrayList(); 729 } 730 for (Iterator i = fields.entrySet().iterator(); i.hasNext();) { 731 Map.Entry entry = (Map.Entry ) i.next(); 732 String name = (String ) entry.getKey(); 733 if (!partialFlattening.isEmpty() && !partialFlattening.contains(name)) 734 continue; 735 AcroFields.Item item = (AcroFields.Item) entry.getValue(); 736 for (int k = 0; k < item.merged.size(); ++k) { 737 PdfDictionary merged = (PdfDictionary)item.merged.get(k); 738 PdfNumber ff = (PdfNumber)PdfReader.getPdfObject(merged.get(PdfName.F)); 739 int flags = 0; 740 if (ff != null) 741 flags = ff.intValue(); 742 int page = ((Integer )item.page.get(k)).intValue(); 743 PdfDictionary appDic = (PdfDictionary)PdfReader.getPdfObject(merged.get(PdfName.AP)); 744 if (appDic != null && (flags & PdfFormField.FLAGS_PRINT) != 0 && (flags & PdfFormField.FLAGS_HIDDEN) == 0) { 745 PdfObject obj = appDic.get(PdfName.N); 746 PdfAppearance app = null; 747 if (obj != null) { 748 PdfObject objReal = PdfReader.getPdfObject(obj); 749 if (obj instanceof PdfIndirectReference && !obj.isIndirect()) 750 app = new PdfAppearance((PdfIndirectReference)obj); 751 else if (objReal instanceof PdfStream) { 752 ((PdfDictionary)objReal).put(PdfName.SUBTYPE, PdfName.FORM); 753 app = new PdfAppearance((PdfIndirectReference)obj); 754 } 755 else { 756 if (objReal != null && objReal.isDictionary()) { 757 PdfName as = (PdfName)PdfReader.getPdfObject(merged.get(PdfName.AS)); 758 if (as != null) { 759 PdfIndirectReference iref = (PdfIndirectReference)((PdfDictionary)objReal).get(as); 760 if (iref != null) { 761 app = new PdfAppearance(iref); 762 if (iref.isIndirect()) { 763 objReal = PdfReader.getPdfObject(iref); 764 ((PdfDictionary)objReal).put(PdfName.SUBTYPE, PdfName.FORM); 765 } 766 } 767 } 768 } 769 } 770 } 771 if (app != null) { 772 Rectangle box = PdfReader.getNormalizedRectangle((PdfArray)PdfReader.getPdfObject(merged.get(PdfName.RECT))); 773 PdfContentByte cb = getOverContent(page); 774 cb.setLiteral("Q "); 775 cb.addTemplate(app, box.getLeft(), box.getBottom()); 776 cb.setLiteral("q "); 777 } 778 } 779 if (partialFlattening.isEmpty()) 780 continue; 781 PdfDictionary pageDic = reader.getPageN(page); 782 PdfArray annots = (PdfArray)PdfReader.getPdfObject(pageDic.get(PdfName.ANNOTS)); 783 if (annots == null) 784 continue; 785 ArrayList ar = annots.getArrayList(); 786 for (int idx = 0; idx < ar.size(); ++idx) { 787 PdfObject ran = (PdfObject)ar.get(idx); 788 if (!ran.isIndirect()) 789 continue; 790 PdfObject ran2 = (PdfObject)item.widget_refs.get(k); 791 if (!ran2.isIndirect()) 792 continue; 793 if (((PRIndirectReference)ran).getNumber() == ((PRIndirectReference)ran2).getNumber()) { 794 ar.remove(idx--); 795 PRIndirectReference wdref = (PRIndirectReference)ran2; 796 while (true) { 797 PdfDictionary wd = (PdfDictionary)PdfReader.getPdfObject(wdref); 798 PRIndirectReference parentRef = (PRIndirectReference)wd.get(PdfName.PARENT); 799 PdfReader.killIndirect(wdref); 800 if (parentRef == null) { for (int fr = 0; fr < acroFds.size(); ++fr) { 802 PdfObject h = (PdfObject)acroFds.get(fr); 803 if (h.isIndirect() && ((PRIndirectReference)h).getNumber() == wdref.getNumber()) { 804 acroFds.remove(fr); 805 --fr; 806 } 807 } 808 break; 809 } 810 PdfDictionary parent = (PdfDictionary)PdfReader.getPdfObject(parentRef); 811 PdfArray kids = (PdfArray)PdfReader.getPdfObject(parent.get(PdfName.KIDS)); 812 ArrayList kar = kids.getArrayList(); 813 for (int fr = 0; fr < kar.size(); ++fr) { 814 PdfObject h = (PdfObject)kar.get(fr); 815 if (h.isIndirect() && ((PRIndirectReference)h).getNumber() == wdref.getNumber()) { 816 kar.remove(fr); 817 --fr; 818 } 819 } 820 if (!kar.isEmpty()) 821 break; 822 wdref = parentRef; 823 } 824 } 825 } 826 if (ar.isEmpty()) { 827 PdfReader.killIndirect(pageDic.get(PdfName.ANNOTS)); 828 pageDic.remove(PdfName.ANNOTS); 829 } 830 } 831 } 832 if (!fieldsAdded && partialFlattening.isEmpty()) { 833 for (int page = 1; page <= reader.getNumberOfPages(); ++page) { 834 PdfDictionary pageDic = reader.getPageN(page); 835 PdfArray annots = (PdfArray)PdfReader.getPdfObject(pageDic.get(PdfName.ANNOTS)); 836 if (annots == null) 837 continue; 838 ArrayList ar = annots.getArrayList(); 839 for (int idx = 0; idx < ar.size(); ++idx) { 840 PdfObject annoto = PdfReader.getPdfObject((PdfObject)ar.get(idx)); 841 if ((annoto instanceof PdfIndirectReference) && !annoto.isIndirect()) 842 continue; 843 PdfDictionary annot = (PdfDictionary)annoto; 844 if (PdfName.WIDGET.equals(annot.get(PdfName.SUBTYPE))) { 845 ar.remove(idx); 846 --idx; 847 } 848 } 849 if (ar.isEmpty()) { 850 PdfReader.killIndirect(pageDic.get(PdfName.ANNOTS)); 851 pageDic.remove(PdfName.ANNOTS); 852 } 853 } 854 eliminateAcroformObjects(); 855 } 856 } 857 858 void eliminateAcroformObjects() { 859 PdfObject acro = reader.getCatalog().get(PdfName.ACROFORM); 860 if (acro == null) 861 return; 862 PdfDictionary acrodic = (PdfDictionary)PdfReader.getPdfObject(acro); 863 reader.killXref(acrodic.get(PdfName.XFA)); 864 acrodic.remove(PdfName.XFA); 865 PdfObject iFields = acrodic.get(PdfName.FIELDS); 866 if (iFields != null) { 867 PdfDictionary kids = new PdfDictionary(); 868 kids.put(PdfName.KIDS, iFields); 869 sweepKids(kids); 870 PdfReader.killIndirect(iFields); 871 acrodic.put(PdfName.FIELDS, new PdfArray()); 872 } 873 } 876 877 void sweepKids(PdfObject obj) { 878 PdfObject oo = PdfReader.killIndirect(obj); 879 if (oo == null || !oo.isDictionary()) 880 return; 881 PdfDictionary dic = (PdfDictionary)oo; 882 PdfArray kids = (PdfArray)PdfReader.killIndirect(dic.get(PdfName.KIDS)); 883 if (kids == null) 884 return; 885 ArrayList ar = kids.getArrayList(); 886 for (int k = 0; k < ar.size(); ++k) { 887 sweepKids((PdfObject)ar.get(k)); 888 } 889 } 890 891 private void flatFreeTextFields() 892 { 893 if (append) 894 throw new IllegalArgumentException ("FreeText flattening is not supported in append mode."); 895 896 for (int page = 1; page <= reader.getNumberOfPages(); ++page) 897 { 898 PdfDictionary pageDic = reader.getPageN(page); 899 PdfArray annots = (PdfArray)PdfReader.getPdfObject(pageDic.get(PdfName.ANNOTS)); 900 if (annots == null) 901 continue; 902 ArrayList ar = annots.getArrayList(); 903 for (int idx = 0; idx < ar.size(); ++idx) 904 { 905 PdfObject annoto = PdfReader.getPdfObject((PdfObject)ar.get(idx)); 906 if ((annoto instanceof PdfIndirectReference) && !annoto.isIndirect()) 907 continue; 908 909 PdfDictionary annDic = (PdfDictionary)annoto; 910 if (!((PdfName)annDic.get(PdfName.SUBTYPE)).equals(PdfName.FREETEXT)) 911 continue; 912 PdfNumber ff = (PdfNumber)PdfReader.getPdfObject(annDic.get(PdfName.F)); 913 int flags = (ff != null) ? ff.intValue() : 0; 914 915 if ( (flags & PdfFormField.FLAGS_PRINT) != 0 && (flags & PdfFormField.FLAGS_HIDDEN) == 0) 916 { 917 PdfObject obj1 = annDic.get(PdfName.AP); 918 if (obj1 == null) 919 continue; 920 PdfDictionary appDic = (obj1 instanceof PdfIndirectReference) ? 921 (PdfDictionary) PdfReader.getPdfObject(obj1) : (PdfDictionary) obj1; 922 PdfObject obj = appDic.get(PdfName.N); 923 PdfAppearance app = null; 924 PdfObject objReal = PdfReader.getPdfObject(obj); 925 926 if (obj instanceof PdfIndirectReference && !obj.isIndirect()) 927 app = new PdfAppearance((PdfIndirectReference)obj); 928 else if (objReal instanceof PdfStream) 929 { 930 ((PdfDictionary)objReal).put(PdfName.SUBTYPE, PdfName.FORM); 931 app = new PdfAppearance((PdfIndirectReference)obj); 932 } 933 else 934 { 935 if (objReal.isDictionary()) 936 { 937 PdfName as_p = (PdfName)PdfReader.getPdfObject(appDic.get(PdfName.AS)); 938 if (as_p != null) 939 { 940 PdfIndirectReference iref = (PdfIndirectReference)((PdfDictionary)objReal).get(as_p); 941 if (iref != null) 942 { 943 app = new PdfAppearance(iref); 944 if (iref.isIndirect()) 945 { 946 objReal = PdfReader.getPdfObject(iref); 947 ((PdfDictionary)objReal).put(PdfName.SUBTYPE, PdfName.FORM); 948 } 949 } 950 } 951 } 952 } 953 if (app != null) 954 { 955 Rectangle box = PdfReader.getNormalizedRectangle((PdfArray)PdfReader.getPdfObject(annDic.get(PdfName.RECT))); 956 PdfContentByte cb = getOverContent(page); 957 cb.setLiteral("Q "); 958 cb.addTemplate(app, box.getLeft(), box.getBottom()); 959 cb.setLiteral("q "); 960 } 961 } 962 } 963 for (int idx = 0; idx < ar.size(); ++idx) 964 { 965 PdfObject annoto = PdfReader.getPdfObject((PdfObject)ar.get(idx)); 966 if (annoto != null && annoto.isDictionary()) 967 { 968 PdfDictionary annot = (PdfDictionary)annoto; 969 if (PdfName.FREETEXT.equals(annot.get(PdfName.SUBTYPE))) 970 { 971 ar.remove(idx); 972 --idx; 973 } 974 } 975 } 976 if (ar.isEmpty()) 977 { 978 PdfReader.killIndirect(pageDic.get(PdfName.ANNOTS)); 979 pageDic.remove(PdfName.ANNOTS); 980 } 981 } 982 } 983 984 987 public PdfIndirectReference getPageReference(int page) { 988 PdfIndirectReference ref = reader.getPageOrigRef(page); 989 if (ref == null) 990 throw new IllegalArgumentException ("Invalid page number " + page); 991 return ref; 992 } 993 994 997 public void addAnnotation(PdfAnnotation annot) { 998 throw new RuntimeException ("Unsupported in this context. Use PdfStamper.addAnnotation()"); 999 } 1000 1001 void addDocumentField(PdfIndirectReference ref) { 1002 PdfDictionary catalog = reader.getCatalog(); 1003 PdfDictionary acroForm = (PdfDictionary)PdfReader.getPdfObject(catalog.get(PdfName.ACROFORM), catalog); 1004 if (acroForm == null) { 1005 acroForm = new PdfDictionary(); 1006 catalog.put(PdfName.ACROFORM, acroForm); 1007 markUsed(catalog); 1008 } 1009 PdfArray fields = (PdfArray)PdfReader.getPdfObject(acroForm.get(PdfName.FIELDS), acroForm); 1010 if (fields == null) { 1011 fields = new PdfArray(); 1012 acroForm.put(PdfName.FIELDS, fields); 1013 markUsed(acroForm); 1014 } 1015 if (!acroForm.contains(PdfName.DA)) { 1016 acroForm.put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g ")); 1017 markUsed(acroForm); 1018 } 1019 fields.add(ref); 1020 markUsed(fields); 1021 } 1022 1023 void addFieldResources() throws IOException { 1024 if (fieldTemplates.isEmpty()) 1025 return; 1026 PdfDictionary catalog = reader.getCatalog(); 1027 PdfDictionary acroForm = (PdfDictionary)PdfReader.getPdfObject(catalog.get(PdfName.ACROFORM), catalog); 1028 if (acroForm == null) { 1029 acroForm = new PdfDictionary(); 1030 catalog.put(PdfName.ACROFORM, acroForm); 1031 markUsed(catalog); 1032 } 1033 PdfDictionary dr = (PdfDictionary)PdfReader.getPdfObject(acroForm.get(PdfName.DR), acroForm); 1034 if (dr == null) { 1035 dr = new PdfDictionary(); 1036 acroForm.put(PdfName.DR, dr); 1037 markUsed(acroForm); 1038 } 1039 markUsed(dr); 1040 for (Iterator it = fieldTemplates.keySet().iterator(); it.hasNext();) { 1041 PdfTemplate template = (PdfTemplate)it.next(); 1042 PdfFormField.mergeResources(dr, (PdfDictionary)template.getResources(), this); 1043 } 1044 if (dr.get(PdfName.ENCODING) == null) 1045 dr.put(PdfName.ENCODING, PdfName.WIN_ANSI_ENCODING); 1046 PdfDictionary fonts = (PdfDictionary)PdfReader.getPdfObject(dr.get(PdfName.FONT)); 1047 if (fonts == null) { 1048 fonts = new PdfDictionary(); 1049 dr.put(PdfName.FONT, fonts); 1050 } 1051 if (!fonts.contains(PdfName.HELV)) { 1052 PdfDictionary dic = new PdfDictionary(PdfName.FONT); 1053 dic.put(PdfName.BASEFONT, PdfName.HELVETICA); 1054 dic.put(PdfName.ENCODING, PdfName.WIN_ANSI_ENCODING); 1055 dic.put(PdfName.NAME, PdfName.HELV); 1056 dic.put(PdfName.SUBTYPE, PdfName.TYPE1); 1057 fonts.put(PdfName.HELV, addToBody(dic).getIndirectReference()); 1058 } 1059 if (!fonts.contains(PdfName.ZADB)) { 1060 PdfDictionary dic = new PdfDictionary(PdfName.FONT); 1061 dic.put(PdfName.BASEFONT, PdfName.ZAPFDINGBATS); 1062 dic.put(PdfName.NAME, PdfName.ZADB); 1063 dic.put(PdfName.SUBTYPE, PdfName.TYPE1); 1064 fonts.put(PdfName.ZADB, addToBody(dic).getIndirectReference()); 1065 } 1066 if (acroForm.get(PdfName.DA) == null) { 1067 acroForm.put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g ")); 1068 markUsed(acroForm); 1069 } 1070 } 1071 1072 void expandFields(PdfFormField field, ArrayList allAnnots) { 1073 allAnnots.add(field); 1074 ArrayList kids = field.getKids(); 1075 if (kids != null) { 1076 for (int k = 0; k < kids.size(); ++k) 1077 expandFields((PdfFormField)kids.get(k), allAnnots); 1078 } 1079 } 1080 1081 void addAnnotation(PdfAnnotation annot, PdfDictionary pageN) { 1082 try { 1083 ArrayList allAnnots = new ArrayList (); 1084 if (annot.isForm()) { 1085 fieldsAdded = true; 1086 getAcroFields(); 1087 PdfFormField field = (PdfFormField)annot; 1088 if (field.getParent() != null) 1089 return; 1090 expandFields(field, allAnnots); 1091 } 1092 else 1093 allAnnots.add(annot); 1094 for (int k = 0; k < allAnnots.size(); ++k) { 1095 annot = (PdfAnnotation)allAnnots.get(k); 1096 if (annot.getPlaceInPage() > 0) 1097 pageN = reader.getPageN(annot.getPlaceInPage()); 1098 if (annot.isForm()) { 1099 if (!annot.isUsed()) { 1100 HashMap templates = annot.getTemplates(); 1101 if (templates != null) 1102 fieldTemplates.putAll(templates); 1103 } 1104 PdfFormField field = (PdfFormField)annot; 1105 if (field.getParent() == null) 1106 addDocumentField(field.getIndirectReference()); 1107 } 1108 if (annot.isAnnotation()) { 1109 PdfObject pdfobj = PdfReader.getPdfObject(pageN.get(PdfName.ANNOTS), pageN); 1110 PdfArray annots = null; 1111 if (pdfobj == null || !pdfobj.isArray()) { 1112 annots = new PdfArray(); 1113 pageN.put(PdfName.ANNOTS, annots); 1114 markUsed(pageN); 1115 } 1116 else 1117 annots = (PdfArray)pdfobj; 1118 annots.add(annot.getIndirectReference()); 1119 markUsed(annots); 1120 if (!annot.isUsed()) { 1121 PdfRectangle rect = (PdfRectangle)annot.get(PdfName.RECT); 1122 if (rect != null && (rect.left() != 0 || rect.right() != 0 || rect.top() != 0 || rect.bottom() != 0)) { 1123 int rotation = reader.getPageRotation(pageN); 1124 Rectangle pageSize = reader.getPageSizeWithRotation(pageN); 1125 switch (rotation) { 1126 case 90: 1127 annot.put(PdfName.RECT, new PdfRectangle( 1128 pageSize.getTop() - rect.bottom(), 1129 rect.left(), 1130 pageSize.getTop() - rect.top(), 1131 rect.right())); 1132 break; 1133 case 180: 1134 annot.put(PdfName.RECT, new PdfRectangle( 1135 pageSize.getRight() - rect.left(), 1136 pageSize.getTop() - rect.bottom(), 1137 pageSize.getRight() - rect.right(), 1138 pageSize.getTop() - rect.top())); 1139 break; 1140 case 270: 1141 annot.put(PdfName.RECT, new PdfRectangle( 1142 rect.bottom(), 1143 pageSize.getRight() - rect.left(), 1144 rect.top(), 1145 pageSize.getRight() - rect.right())); 1146 break; 1147 } 1148 } 1149 } 1150 } 1151 if (!annot.isUsed()) { 1152 annot.setUsed(); 1153 addToBody(annot, annot.getIndirectReference()); 1154 } 1155 } 1156 } 1157 catch (IOException e) { 1158 throw new ExceptionConverter(e); 1159 } 1160 } 1161 1162 void addAnnotation(PdfAnnotation annot, int page) { 1163 addAnnotation(annot, reader.getPageN(page)); 1164 } 1165 1166 private void outlineTravel(PRIndirectReference outline) { 1167 while (outline != null) { 1168 PdfDictionary outlineR = (PdfDictionary)PdfReader.getPdfObjectRelease(outline); 1169 PRIndirectReference first = (PRIndirectReference)outlineR.get(PdfName.FIRST); 1170 if (first != null) { 1171 outlineTravel(first); 1172 } 1173 PdfReader.killIndirect(outlineR.get(PdfName.DEST)); 1174 PdfReader.killIndirect(outlineR.get(PdfName.A)); 1175 PdfReader.killIndirect(outline); 1176 outline = (PRIndirectReference)outlineR.get(PdfName.NEXT); 1177 } 1178 } 1179 1180 void deleteOutlines() { 1181 PdfDictionary catalog = reader.getCatalog(); 1182 PRIndirectReference outlines = (PRIndirectReference)catalog.get(PdfName.OUTLINES); 1183 if (outlines == null) 1184 return; 1185 outlineTravel(outlines); 1186 PdfReader.killIndirect(outlines); 1187 catalog.remove(PdfName.OUTLINES); 1188 markUsed(catalog); 1189 } 1190 1191 void setJavaScript() throws IOException { 1192 ArrayList djs = pdf.getDocumentJavaScript(); 1193 if (djs.isEmpty()) 1194 return; 1195 PdfDictionary catalog = reader.getCatalog(); 1196 PdfDictionary names = (PdfDictionary)PdfReader.getPdfObject(catalog.get(PdfName.NAMES), catalog); 1197 if (names == null) { 1198 names = new PdfDictionary(); 1199 catalog.put(PdfName.NAMES, names); 1200 markUsed(catalog); 1201 } 1202 markUsed(names); 1203 String s = String.valueOf(djs.size() - 1); 1204 int n = s.length(); 1205 String pad = "000000000000000"; 1206 HashMap maptree = new HashMap (); 1207 for (int k = 0; k < djs.size(); ++k) { 1208 s = String.valueOf(k); 1209 s = pad.substring(0, n - s.length()) + s; 1210 maptree.put(s, djs.get(k)); 1211 } 1212 PdfDictionary tree = PdfNameTree.writeTree(maptree, this); 1213 names.put(PdfName.JAVASCRIPT, addToBody(tree).getIndirectReference()); 1214 } 1215 1216 void addFileAttachments() throws IOException { 1217 HashMap fs = pdf.getDocumentFileAttachment(); 1218 if (fs.isEmpty()) 1219 return; 1220 PdfDictionary catalog = reader.getCatalog(); 1221 PdfDictionary names = (PdfDictionary)PdfReader.getPdfObject(catalog.get(PdfName.NAMES), catalog); 1222 if (names == null) { 1223 names = new PdfDictionary(); 1224 catalog.put(PdfName.NAMES, names); 1225 markUsed(catalog); 1226 } 1227 markUsed(names); 1228 HashMap old = PdfNameTree.readTree((PdfDictionary)PdfReader.getPdfObjectRelease(names.get(PdfName.EMBEDDEDFILES))); 1229 for (Iterator it = fs.entrySet().iterator(); it.hasNext();) { 1230 Map.Entry entry = (Map.Entry ) it.next(); 1231 String name = (String ) entry.getKey(); 1232 int k = 0; 1233 String nn = name; 1234 while (old.containsKey(nn)) { 1235 ++k; 1236 nn += " " + k; 1237 } 1238 old.put(nn, entry.getValue()); 1239 } 1240 PdfDictionary tree = PdfNameTree.writeTree(old, this); 1241 names.put(PdfName.EMBEDDEDFILES, addToBody(tree).getIndirectReference()); 1242 } 1243 1244 1248 void makePackage( PdfCollection collection ) { 1249 PdfDictionary catalog = reader.getCatalog(); 1250 catalog.put( PdfName.COLLECTION, collection ); 1251 } 1252 1253 void setOutlines() throws IOException { 1254 if (newBookmarks == null) 1255 return; 1256 deleteOutlines(); 1257 if (newBookmarks.isEmpty()) 1258 return; 1259 namedAsNames = (reader.getCatalog().get(PdfName.DESTS) != null); 1260 PdfDictionary top = new PdfDictionary(); 1261 PdfIndirectReference topRef = getPdfIndirectReference(); 1262 Object kids[] = SimpleBookmark.iterateOutlines(this, topRef, newBookmarks, namedAsNames); 1263 top.put(PdfName.FIRST, (PdfIndirectReference)kids[0]); 1264 top.put(PdfName.LAST, (PdfIndirectReference)kids[1]); 1265 top.put(PdfName.COUNT, new PdfNumber(((Integer )kids[2]).intValue())); 1266 addToBody(top, topRef); 1267 reader.getCatalog().put(PdfName.OUTLINES, topRef); 1268 markUsed(reader.getCatalog()); 1269 } 1270 1271 void setOutlines(List outlines) { 1272 newBookmarks = outlines; 1273 } 1274 1275 1280 public void setViewerPreferences(int preferences) { 1281 useVp = true; 1282 this.viewerPreferences.setViewerPreferences(preferences); 1283 } 1284 1285 1290 public void addViewerPreference(PdfName key, PdfObject value) { 1291 useVp = true; 1292 this.viewerPreferences.addViewerPreference(key, value); 1293 } 1294 1295 1299 public void setSigFlags(int f) { 1300 sigFlags |= f; 1301 } 1302 1303 1309 public void setPageAction(PdfName actionType, PdfAction action) throws PdfException { 1310 throw new UnsupportedOperationException ("Use setPageAction(PdfName actionType, PdfAction action, int page)"); 1311 } 1312 1313 1321 void setPageAction(PdfName actionType, PdfAction action, int page) throws PdfException { 1322 if (!actionType.equals(PAGE_OPEN) && !actionType.equals(PAGE_CLOSE)) 1323 throw new PdfException("Invalid page additional action type: " + actionType.toString()); 1324 PdfDictionary pg = reader.getPageN(page); 1325 PdfDictionary aa = (PdfDictionary)PdfReader.getPdfObject(pg.get(PdfName.AA), pg); 1326 if (aa == null) { 1327 aa = new PdfDictionary(); 1328 pg.put(PdfName.AA, aa); 1329 markUsed(pg); 1330 } 1331 aa.put(actionType, action); 1332 markUsed(aa); 1333 } 1334 1335 1339 public void setDuration(int seconds) { 1340 throw new UnsupportedOperationException ("Use setPageAction(PdfName actionType, PdfAction action, int page)"); 1341 } 1342 1343 1347 public void setTransition(PdfTransition transition) { 1348 throw new UnsupportedOperationException ("Use setPageAction(PdfName actionType, PdfAction action, int page)"); 1349 } 1350 1351 1356 void setDuration(int seconds, int page) { 1357 PdfDictionary pg = reader.getPageN(page); 1358 if (seconds < 0) 1359 pg.remove(PdfName.DUR); 1360 else 1361 pg.put(PdfName.DUR, new PdfNumber(seconds)); 1362 markUsed(pg); 1363 } 1364 1365 1370 void setTransition(PdfTransition transition, int page) { 1371 PdfDictionary pg = reader.getPageN(page); 1372 if (transition == null) 1373 pg.remove(PdfName.TRANS); 1374 else 1375 pg.put(PdfName.TRANS, transition.getTransitionDictionary()); 1376 markUsed(pg); 1377 } 1378 1379 protected void markUsed(PdfObject obj) { 1380 if (append && obj != null) { 1381 PRIndirectReference ref = null; 1382 if (obj.type() == PdfObject.INDIRECT) 1383 ref = (PRIndirectReference)obj; 1384 else 1385 ref = obj.getIndRef(); 1386 if (ref != null) 1387 marked.put(ref.getNumber(), 1); 1388 } 1389 } 1390 1391 protected void markUsed(int num) { 1392 if (append) 1393 marked.put(num, 1); 1394 } 1395 1396 1400 boolean isAppend() { 1401 return append; 1402 } 1403 1404 1414 public void setAdditionalAction(PdfName actionType, PdfAction action) throws PdfException { 1415 if (!(actionType.equals(DOCUMENT_CLOSE) || 1416 actionType.equals(WILL_SAVE) || 1417 actionType.equals(DID_SAVE) || 1418 actionType.equals(WILL_PRINT) || 1419 actionType.equals(DID_PRINT))) { 1420 throw new PdfException("Invalid additional action type: " + actionType.toString()); 1421 } 1422 PdfDictionary aa = (PdfDictionary)PdfReader.getPdfObject(reader.getCatalog().get(PdfName.AA)); 1423 if (aa == null) { 1424 if (action == null) 1425 return; 1426 aa = new PdfDictionary(); 1427 reader.getCatalog().put(PdfName.AA, aa); 1428 } 1429 markUsed(aa); 1430 if (action == null) 1431 aa.remove(actionType); 1432 else 1433 aa.put(actionType, action); 1434 } 1435 1436 1439 public void setOpenAction(PdfAction action) { 1440 openAction = action; 1441 } 1442 1443 1446 public void setOpenAction(String name) { 1447 throw new UnsupportedOperationException ("Open actions by name are not supported."); 1448 } 1449 1450 1453 public void setThumbnail(com.lowagie.text.Image image) { 1454 throw new UnsupportedOperationException ("Use PdfStamper.setThumbnail()."); 1455 } 1456 1457 void setThumbnail(Image image, int page) throws PdfException, DocumentException { 1458 PdfIndirectReference thumb = getImageReference(addDirectImageSimple(image)); 1459 reader.resetReleasePage(); 1460 PdfDictionary dic = reader.getPageN(page); 1461 dic.put(PdfName.THUMB, thumb); 1462 reader.resetReleasePage(); 1463 } 1464 1465 public PdfContentByte getDirectContentUnder() { 1466 throw new UnsupportedOperationException ("Use PdfStamper.getUnderContent() or PdfStamper.getOverContent()"); 1467 } 1468 1469 public PdfContentByte getDirectContent() { 1470 throw new UnsupportedOperationException ("Use PdfStamper.getUnderContent() or PdfStamper.getOverContent()"); 1471 } 1472 1473 static class PageStamp { 1474 1475 PdfDictionary pageN; 1476 StampContent under; 1477 StampContent over; 1478 PageResources pageResources; 1479 1480 PageStamp(PdfStamperImp stamper, PdfReader reader, PdfDictionary pageN) { 1481 this.pageN = pageN; 1482 pageResources = new PageResources(); 1483 PdfDictionary resources = (PdfDictionary)PdfReader.getPdfObject(pageN.get(PdfName.RESOURCES)); 1484 pageResources.setOriginalResources(resources, stamper.namePtr); 1485 } 1486 } 1487} 1488 | Popular Tags |