package org.pdfclown.samples.cli; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.pdfclown.documents.Document; import org.pdfclown.documents.Page; import org.pdfclown.documents.Pages; import org.pdfclown.files.File; import org.pdfclown.objects.PdfReference; import org.pdfclown.tools.PageManager; /** This sample demonstrates how to manipulate the pages collection within a PDF document, to perform page data size calculations, additions, movements, removals, extractions and splits of groups of pages. @author Stefano Chizzolini (http://www.stefanochizzolini.it) @version 0.1.0 */ public class PageManagementSample extends Sample { private enum ActionEnum { PageDataSizeCalculation, PageAddition, PageMovement, PageRemoval, PageExtraction, DocumentMerge, DocumentBurst, DocumentSplitByPageIndex, DocumentSplitOnMaximumFileSize; public String getDescription( ) { StringBuilder builder = new StringBuilder(); for(char c : name().toCharArray()) { if(Character.isUpperCase(c) && builder.length() > 0) {builder.append(" ");} builder.append(c); } return builder.toString(); } } @Override public boolean run( ) { final String mainFilePath = promptPdfFileChoice("Please select a PDF file"); // Open the PDF file! final File mainFile; try {mainFile = new File(mainFilePath);} catch(Exception e) {throw new RuntimeException(mainFilePath + " file access error.",e);} final Document mainDocument = mainFile.getDocument(); final Pages mainPages = mainDocument.getPages(); final int mainPagesCount = mainPages.size(); final ActionEnum action = promptAction(); switch(action) { case PageDataSizeCalculation: { System.out.println("\nThis algorithm calculates the data size (expressed in bytes) of the selected document's pages."); System.out.println("Legend:"); System.out.println(" * full: page data size encompassing all its dependencies (like shared resources) -- this is the size of the page when extracted as a single-page document;"); System.out.println(" * differential: additional page data size -- this is the extra-content that's not shared with previous pages;"); System.out.println(" * incremental: data size of the page sublist encompassing all the previous pages and the current one.\n"); // Calculating the page data sizes... Set visitedReferences = new HashSet(); long incrementalDataSize = 0; for(Page page : mainPages) { long pageFullDataSize = PageManager.getSize(page); long pageDifferentialDataSize = PageManager.getSize(page, visitedReferences); incrementalDataSize += pageDifferentialDataSize; System.out.println( "Page " + (page.getIndex()+1) + ": " + pageFullDataSize + " (full); " + pageDifferentialDataSize + " (differential); " + incrementalDataSize + " (incremental)" ); } } break; case PageAddition: { // Source file. File sourceFile; { String sourceFilePath = promptPdfFileChoice("Select the source PDF file"); try {sourceFile = new File(sourceFilePath);} catch(Exception e) {throw new RuntimeException(sourceFilePath + " file access error.",e);} } // Source page collection. Pages sourcePages = sourceFile.getDocument().getPages(); // Source page count. int sourcePagesCount = sourcePages.size(); // First page to add. int fromSourcePageIndex = promptPageChoice("Select the start source page to add", sourcePagesCount); // Last page to add. int toSourcePageIndex = promptPageChoice("Select the end source page to add", fromSourcePageIndex + 1, sourcePagesCount) + 1; // Target position. int targetPageIndex = promptPageChoice("Select the position where to insert the source pages", mainPagesCount + 1); // Add the chosen page range to the main document! new PageManager(mainDocument).add( targetPageIndex, sourcePages.subList( fromSourcePageIndex, toSourcePageIndex ) ); // Serialize the main file! serialize(mainFile, action); } break; case PageMovement: { // First page to move. int fromSourcePageIndex = promptPageChoice("Select the start page to move", mainPagesCount); // Last page to move. int toSourcePageIndex = promptPageChoice("Select the end page to move", fromSourcePageIndex + 1, mainPagesCount) + 1; // Target position. int targetPageIndex = promptPageChoice("Select the position where to insert the pages", mainPagesCount + 1); // Move the chosen page range! new PageManager(mainDocument).move( fromSourcePageIndex, toSourcePageIndex, targetPageIndex ); // Serialize the main file! serialize(mainFile, action); } break; case PageRemoval: { // First page to remove. int fromPageIndex = promptPageChoice("Select the start page to remove", mainPagesCount); // Last page to remove. int toPageIndex = promptPageChoice("Select the end page to remove", fromPageIndex + 1, mainPagesCount) + 1; // Remove the chosen page range! new PageManager(mainDocument).remove( fromPageIndex, toPageIndex ); // Serialize the main file! serialize(mainFile, action); } break; case PageExtraction: { // First page to extract. int fromPageIndex = promptPageChoice("Select the start page", mainPagesCount); // Last page to extract. int toPageIndex = promptPageChoice("Select the end page", fromPageIndex + 1, mainPagesCount) + 1; // Extract the chosen page range! Document targetDocument = new PageManager(mainDocument).extract( fromPageIndex, toPageIndex ); // Serialize the target file! serialize(targetDocument.getFile(), action); } break; case DocumentMerge: { // Source file. File sourceFile; { String sourceFilePath = promptPdfFileChoice("Select the source PDF file"); try {sourceFile = new File(sourceFilePath);} catch(Exception e) {throw new RuntimeException(sourceFilePath + " file access error.",e);} } // Append the chosen source document to the main document! new PageManager(mainDocument).add(sourceFile.getDocument()); // Serialize the main file! serialize(mainFile, action); } break; case DocumentBurst: { // Split the document into single-page documents! List splitDocuments = new PageManager(mainDocument).split(); // Serialize the split files! int index = 0; for(Document splitDocument : splitDocuments) {serialize(splitDocument.getFile(), action, ++index, false);} } break; case DocumentSplitByPageIndex: { // Number of splits to apply to the source document. int splitCount; try {splitCount = Integer.parseInt(promptChoice("Number of split positions: "));} catch(Exception e) {splitCount = 0;} // Split positions within the source document. int[] splitIndexes = new int[splitCount]; { int prevSplitIndex = 0; for(int index = 0; index < splitCount; index++) { int splitIndex = promptPageChoice("Position " + (index + 1) + " of " + splitCount, prevSplitIndex + 1, mainPagesCount); splitIndexes[index] = splitIndex; prevSplitIndex = splitIndex; } } // Split the document at the chosen positions! List splitDocuments = new PageManager(mainDocument).split(splitIndexes); // Serialize the split files! int index = 0; for(Document splitDocument : splitDocuments) {serialize(splitDocument.getFile(), action, ++index, false);} } break; case DocumentSplitOnMaximumFileSize: { // Maximum file size. long maxDataSize; { long mainFileSize = new java.io.File(mainFilePath).length(); int kbMaxDataSize; do { try {kbMaxDataSize = Integer.parseInt(promptChoice("Max file size (KB): "));} catch(Exception e) {kbMaxDataSize = 0;} } while(kbMaxDataSize == 0); maxDataSize = kbMaxDataSize << 10; if(maxDataSize > mainFileSize) {maxDataSize = mainFileSize;} } // Split the document on maximum file size! List splitDocuments = new PageManager(mainDocument).split(maxDataSize); // Serialize the split files! int index = 0; for(Document splitDocument : splitDocuments) {serialize(splitDocument.getFile(), action, ++index, false);} } break; } return true; } private ActionEnum promptAction( ) { ActionEnum[] actions = ActionEnum.values(); Map options = new HashMap(); for(ActionEnum action : actions) {options.put(Integer.toString(action.ordinal()), action.getDescription());} try {return actions[Integer.parseInt(promptChoice(options))];} catch(Exception e) {return actions[0];} } /** Serializes the specified PDF file. @param file File to serialize. @param action Generator. */ private void serialize( File file, ActionEnum action ) {serialize(file, action, null, true);} /** Serializes the specified PDF file. @param file File to serialize. @param action Generator. @param index File index. @param chooseMode Whether to allow user choice of serialization mode. */ private void serialize( File file, ActionEnum action, Integer index, boolean chooseMode ) { serialize( file, getClass().getSimpleName() + "_" + action.name() + (index != null ? "." + index : ""), chooseMode ); } }