nz.ac.waikato.cms.doc.OverlayFilename.java Source code

Java tutorial

Introduction

Here is the source code for nz.ac.waikato.cms.doc.OverlayFilename.java

Source

/*
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * OverlayFilename.java
 * Copyright (C) 2015-2016 University of Waikato, Hamilton, NZ
 */

package nz.ac.waikato.cms.doc;

import com.itextpdf.text.Document;
import com.itextpdf.text.Element;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfWriter;
import net.sourceforge.argparse4j.ArgumentParsers;
import net.sourceforge.argparse4j.inf.ArgumentParser;
import net.sourceforge.argparse4j.inf.Namespace;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.List;

/**
 * Overlays the file name of the PDF on the pages.
 *
 * @author FracPete (fracpete at waikato dot ac dot nz)
 */
public class OverlayFilename {

    public static final String INPUT = "input";

    public static final String OUTPUT = "output";

    public static final String VPOS = "vpos";

    public static final String HPOS = "hpos";

    public static final String STRIPPATH = "strippath";

    public static final String STRIPEXT = "stripext";

    public static final String EVENPAGES = "event-pages";

    /**
     * For filtering PDF files in a directory.
     *
     * @author FracPete (fracpete at waikato dot ac dot nz)
     */
    public static class PdfFilenameFilter implements FilenameFilter {

        @Override
        public boolean accept(File dir, String name) {
            return name.toLowerCase().endsWith(".pdf");
        }
    }

    /**
     * Performs the overlay.
     *
     * @param input   the input file/dir
     * @param output   the output file/dir
     * @param vpos   the vertical position
     * @param hpos   the horizontal position
     * @param stripPath   whether to strip the path
     * @param stripExt   whether to strip the extension
     * @param pages   the array of pages (1-based) to add the overlay to, null for all
     * @param evenPages   whether to enforce even pages in the document
     * @return      true if successfully overlay
     */
    public boolean overlay(File input, File output, int vpos, int hpos, boolean stripPath, boolean stripExt,
            int[] pages, boolean evenPages) {
        PdfReader reader;
        PdfStamper stamper;
        FileOutputStream fos;
        PdfContentByte canvas;
        int i;
        String text;
        int numPages;
        File tmpFile;
        Document document;
        PdfWriter writer;
        PdfImportedPage page;
        PdfContentByte cb;

        reader = null;
        stamper = null;
        fos = null;
        numPages = -1;
        try {
            reader = new PdfReader(input.getAbsolutePath());
            fos = new FileOutputStream(output.getAbsolutePath());
            stamper = new PdfStamper(reader, fos);
            numPages = reader.getNumberOfPages();
            if (pages == null) {
                pages = new int[reader.getNumberOfPages()];
                for (i = 0; i < pages.length; i++)
                    pages[i] = i + 1;
            }

            if (stripPath)
                text = input.getName();
            else
                text = input.getAbsolutePath();
            if (stripExt)
                text = text.replaceFirst("\\.[pP][dD][fF]$", "");

            for (i = 0; i < pages.length; i++) {
                canvas = stamper.getOverContent(pages[i]);
                ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, new Paragraph(text), hpos, vpos, 0.0f);
            }
        } catch (Exception e) {
            System.err.println("Failed to process " + input + ":");
            e.printStackTrace();
            return false;
        } finally {
            try {
                if (stamper != null)
                    stamper.close();
            } catch (Exception e) {
                // ignored
            }
            try {
                if (reader != null)
                    reader.close();
            } catch (Exception e) {
                // ignored
            }
            try {
                if (fos != null) {
                    fos.flush();
                    fos.close();
                }
            } catch (Exception e) {
                // ignored
            }
        }

        // enforce even pages?
        if (evenPages && (numPages > 0) && (numPages % 2 == 1)) {
            reader = null;
            fos = null;
            writer = null;
            tmpFile = new File(output.getAbsolutePath() + "tmp");
            try {
                if (!output.renameTo(tmpFile)) {
                    System.err.println("Failed to rename '" + output + "' to '" + tmpFile + "'!");
                    return false;
                }
                reader = new PdfReader(tmpFile.getAbsolutePath());
                document = new Document(reader.getPageSize(1));
                fos = new FileOutputStream(output.getAbsoluteFile());
                writer = PdfWriter.getInstance(document, fos);
                document.open();
                document.addCreationDate();
                document.addAuthor(System.getProperty("user.name"));
                cb = writer.getDirectContent();
                for (i = 0; i < reader.getNumberOfPages(); i++) {
                    page = writer.getImportedPage(reader, i + 1);
                    document.newPage();
                    cb.addTemplate(page, 0, 0);
                }
                document.newPage();
                document.add(new Paragraph(" ")); // fake content
                document.close();
            } catch (Exception e) {
                System.err.println("Failed to process " + tmpFile + ":");
                e.printStackTrace();
                return false;
            } finally {
                try {
                    if (fos != null) {
                        fos.flush();
                        fos.close();
                    }
                } catch (Exception e) {
                    // ignored
                }
                try {
                    if (reader != null)
                        reader.close();
                } catch (Exception e) {
                    // ignored
                }
                try {
                    if (writer != null)
                        writer.close();
                } catch (Exception e) {
                    // ignored
                }
                if (tmpFile.exists()) {
                    try {
                        tmpFile.delete();
                    } catch (Exception e) {
                        // ignored
                    }
                }
            }
        }

