private LayoutTaggingHelper initTaggingHelperIfNeeded() { return defaultLayoutTaggingHelper == null && pdfDocument.isTagged() ? defaultLayoutTaggingHelper = new LayoutTaggingHelper(pdfDocument, immediateFlush) : defaultLayoutTaggingHelper; } }
private LayoutTaggingHelper initTaggingHelperIfNeeded() { return defaultLayoutTaggingHelper == null && pdfDocument.isTagged() ? defaultLayoutTaggingHelper = new LayoutTaggingHelper(pdfDocument, immediateFlush) : defaultLayoutTaggingHelper; } }
/** * Copies structure to a {@code destDocument}. * <br/><br/> * NOTE: Works only for {@code PdfStructTreeRoot} that is read from the document opened in reading mode, * otherwise an exception is thrown. * * @param destDocument document to copy structure to. Shall not be current document. * @param page2page association between original page and copied page. */ public static void copyTo(PdfDocument destDocument, Map<PdfPage, PdfPage> page2page, PdfDocument callingDocument) { if (!destDocument.isTagged()) return; copyTo(destDocument, page2page, callingDocument, false); }
/** * Copies structure to a {@code destDocument} and insert it in a specified position in the document. * <br/><br/> * NOTE: Works only for {@code PdfStructTreeRoot} that is read from the document opened in reading mode, * otherwise an exception is thrown. * <br/> * Also, to insert a tagged page into existing tag structure, existing tag structure shouldn't be flushed, otherwise * an exception may be raised. * * @param destDocument document to copy structure to. * @param insertBeforePage indicates where the structure to be inserted. * @param page2page association between original page and copied page. */ public static void copyTo(PdfDocument destDocument, int insertBeforePage, Map<PdfPage, PdfPage> page2page, PdfDocument callingDocument) { if (!destDocument.isTagged()) return; copyTo(destDocument, insertBeforePage, page2page, callingDocument, false); }
private static void copyTo(PdfDocument destDocument, int insertBeforePage, Map<PdfPage, PdfPage> page2page, PdfDocument callingDocument, boolean copyFromDestDocument) { if (!destDocument.isTagged()) return; int insertIndex = separateStructure(destDocument, insertBeforePage); //Opposite should never happened. if (insertIndex > 0) { copyTo(destDocument, page2page, callingDocument, copyFromDestDocument, insertIndex); } }
/** * Gets document {@code TagStructureContext}. * The document must be tagged, otherwise an exception will be thrown. * * @return document {@code TagStructureContext}. */ public TagStructureContext getTagStructureContext() { checkClosingStatus(); if (tagStructureContext == null) { if (!isTagged()) { throw new PdfException(PdfException.MustBeATaggedDocument); } initTagStructureContext(); } return tagStructureContext; }
/** * Do not use this constructor, instead use {@link PdfDocument#getTagStructureContext()} * method. * <br/><br/> * Creates {@code TagStructureContext} for document. There shall be only one instance of this * class per {@code PdfDocument}. * @param document the document which tag structure will be manipulated with this class. * @param tagStructureTargetVersion the version of the pdf standard to which the tag structure shall adhere. */ public TagStructureContext(PdfDocument document, PdfVersion tagStructureTargetVersion) { this.document = document; if (!document.isTagged()) { throw new PdfException(PdfException.MustBeATaggedDocument); } waitingTagsManager = new WaitingTagsManager(); namespaces = new LinkedHashSet<>(); nameToNamespace = new HashMap<>(); this.tagStructureTargetVersion = tagStructureTargetVersion; forbidUnknownRoles = true; if (targetTagStructureVersionIs2()) { initRegisteredNamespaces(); setNamespaceForNewTagsBasedOnExistingRoot(); } }
/** * Update XMP metadata values from {@link PdfDocumentInfo}. */ protected XMPMeta updateDefaultXmpMetadata() throws XMPException { XMPMeta xmpMeta = XMPMetaFactory.parseFromBuffer(getXmpMetadata(true)); XmpMetaInfoConverter.appendDocumentInfoToMetadata(info, xmpMeta); if (isTagged() && writer.properties.addUAXmpMetadata && !isXmpMetaHasProperty(xmpMeta, XMPConst.NS_PDFUA_ID, XMPConst.PART)) { xmpMeta.setPropertyInteger(XMPConst.NS_PDFUA_ID, XMPConst.PART, 1, new PropertyOptions(PropertyOptions.SEPARATE_NODE)); } return xmpMeta; }
/** * Calculates and returns next available MCID reference. * * @return calculated MCID reference. * @throws PdfException in case of not tagged document. */ public int getNextMcid() { if (!getDocument().isTagged()) { throw new PdfException(PdfException.MustBeATaggedDocument); } if (mcid == -1) { PdfStructTreeRoot structTreeRoot = getDocument().getStructTreeRoot(); mcid = structTreeRoot.getNextMcidForPage(this); } return mcid++; }
/** * This method merges pages from the source document to the current one. * <br><br> * If <i>closeSourceDocuments</i> flag is set to <i>true</i> (see {@link #setCloseSourceDocuments(boolean)}), * passed {@code PdfDocument} will be closed after pages are merged. * @param from - document, from which pages will be copied. * @param pages - List of numbers of pages which will be copied. * @return this {@code PdfMerger} instance. */ public PdfMerger merge(PdfDocument from, List<Integer> pages) { if (mergeTags && from.isTagged()) { pdfDocument.setTagged(); } if (mergeOutlines && from.hasOutlines()) { pdfDocument.initializeOutlines(); } from.copyPagesTo(pages, pdfDocument); if (closeSrcDocuments) { from.close(); } return this; }
private PdfDocument createPdfDocument(PageRange currentPageRange) { PdfDocument newDocument = new PdfDocument(getNextPdfWriter(currentPageRange), new DocumentProperties().setEventCountingMetaInfo(metaInfo)); if (pdfDocument.isTagged() && preserveTagged) newDocument.setTagged(); if (pdfDocument.hasOutlines() && preserveOutlines) newDocument.initializeOutlines(); return newDocument; }
private void addWidgetAnnotationToPage(PdfPage page, PdfAnnotation annot) { if (page.containsAnnotation(annot)) { return; } TagTreePointer tagPointer = null; boolean tagged = page.getDocument().isTagged(); if (tagged) { tagPointer = page.getDocument().getTagStructureContext().getAutoTaggingPointer(); //TODO attributes? tagPointer.addTag(StandardRoles.FORM); } page.addAnnotation(annot); if (tagged) { tagPointer.moveToParent(); } }
private void addWidgetAnnotationToPage(PdfPage page, PdfAnnotation annot) { if (page.containsAnnotation(annot)) { return; } TagTreePointer tagPointer = null; boolean tagged = page.getDocument().isTagged(); if (tagged) { tagPointer = page.getDocument().getTagStructureContext().getAutoTaggingPointer(); //TODO attributes? tagPointer.addTag(StandardRoles.FORM); } page.addAnnotation(annot); if (tagged) { tagPointer.moveToParent(); } }
protected void flushSingleRenderer(IRenderer resultRenderer) { Transform transformProp = resultRenderer.<Transform>getProperty(Property.TRANSFORM); if (!waitingDrawingElements.contains(resultRenderer)) { processWaitingDrawing(resultRenderer, transformProp, waitingDrawingElements); if (FloatingHelper.isRendererFloating(resultRenderer) || transformProp != null) return; } if (!resultRenderer.isFlushed() && null != resultRenderer.getOccupiedArea()) { // TODO Remove checking occupied area to be not null when DEVSIX-1001 is resolved. int pageNum = resultRenderer.getOccupiedArea().getPageNumber(); PdfDocument pdfDocument = document.getPdfDocument(); ensureDocumentHasNPages(pageNum, null); PdfPage correspondingPage = pdfDocument.getPage(pageNum); if (correspondingPage.isFlushed()) { throw new PdfException(PdfException.CannotDrawElementsOnAlreadyFlushedPages); } boolean wrapOldContent = pdfDocument.getReader() != null && pdfDocument.getWriter() != null && correspondingPage.getContentStreamCount() > 0 && correspondingPage.getLastContentStream().getLength() > 0 && !wrappedContentPage.contains(pageNum) && pdfDocument.getNumberOfPages() >= pageNum; wrappedContentPage.add(pageNum); if (pdfDocument.isTagged()) { pdfDocument.getTagStructureContext().getAutoTaggingPointer().setPageForTagging(correspondingPage); } resultRenderer.draw(new DrawContext(pdfDocument, new PdfCanvas(correspondingPage, wrapOldContent), pdfDocument.isTagged())); } }
protected void flushSingleRenderer(IRenderer resultRenderer) { Transform transformProp = resultRenderer.<Transform>getProperty(Property.TRANSFORM); if (!waitingDrawingElements.contains(resultRenderer)) { processWaitingDrawing(resultRenderer, transformProp, waitingDrawingElements); if (FloatingHelper.isRendererFloating(resultRenderer) || transformProp != null) return; } if (!resultRenderer.isFlushed() && null != resultRenderer.getOccupiedArea()) { // TODO Remove checking occupied area to be not null when DEVSIX-1001 is resolved. int pageNum = resultRenderer.getOccupiedArea().getPageNumber(); PdfDocument pdfDocument = document.getPdfDocument(); ensureDocumentHasNPages(pageNum, null); PdfPage correspondingPage = pdfDocument.getPage(pageNum); if (correspondingPage.isFlushed()) { throw new PdfException(PdfException.CannotDrawElementsOnAlreadyFlushedPages); } boolean wrapOldContent = pdfDocument.getReader() != null && pdfDocument.getWriter() != null && correspondingPage.getContentStreamCount() > 0 && correspondingPage.getLastContentStream().getLength() > 0 && !wrappedContentPage.contains(pageNum) && pdfDocument.getNumberOfPages() >= pageNum; wrappedContentPage.add(pageNum); if (pdfDocument.isTagged()) { pdfDocument.getTagStructureContext().getAutoTaggingPointer().setPageForTagging(correspondingPage); } resultRenderer.draw(new DrawContext(pdfDocument, new PdfCanvas(correspondingPage, wrapOldContent), pdfDocument.isTagged())); } }
/** * Moves page to new place in same document with all it tag structure * * @param pageNumber number of Page that will be moved * @param insertBefore indicates before which page new one will be inserted to */ public void movePage(int pageNumber, int insertBefore) { checkClosingStatus(); if (insertBefore < 1 || insertBefore > getNumberOfPages() + 1) { throw new IndexOutOfBoundsException(MessageFormatUtil.format(PdfException.RequestedPageNumberIsOutOfBounds, insertBefore)); } PdfPage page = getPage(pageNumber); if (isTagged()) { getStructTreeRoot().move(page, insertBefore); getTagStructureContext().normalizeDocumentRootTag(); } PdfPage removedPage = catalog.getPageTree().removePage(pageNumber); if (insertBefore > pageNumber) { --insertBefore; } catalog.getPageTree().addPage(insertBefore, removedPage); }
protected PdfPage(PdfDocument pdfDocument, PageSize pageSize) { this((PdfDictionary) new PdfDictionary().makeIndirect(pdfDocument)); PdfStream contentStream = (PdfStream) new PdfStream().makeIndirect(pdfDocument); getPdfObject().put(PdfName.Contents, contentStream); getPdfObject().put(PdfName.Type, PdfName.Page); getPdfObject().put(PdfName.MediaBox, new PdfArray(pageSize)); getPdfObject().put(PdfName.TrimBox, new PdfArray(pageSize)); if (pdfDocument.isTagged()) { setTabOrder(PdfName.S); } }
@Override protected PdfDictionary getFontDescriptor(String fontName) { if (fontName != null && fontName.length() > 0) { PdfDictionary fontDescriptor = new PdfDictionary(); makeObjectIndirect(fontDescriptor); fontDescriptor.put(PdfName.Type, PdfName.FontDescriptor); FontMetrics fontMetrics = fontProgram.getFontMetrics(); fontDescriptor.put(PdfName.CapHeight, new PdfNumber(fontMetrics.getCapHeight())); fontDescriptor.put(PdfName.ItalicAngle, new PdfNumber(fontMetrics.getItalicAngle())); FontNames fontNames = fontProgram.getFontNames(); fontDescriptor.put(PdfName.FontWeight, new PdfNumber(fontNames.getFontWeight())); fontDescriptor.put(PdfName.FontName, new PdfName(fontName)); if (fontNames.getFamilyName() != null && fontNames.getFamilyName().length > 0 && fontNames.getFamilyName()[0].length >= 4) { fontDescriptor.put(PdfName.FontFamily, new PdfString(fontNames.getFamilyName()[0][3])); } int flags = fontProgram.getPdfFontFlags(); flags &= ~(FontDescriptorFlags.Symbolic | FontDescriptorFlags.Nonsymbolic); // reset both flags flags |= fontEncoding.isFontSpecific() ? // set based on font encoding FontDescriptorFlags.Symbolic : FontDescriptorFlags.Nonsymbolic; fontDescriptor.put(PdfName.Flags, new PdfNumber(flags)); return fontDescriptor; } else if (getPdfObject().getIndirectReference() != null && getPdfObject().getIndirectReference().getDocument().isTagged()) { Logger logger = LoggerFactory.getLogger(PdfType3Font.class); logger.warn(LogMessageConstant.TYPE3_FONT_ISSUE_TAGGED_PDF); } return null; }
/** * Removes page from the document by page number. * * @param pageNum the one-based index of the PdfPage to be removed */ public void removePage(int pageNum) { checkClosingStatus(); PdfPage removedPage = catalog.getPageTree().removePage(pageNum); if (removedPage != null) { catalog.removeOutlines(removedPage); removeUnusedWidgetsFromFields(removedPage); if (isTagged()) { getTagStructureContext().removePageTags(removedPage); } // TODO should we remove everything (outlines, tags) if page won't be removed in the end, because it's already flushed? wouldn't tags be also flushed? if (!removedPage.getPdfObject().isFlushed()) { removedPage.getPdfObject().remove(PdfName.Parent); removedPage.getPdfObject().getIndirectReference().setFree(); } dispatchEvent(new PdfDocumentEvent(PdfDocumentEvent.REMOVE_PAGE, removedPage)); } }
if (getDocument().isTagged() && !getDocument().getStructTreeRoot().isFlushed()) { tryFlushPageTags();