Return-Path: X-Original-To: apmail-pdfbox-commits-archive@www.apache.org Delivered-To: apmail-pdfbox-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 9C71511367 for ; Thu, 12 Jun 2014 18:32:10 +0000 (UTC) Received: (qmail 13551 invoked by uid 500); 12 Jun 2014 18:32:08 -0000 Delivered-To: apmail-pdfbox-commits-archive@pdfbox.apache.org Received: (qmail 13528 invoked by uid 500); 12 Jun 2014 18:32:08 -0000 Mailing-List: contact commits-help@pdfbox.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@pdfbox.apache.org Delivered-To: mailing list commits@pdfbox.apache.org Received: (qmail 13521 invoked by uid 99); 12 Jun 2014 18:32:08 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 12 Jun 2014 18:32:08 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED,T_FILL_THIS_FORM_SHORT X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 12 Jun 2014 18:32:06 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 53079238896F; Thu, 12 Jun 2014 18:31:41 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1602258 - in /pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox: OverlayPDF.java util/Overlay.java Date: Thu, 12 Jun 2014 18:31:41 -0000 To: commits@pdfbox.apache.org From: lehmi@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20140612183141.53079238896F@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: lehmi Date: Thu Jun 12 18:31:40 2014 New Revision: 1602258 URL: http://svn.apache.org/r1602258 Log: PDFBOX-1596: moved overlay implementation into its own class as proposed by James Green Added: pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/util/Overlay.java (with props) Modified: pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/OverlayPDF.java Modified: pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/OverlayPDF.java URL: http://svn.apache.org/viewvc/pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/OverlayPDF.java?rev=1602258&r1=1602257&r2=1602258&view=diff ============================================================================== --- pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/OverlayPDF.java (original) +++ pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/OverlayPDF.java Thu Jun 12 18:31:40 2014 @@ -16,35 +16,17 @@ */ package org.apache.pdfbox; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.pdfbox.cos.COSArray; -import org.apache.pdfbox.cos.COSBase; -import org.apache.pdfbox.cos.COSDictionary; -import org.apache.pdfbox.cos.COSInteger; -import org.apache.pdfbox.cos.COSName; -import org.apache.pdfbox.cos.COSObject; -import org.apache.pdfbox.cos.COSStream; -import org.apache.pdfbox.exceptions.COSVisitorException; -import org.apache.pdfbox.io.RandomAccessBuffer; import org.apache.pdfbox.pdfparser.BaseParser; -import org.apache.pdfbox.pdmodel.PDDocument; -import org.apache.pdfbox.pdmodel.PDDocumentCatalog; -import org.apache.pdfbox.pdmodel.PDPage; -import org.apache.pdfbox.pdmodel.PDResources; -import org.apache.pdfbox.pdmodel.common.PDRectangle; -import org.apache.pdfbox.util.MapUtil; +import org.apache.pdfbox.util.Overlay; +import org.apache.pdfbox.util.Overlay.Position; /** + * * Adds an overlay to an existing PDF document. * * Based on code contributed by Balazs Jerk. @@ -52,38 +34,8 @@ import org.apache.pdfbox.util.MapUtil; */ public class OverlayPDF { - /** - * Possible loacation of the overlayed pages: foreground or background. - */ - private enum Position - { - FOREGROUND, BACKGROUND - }; - private static final Log LOG = LogFactory.getLog(BaseParser.class); - private static final String XOBJECT_PREFIX = "OL"; - - private LayoutPage defaultOverlayPage; - private LayoutPage firstPageOverlayPage; - private LayoutPage lastPageOverlayPage; - private LayoutPage oddPageOverlayPage; - private LayoutPage evenPageOverlayPage; - - private static Map specificPageOverlay = new HashMap(); - private static Map specificPageOverlayPage = new HashMap(); - - private static Position overlayPosition = Position.BACKGROUND; - - private static boolean useNonSeqParser = false; - private static String inputFile = null; - private static String outputFile = null; - private static String defaultOverlayFile = null; - private static String firstPageOverlayFile = null; - private static String lastPageOverlayFile = null; - private static String oddPageOverlayFile = null; - private static String evenPageOverlayFile = null; - // Command line options private static final String POSITION = "-position"; private static final String ODD = "-odd"; @@ -98,33 +50,33 @@ public class OverlayPDF * * @param args command line arguments * @throws Exception if something went wrong - * @see #USAGE */ public static void main(final String[] args) throws Exception { + Overlay overlayer = new Overlay(); Map specificPageOverlayFile = new HashMap(); - + boolean useNonSeqParser = false; // input arguments for (int i = 0; i < args.length; i++) { String arg = args[i].trim(); if (i == 0) { - inputFile = arg; + overlayer.setInputFile(arg); } else if (i == (args.length - 1)) { - outputFile = arg; + overlayer.setOutputFile(arg); } else if (arg.equals(POSITION) && ((i + 1) < args.length)) { if (Position.FOREGROUND.toString().equalsIgnoreCase(args[i + 1].trim())) { - overlayPosition = Position.FOREGROUND; + overlayer.setOverlayPosition(Position.FOREGROUND); } else if (Position.BACKGROUND.toString().equalsIgnoreCase(args[i + 1].trim())) { - overlayPosition = Position.BACKGROUND; + overlayer.setOverlayPosition(Position.BACKGROUND); } else { @@ -134,22 +86,22 @@ public class OverlayPDF } else if (arg.equals(ODD) && ((i + 1) < args.length)) { - oddPageOverlayFile = args[i + 1].trim(); + overlayer.setOddPageOverlayFile(args[i + 1].trim()); i += 1; } else if (arg.equals(EVEN) && ((i + 1) < args.length)) { - evenPageOverlayFile = args[i + 1].trim(); + overlayer.setEvenPageOverlayFile(args[i + 1].trim()); i += 1; } else if (arg.equals(FIRST) && ((i + 1) < args.length)) { - firstPageOverlayFile = args[i + 1].trim(); + overlayer.setFirstPageOverlayFile(args[i + 1].trim()); i += 1; } else if (arg.equals(LAST) && ((i + 1) < args.length)) { - lastPageOverlayFile = args[i + 1].trim(); + overlayer.setLastPageOverlayFile(args[i + 1].trim()); i += 1; } else if (arg.equals(PAGE) && ((i + 2) < args.length) && (isInteger(args[i + 1].trim()))) @@ -161,9 +113,9 @@ public class OverlayPDF { useNonSeqParser = true; } - else if (defaultOverlayFile == null) + else if (overlayer.getDefaultOverlayFile() == null) { - defaultOverlayFile = arg; + overlayer.setDefaultOverlayFile(arg); } else { @@ -171,15 +123,14 @@ public class OverlayPDF } } - if ((inputFile == null) || (outputFile == null)) + if (overlayer.getInputFile() == null || overlayer.getOutputFile() == null) { usage(); } try { - OverlayPDF overlayer = new OverlayPDF(); - overlayer.overlay(specificPageOverlayFile); + overlayer.overlay(specificPageOverlayFile,useNonSeqParser); } catch (Exception e) { @@ -208,138 +159,6 @@ public class OverlayPDF System.exit( 1 ); } - /** - * This will add overlays to a documents. - * - * @param specificPageOverlayFile map of overlay files for specific pages - * @throws IOException exception - * @throws COSVisitorException exception - */ - public void overlay(Map specificPageOverlayFile) throws IOException, COSVisitorException - { - PDDocument sourcePDFDocument = null; - PDDocument defaultOverlay = null; - PDDocument firstPageOverlay = null; - PDDocument lastPageOverlay = null; - PDDocument oddPageOverlay = null; - PDDocument evenPageOverlay = null; - try - { - sourcePDFDocument = PDDocument.load(inputFile); - if (defaultOverlayFile != null) - { - if (useNonSeqParser) - { - defaultOverlay = PDDocument.loadNonSeq(new File(defaultOverlayFile), null); - } - else - { - defaultOverlay = PDDocument.load(defaultOverlayFile); - } - defaultOverlayPage = getLayoutPage(defaultOverlay); - } - if (firstPageOverlayFile != null) - { - if (useNonSeqParser) - { - firstPageOverlay = PDDocument.loadNonSeq(new File(firstPageOverlayFile), null); - } - else - { - firstPageOverlay = PDDocument.load(firstPageOverlayFile); - } - firstPageOverlayPage = getLayoutPage(firstPageOverlay); - } - if (lastPageOverlayFile != null) - { - if (useNonSeqParser) - { - lastPageOverlay = PDDocument.loadNonSeq(new File(lastPageOverlayFile), null); - } - else - { - lastPageOverlay = PDDocument.load(lastPageOverlayFile); - } - lastPageOverlayPage = getLayoutPage(lastPageOverlay); - } - if (oddPageOverlayFile != null) - { - if (useNonSeqParser) - { - oddPageOverlay = PDDocument.loadNonSeq(new File(oddPageOverlayFile), null); - } - else - { - oddPageOverlay = PDDocument.load(oddPageOverlayFile); - } - oddPageOverlayPage = getLayoutPage(oddPageOverlay); - } - if (evenPageOverlayFile != null) - { - if (useNonSeqParser) - { - evenPageOverlay = PDDocument.loadNonSeq(new File(evenPageOverlayFile), null); - } - else - { - evenPageOverlay = PDDocument.load(evenPageOverlayFile); - } - evenPageOverlayPage = getLayoutPage(evenPageOverlay); - } - for (Map.Entry e : specificPageOverlayFile.entrySet()) - { - PDDocument doc = null; - if (useNonSeqParser) - { - doc = PDDocument.loadNonSeq(new File(e.getValue()), null); - } - else - { - doc = PDDocument.load(e.getValue()); - } - specificPageOverlay.put(e.getKey(), doc); - specificPageOverlayPage.put(e.getKey(), getLayoutPage(doc)); - } - PDDocumentCatalog pdfCatalog = sourcePDFDocument.getDocumentCatalog(); - processPages(pdfCatalog.getAllPages()); - - sourcePDFDocument.save(outputFile); - } - finally - { - if (sourcePDFDocument != null) - { - sourcePDFDocument.close(); - } - if (defaultOverlay != null) - { - defaultOverlay.close(); - } - if (firstPageOverlay != null) - { - firstPageOverlay.close(); - } - if (lastPageOverlay != null) - { - lastPageOverlay.close(); - } - if (oddPageOverlay != null) - { - oddPageOverlay.close(); - } - if (evenPageOverlay != null) - { - evenPageOverlay.close(); - } - for (Map.Entry e : specificPageOverlay.entrySet()) - { - e.getValue().close(); - } - specificPageOverlay.clear(); - specificPageOverlayPage.clear(); - } - } - private static boolean isInteger(String str) { try @@ -353,236 +172,4 @@ public class OverlayPDF return true; } - /** - * Stores the overlay page information. - */ - private static class LayoutPage - { - private final PDRectangle overlayMediaBox; - private final COSStream overlayContentStream; - private final COSDictionary overlayResources; - - private LayoutPage(PDRectangle mediaBox, COSStream contentStream, COSDictionary resources) - { - overlayMediaBox = mediaBox; - overlayContentStream = contentStream; - overlayResources = resources; - } - } - - private LayoutPage getLayoutPage(PDDocument doc) throws IOException - { - PDDocumentCatalog catalog = doc.getDocumentCatalog(); - PDPage page = (PDPage)catalog.getAllPages().get(0); - COSBase contents = page.getCOSDictionary().getDictionaryObject(COSName.CONTENTS); - PDResources resources = page.findResources(); - if (resources == null) - { - resources = new PDResources(); - } - return new LayoutPage(page.getMediaBox(), createContentStream(contents), resources.getCOSDictionary()); - } - - private COSStream createContentStream(COSBase contents) throws IOException - { - List contentStreams = createContentStreamList(contents); - // concatenate streams - COSStream concatStream = new COSStream(new RandomAccessBuffer()); - OutputStream out = concatStream.createUnfilteredStream(); - for (COSStream contentStream : contentStreams) - { - InputStream in = contentStream.getUnfilteredStream(); - byte[] buf = new byte[2048]; - int n; - while ((n = in.read(buf)) > 0) - { - out.write(buf, 0, n); - } - out.flush(); - } - out.close(); - concatStream.setFilters(COSName.FLATE_DECODE); - return concatStream; - } - - private List createContentStreamList(COSBase contents) throws IOException - { - List contentStreams = new ArrayList(); - if (contents instanceof COSStream) - { - contentStreams.add((COSStream) contents); - } - else if (contents instanceof COSArray) - { - for (COSBase item : (COSArray) contents) - { - contentStreams.addAll(createContentStreamList(item)); - } - } - else if (contents instanceof COSObject) - { - contentStreams.addAll(createContentStreamList(((COSObject) contents).getObject())); - } - else - { - throw new IOException("Contents are unknown type:" + contents.getClass().getName()); - } - return contentStreams; - } - - private void processPages(List pages) throws IOException - { - int pageCount = 0; - for (Object pageObject : pages) - { - PDPage page = (PDPage) pageObject; - COSDictionary pageDictionary = page.getCOSDictionary(); - COSBase contents = pageDictionary.getDictionaryObject(COSName.CONTENTS); - COSArray contentArray = new COSArray(); - switch (overlayPosition) - { - case FOREGROUND: - // save state - contentArray.add(createStream("q\n")); - // original content - if (contents instanceof COSStream) - { - contentArray.add(contents); - } - else if (contents instanceof COSArray) - { - contentArray.addAll((COSArray) contents); - } - else - { - throw new IOException("Unknown content type:" + contents.getClass().getName()); - } - // restore state - contentArray.add(createStream("Q\n")); - // overlay content - overlayPage(contentArray, page, pageCount + 1, pages.size()); - break; - case BACKGROUND: - // overlay content - overlayPage(contentArray, page, pageCount + 1, pages.size()); - // original content - if (contents instanceof COSStream) - { - contentArray.add(contents); - } - else if (contents instanceof COSArray) - { - contentArray.addAll((COSArray) contents); - } - else - { - throw new IOException("Unknown content type:" + contents.getClass().getName()); - } - break; - default: - throw new IOException("Unknown type of position:" + overlayPosition); - } - pageDictionary.setItem(COSName.CONTENTS, contentArray); - pageCount++; - } - } - - private void overlayPage(COSArray array, PDPage page, int pageNumber, int numberOfPages) throws IOException - { - LayoutPage layoutPage = null; - if (specificPageOverlayPage.containsKey(pageNumber)) - { - layoutPage = specificPageOverlayPage.get(pageNumber); - } - else if ((pageNumber == 1) && (firstPageOverlayPage != null)) - { - layoutPage = firstPageOverlayPage; - } - else if ((pageNumber == numberOfPages) && (lastPageOverlayPage != null)) - { - layoutPage = lastPageOverlayPage; - } - else if ((pageNumber % 2 == 1) && (oddPageOverlayPage != null)) - { - layoutPage = oddPageOverlayPage; - } - else if ((pageNumber % 2 == 0) && (evenPageOverlayPage != null)) - { - layoutPage = evenPageOverlayPage; - } - else if (defaultOverlayPage != null) - { - layoutPage = defaultOverlayPage; - } - if (layoutPage != null) - { - PDResources resources = page.findResources(); - if (resources == null) - { - resources = new PDResources(); - page.setResources(resources); - } - String xObjectId = createOverlayXObject(page, layoutPage, layoutPage.overlayContentStream); - array.add(createOverlayStream(page, layoutPage, xObjectId)); - } - } - - private String createOverlayXObject(PDPage page, LayoutPage layoutPage, COSStream contentStream) - { - PDResources resources = page.findResources(); - // determine new ID - COSDictionary dict = (COSDictionary) resources.getCOSDictionary().getDictionaryObject(COSName.XOBJECT); - if (dict == null) - { - dict = new COSDictionary(); - resources.getCOSDictionary().setItem(COSName.XOBJECT, dict); - } - String xObjectId = MapUtil.getNextUniqueKey( resources.getXObjects(), XOBJECT_PREFIX ); - - // wrap the layout content in a BBox and add it to page - COSStream xobj = contentStream; - xobj.setItem(COSName.RESOURCES, layoutPage.overlayResources); - xobj.setItem(COSName.TYPE, COSName.XOBJECT); - xobj.setItem(COSName.SUBTYPE, COSName.FORM); - xobj.setInt(COSName.FORMTYPE, 1); - COSArray matrix = new COSArray(); - matrix.add(COSInteger.get(1)); - matrix.add(COSInteger.get(0)); - matrix.add(COSInteger.get(0)); - matrix.add(COSInteger.get(1)); - matrix.add(COSInteger.get(0)); - matrix.add(COSInteger.get(0)); - xobj.setItem(COSName.MATRIX, matrix); - COSArray bbox = new COSArray(); - bbox.add(COSInteger.get(0)); - bbox.add(COSInteger.get(0)); - bbox.add(COSInteger.get((int) layoutPage.overlayMediaBox.getWidth())); - bbox.add(COSInteger.get((int) layoutPage.overlayMediaBox.getHeight())); - xobj.setItem(COSName.BBOX, bbox); - dict.setItem(xObjectId, xobj); - - return xObjectId; - } - - private COSStream createOverlayStream(PDPage page, LayoutPage layoutPage, String xObjectId) throws IOException - { - // create a new content stream that executes the XObject content - PDRectangle pageMediaBox = page.getMediaBox(); - float scale = 1; - float hShift = (pageMediaBox.getWidth() - layoutPage.overlayMediaBox.getWidth()) / 2.0f; - float vShift = (pageMediaBox.getHeight() - layoutPage.overlayMediaBox.getHeight()) / 2.0f; - return createStream("q\nq " + scale + " 0 0 " + scale + " " + hShift + " " + vShift + " cm /" - + xObjectId + " Do Q\nQ\n"); - } - - private COSStream createStream(String content) throws IOException - { - COSStream stream = new COSStream(new RandomAccessBuffer()); - OutputStream out = stream.createUnfilteredStream(); - out.write(content.getBytes("ISO-8859-1")); - out.close(); - stream.setFilters(COSName.FLATE_DECODE); - return stream; - } - } Added: pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/util/Overlay.java URL: http://svn.apache.org/viewvc/pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/util/Overlay.java?rev=1602258&view=auto ============================================================================== --- pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/util/Overlay.java (added) +++ pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/util/Overlay.java Thu Jun 12 18:31:40 2014 @@ -0,0 +1,548 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.pdfbox.util; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.pdfbox.cos.COSArray; +import org.apache.pdfbox.cos.COSBase; +import org.apache.pdfbox.cos.COSDictionary; +import org.apache.pdfbox.cos.COSInteger; +import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.cos.COSObject; +import org.apache.pdfbox.cos.COSStream; +import org.apache.pdfbox.exceptions.COSVisitorException; +import org.apache.pdfbox.io.RandomAccessBuffer; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDDocumentCatalog; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDResources; +import org.apache.pdfbox.pdmodel.common.PDRectangle; + +/** + * Adds an overlay to an existing PDF document. + * + * Based on code contributed by Balazs Jerk. + * + */ +public class Overlay +{ + /** + * Possible loacation of the overlayed pages: foreground or background. + */ + public enum Position + { + FOREGROUND, BACKGROUND + }; + + private static final String XOBJECT_PREFIX = "OL"; + + private LayoutPage defaultOverlayPage; + private LayoutPage firstPageOverlayPage; + private LayoutPage lastPageOverlayPage; + private LayoutPage oddPageOverlayPage; + private LayoutPage evenPageOverlayPage; + + private Map specificPageOverlay = new HashMap(); + private Map specificPageOverlayPage = new HashMap(); + + private Position position = Position.BACKGROUND; + + private String inputFileName = null; + private String outputFilename = null; + private String defaultOverlayFilename = null; + private String firstPageOverlayFilename = null; + private String lastPageOverlayFilename = null; + private String oddPageOverlayFilename = null; + private String evenPageOverlayFilename = null; + + /** + * This will add overlays to a documents. + * + * @param specificPageOverlayFile map of overlay files for specific pages + * @param useNonSeqParser indicates whether the nonsequential parser is used + * @throws IOException if something went wrong + */ + public void overlay(Map specificPageOverlayFile, boolean useNonSeqParser) + throws IOException, COSVisitorException + { + PDDocument sourcePDFDocument = null; + PDDocument defaultOverlay = null; + PDDocument firstPageOverlay = null; + PDDocument lastPageOverlay = null; + PDDocument oddPageOverlay = null; + PDDocument evenPageOverlay = null; + try + { + sourcePDFDocument = PDDocument.load(inputFileName); + if (defaultOverlayFilename != null) + { + defaultOverlay = loadPDF(defaultOverlayFilename, useNonSeqParser); + defaultOverlayPage = getLayoutPage(defaultOverlay); + } + if (firstPageOverlayFilename != null) + { + firstPageOverlay = loadPDF(firstPageOverlayFilename, useNonSeqParser); + firstPageOverlayPage = getLayoutPage(firstPageOverlay); + } + if (lastPageOverlayFilename != null) + { + lastPageOverlay = loadPDF(lastPageOverlayFilename, useNonSeqParser); + lastPageOverlayPage = getLayoutPage(lastPageOverlay); + } + if (oddPageOverlayFilename != null) + { + oddPageOverlay = loadPDF(oddPageOverlayFilename, useNonSeqParser); + oddPageOverlayPage = getLayoutPage(oddPageOverlay); + } + if (evenPageOverlayFilename != null) + { + if (useNonSeqParser) + { + evenPageOverlay = PDDocument.loadNonSeq(new File(evenPageOverlayFilename), null); + } + else + { + evenPageOverlay = PDDocument.load(evenPageOverlayFilename); + } + evenPageOverlay = loadPDF(evenPageOverlayFilename, useNonSeqParser); + evenPageOverlayPage = getLayoutPage(evenPageOverlay); + } + for (Map.Entry e : specificPageOverlayFile.entrySet()) + { + PDDocument doc = loadPDF(e.getValue(), useNonSeqParser); + specificPageOverlay.put(e.getKey(), doc); + specificPageOverlayPage.put(e.getKey(), getLayoutPage(doc)); + } + PDDocumentCatalog pdfCatalog = sourcePDFDocument.getDocumentCatalog(); + processPages(pdfCatalog.getAllPages()); + + sourcePDFDocument.save(outputFilename); + } + finally + { + if (sourcePDFDocument != null) + { + sourcePDFDocument.close(); + } + if (defaultOverlay != null) + { + defaultOverlay.close(); + } + if (firstPageOverlay != null) + { + firstPageOverlay.close(); + } + if (lastPageOverlay != null) + { + lastPageOverlay.close(); + } + if (oddPageOverlay != null) + { + oddPageOverlay.close(); + } + if (evenPageOverlay != null) + { + evenPageOverlay.close(); + } + for (Map.Entry e : specificPageOverlay.entrySet()) + { + e.getValue().close(); + } + specificPageOverlay.clear(); + specificPageOverlayPage.clear(); + } + } + + private PDDocument loadPDF(String pdfName, boolean useNonSeqParser) throws IOException + { + PDDocument pdf = null; + if (useNonSeqParser) + { + pdf = PDDocument.loadNonSeq(new File(pdfName), null); + } + else + { + pdf = PDDocument.load(pdfName); + } + return pdf; + } + + /** + * Stores the overlay page information. + */ + private static class LayoutPage + { + private final PDRectangle overlayMediaBox; + private final COSStream overlayContentStream; + private final COSDictionary overlayResources; + + private LayoutPage(PDRectangle mediaBox, COSStream contentStream, COSDictionary resources) + { + overlayMediaBox = mediaBox; + overlayContentStream = contentStream; + overlayResources = resources; + } + } + + private LayoutPage getLayoutPage(PDDocument doc) throws IOException + { + PDDocumentCatalog catalog = doc.getDocumentCatalog(); + PDPage page = (PDPage) catalog.getAllPages().get(0); + COSBase contents = page.getCOSDictionary().getDictionaryObject(COSName.CONTENTS); + PDResources resources = page.findResources(); + if (resources == null) + { + resources = new PDResources(); + } + return new LayoutPage(page.getMediaBox(), createContentStream(contents), + resources.getCOSDictionary()); + } + + private COSStream createContentStream(COSBase contents) throws IOException + { + List contentStreams = createContentStreamList(contents); + // concatenate streams + COSStream concatStream = new COSStream(new RandomAccessBuffer()); + OutputStream out = concatStream.createUnfilteredStream(); + for (COSStream contentStream : contentStreams) + { + InputStream in = contentStream.getUnfilteredStream(); + byte[] buf = new byte[2048]; + int n; + while ((n = in.read(buf)) > 0) + { + out.write(buf, 0, n); + } + out.flush(); + } + out.close(); + concatStream.setFilters(COSName.FLATE_DECODE); + return concatStream; + } + + private List createContentStreamList(COSBase contents) throws IOException + { + List contentStreams = new ArrayList(); + if (contents instanceof COSStream) + { + contentStreams.add((COSStream) contents); + } + else if (contents instanceof COSArray) + { + for (COSBase item : (COSArray) contents) + { + contentStreams.addAll(createContentStreamList(item)); + } + } + else if (contents instanceof COSObject) + { + contentStreams.addAll(createContentStreamList(((COSObject) contents).getObject())); + } + else + { + throw new IOException("Contents are unknown type:" + contents.getClass().getName()); + } + return contentStreams; + } + + private void processPages(List pages) throws IOException + { + int pageCount = 0; + for (PDPage page : pages) + { + COSDictionary pageDictionary = page.getCOSDictionary(); + COSBase contents = pageDictionary.getDictionaryObject(COSName.CONTENTS); + COSArray contentArray = new COSArray(); + switch (position) + { + case FOREGROUND: + // save state + contentArray.add(createStream("q\n")); + // original content + if (contents instanceof COSStream) + { + contentArray.add(contents); + } + else if (contents instanceof COSArray) + { + contentArray.addAll((COSArray) contents); + } + else + { + throw new IOException("Unknown content type:" + contents.getClass().getName()); + } + // restore state + contentArray.add(createStream("Q\n")); + // overlay content + overlayPage(contentArray, page, pageCount + 1, pages.size()); + break; + case BACKGROUND: + // overlay content + overlayPage(contentArray, page, pageCount + 1, pages.size()); + // original content + if (contents instanceof COSStream) + { + contentArray.add(contents); + } + else if (contents instanceof COSArray) + { + contentArray.addAll((COSArray) contents); + } + else + { + throw new IOException("Unknown content type:" + contents.getClass().getName()); + } + break; + default: + throw new IOException("Unknown type of position:" + position); + } + pageDictionary.setItem(COSName.CONTENTS, contentArray); + pageCount++; + } + } + + private void overlayPage(COSArray array, PDPage page, int pageNumber, int numberOfPages) + throws IOException + { + LayoutPage layoutPage = null; + if (specificPageOverlayPage.containsKey(pageNumber)) + { + layoutPage = specificPageOverlayPage.get(pageNumber); + } + else if ((pageNumber == 1) && (firstPageOverlayPage != null)) + { + layoutPage = firstPageOverlayPage; + } + else if ((pageNumber == numberOfPages) && (lastPageOverlayPage != null)) + { + layoutPage = lastPageOverlayPage; + } + else if ((pageNumber % 2 == 1) && (oddPageOverlayPage != null)) + { + layoutPage = oddPageOverlayPage; + } + else if ((pageNumber % 2 == 0) && (evenPageOverlayPage != null)) + { + layoutPage = evenPageOverlayPage; + } + else if (defaultOverlayPage != null) + { + layoutPage = defaultOverlayPage; + } + if (layoutPage != null) + { + PDResources resources = page.findResources(); + if (resources == null) + { + resources = new PDResources(); + page.setResources(resources); + } + String xObjectId = createOverlayXObject(page, layoutPage, + layoutPage.overlayContentStream); + array.add(createOverlayStream(page, layoutPage, xObjectId)); + } + } + + private String createOverlayXObject(PDPage page, LayoutPage layoutPage, COSStream contentStream) + { + PDResources resources = page.findResources(); + // determine new ID + COSDictionary dict = (COSDictionary) resources.getCOSDictionary().getDictionaryObject( + COSName.XOBJECT); + if (dict == null) + { + dict = new COSDictionary(); + resources.getCOSDictionary().setItem(COSName.XOBJECT, dict); + } + String xObjectId = getNextUniqueKey(resources.getXObjects(), XOBJECT_PREFIX); + + // wrap the layout content in a BBox and add it to page + COSStream xobj = contentStream; + xobj.setItem(COSName.RESOURCES, layoutPage.overlayResources); + xobj.setItem(COSName.TYPE, COSName.XOBJECT); + xobj.setItem(COSName.SUBTYPE, COSName.FORM); + xobj.setInt(COSName.FORMTYPE, 1); + COSArray matrix = new COSArray(); + matrix.add(COSInteger.get(1)); + matrix.add(COSInteger.get(0)); + matrix.add(COSInteger.get(0)); + matrix.add(COSInteger.get(1)); + matrix.add(COSInteger.get(0)); + matrix.add(COSInteger.get(0)); + xobj.setItem(COSName.MATRIX, matrix); + COSArray bbox = new COSArray(); + bbox.add(COSInteger.get(0)); + bbox.add(COSInteger.get(0)); + bbox.add(COSInteger.get((int) layoutPage.overlayMediaBox.getWidth())); + bbox.add(COSInteger.get((int) layoutPage.overlayMediaBox.getHeight())); + xobj.setItem(COSName.BBOX, bbox); + dict.setItem(xObjectId, xobj); + + return xObjectId; + } + + private static String getNextUniqueKey(Map map, String prefix) + { + int counter = 0; + while (map != null && map.get(prefix + counter) != null) + { + counter++; + } + return prefix + counter; + } + + private COSStream createOverlayStream(PDPage page, LayoutPage layoutPage, String xObjectId) + throws IOException + { + // create a new content stream that executes the XObject content + PDRectangle pageMediaBox = page.getMediaBox(); + float scale = 1; + float hShift = (pageMediaBox.getWidth() - layoutPage.overlayMediaBox.getWidth()) / 2.0f; + float vShift = (pageMediaBox.getHeight() - layoutPage.overlayMediaBox.getHeight()) / 2.0f; + return createStream("q\nq " + scale + " 0 0 " + scale + " " + hShift + " " + vShift + + " cm /" + xObjectId + " Do Q\nQ\n"); + } + + private COSStream createStream(String content) throws IOException + { + COSStream stream = new COSStream(new RandomAccessBuffer()); + OutputStream out = stream.createUnfilteredStream(); + out.write(content.getBytes("ISO-8859-1")); + out.close(); + stream.setFilters(COSName.FLATE_DECODE); + return stream; + } + + /** + * Sets the overlay position. + * + * @param overlayPosition the overlay position + */ + public void setOverlayPosition(Position overlayPosition) + { + position = overlayPosition; + } + + /** + * Sets the file to be overlayed. + * + * @param inputFile the file to be overlayed + */ + public void setInputFile(String inputFile) + { + inputFileName = inputFile; + } + + /** + * Returns the input file. + * + * @return the input file + */ + public String getInputFile() + { + return inputFileName; + } + + /** + * Sets the output file. + * + * @param outputFile the output file + */ + public void setOutputFile(String outputFile) + { + outputFilename = outputFile; + } + + /** + * Returns the output file. + * + * @return the output file + */ + public String getOutputFile() + { + return outputFilename; + } + + /** + * Sets the default overlay file. + * + * @param defaultOverlayFile the default overlay file + */ + public void setDefaultOverlayFile(String defaultOverlayFile) + { + defaultOverlayFilename = defaultOverlayFile; + } + + /** + * Returns the default overlay file. + * + * @return the default overlay file + */ + public String getDefaultOverlayFile() + { + return defaultOverlayFilename; + } + + /** + * Sets the first page overlay file. + * + * @param firstPageOverlayFile the first page overlay file + */ + public void setFirstPageOverlayFile(String firstPageOverlayFile) + { + firstPageOverlayFilename = firstPageOverlayFile; + } + + /** + * Sets the last page overlay file. + * + * @param lastPageOverlayFile the last page overlay file + */ + public void setLastPageOverlayFile(String lastPageOverlayFile) + { + lastPageOverlayFilename = lastPageOverlayFile; + } + + /** + * Sets the odd page overlay file. + * + * @param oddPageOverlayFile the odd page overlay file + */ + public void setOddPageOverlayFile(String oddPageOverlayFile) + { + oddPageOverlayFilename = oddPageOverlayFile; + } + + /** + * Sets the even page overlay file. + * + * @param evenPageOverlayFile the even page overlay file + */ + public void setEvenPageOverlayFile(String evenPageOverlayFile) + { + evenPageOverlayFilename = evenPageOverlayFile; + } + +} Propchange: pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/util/Overlay.java ------------------------------------------------------------------------------ svn:eol-style = native