        return true;
    }

    /**
     * Determines the input and output files and returns them as array (0=input, 1=output).
     *
     * @param input the input file/dir
     * @param output the output file/dir
     * @return the matched input/output files
     */
    public File[][] determineFiles(File input, File output) {
        File[][] result;
        List<File> files;
        int i;

        if (input.isFile()) {
            if (output.isFile()) {
                return new File[][] { new File[] { input }, new File[] { output } };
            } else {
                return new File[][] { new File[] { input },
                        new File[] { new File(output.getAbsolutePath() + File.separator + input.getName()) } };
            }
        }

        if (output.isFile())
            output = output.getParentFile();
        files = new ArrayList<>();
        for (String fname : input.list(new PdfFilenameFilter())) {
            files.add(new File(input.getAbsolutePath() + File.separator + fname));
        }
        result = new File[2][files.size()];
        for (i = 0; i < files.size(); i++) {
            result[0][i] = files.get(i);
            result[1][i] = new File(output.getAbsolutePath() + File.separator + files.get(i).getName());
        }

        return result;
    }

    /**
     * Expects the following arguments:
     * <ul>
     *   <li>input -- the input PDF file or dir with PDFs<li/>
     *   <li>output -- the output PDF file or dir if input is dir<li/>
     *   <li>[optional] --vpos {pos} -- the vertical position of the overlay<li/>
     *   <li>[optional] --hpos {pos} -- the horizontal position of the overlay<li/>
     *   <li>[optional] --strippath {true|false} -- whether to strip the path from the filename<li/>
     *   <li>[optional] --stripext {true|false} -- whether to strip the extension from the filename<li/>
     * </ul>
     * Use -h/--help to see full help.
     *
     * @param args   the commandline arguments
     * @throws Exception   if processing fails
     */
    public static void main(String[] args) throws Exception {
        ArgumentParser parser;

        parser = ArgumentParsers.newArgumentParser("OverlayFilename");
        parser.description("Overlays the filename of the PDF on the pages.");
        parser.addArgument(INPUT).metavar(INPUT).type(String.class)
                .help("The PDF file (or directory with PDFs) to add the filename overlay to.");
        parser.addArgument(OUTPUT).metavar(OUTPUT).type(String.class)
                .help("The file to save the modified PDF to (must be a directory if input is a directory).");
        parser.addArgument("--" + VPOS).metavar(VPOS).type(Integer.class).setDefault(10)
                .help("The vertical position of the overlay.");
        parser.addArgument("--" + HPOS).metavar(HPOS).type(Integer.class).setDefault(20)
                .help("The horizontal position of the overlay.");
        parser.addArgument("--" + STRIPPATH).metavar(STRIPPATH).type(Boolean.class).dest(STRIPPATH)
                .setDefault(false).help("Whether to strip the path from the filename.");
        parser.addArgument("--" + STRIPEXT).metavar(STRIPEXT).type(Boolean.class).dest(STRIPEXT).setDefault(false)
                .help("Whether to strip the extension from the filename.");
        parser.addArgument(EVENPAGES).metavar(EVENPAGES).type(Boolean.class).dest(EVENPAGES).setDefault(false)
                .help("Whether to enforce even pages in the document (simply adds an empty one).");

        Namespace namespace;
        try {
            namespace = parser.parseArgs(args);
        } catch (Exception e) {
            parser.printHelp();
            return;
        }

        OverlayFilename of = new OverlayFilename();

        File[][] files = of.determineFiles(new File(namespace.getString(INPUT)),
                new File(namespace.getString(OUTPUT)));

        for (int i = 0; i < files[0].length; i++) {
            System.out.println(files[0][i] + "\n--> " + files[1][i]);
            of.overlay(files[0][i], files[1][i], namespace.getInt(VPOS), namespace.getInt(HPOS),
                    namespace.getBoolean(STRIPPATH), namespace.getBoolean(STRIPEXT), null,
                    namespace.getBoolean(EVENPAGES));
        }
    }
}