001/* 002 * TwoUpPDF 003 * a simple tool to format a PDF document's pages as 2Up pages that have been 004 * scaled/maximized for readablity when 2Up. 005 * 006 * $URL: svn://svn.webarts.bc.ca/open/trunk/projects/WebARTS/ca/bc/webarts/tools/pdf/TwoUpPDF.java $ 007 * $REVISION: $ 008 * Copyright (C) 2003 Tom Gutwin 009 * tgutwin@webarts.bc.ca 010 * 011 * 012 * This program is free software; you can redistribute it and/or 013 * modify it under the terms of the GNU General Public License 014 * as published by the Free Software Foundation; either version 2 015 * of the License, or any later version. 016 * 017 * This program is distributed in the hope that it will be useful, 018 * but WITHOUT ANY WARRANTY; without even the implied warranty of 019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 020 * GNU General Public License for more details. 021 * 022 * You should have received a copy of the GNU General Public License 023 * along with the jEdit program; if not, write to the Free Software 024 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 025 */ 026 027package ca.bc.webarts.tools.pdf; 028 029import ca.bc.webarts.tools.NativeAppLauncher; 030 031import com.itextpdf.text.*; 032import com.itextpdf.text.pdf.*; 033 034import java.io.*; 035 036 037/** 038 * A Utility class to perform specific manipulation to a PDF document. 039 * It Crops the pages a specified ammount and then places the pages in a 040 * Two Up format on a page.<br><br>It Can be called with a single 041 * parameter specifying the PDF file to manipulate.<br> or it can be called 042 * with two paramters: the 1st is the amount to crop off each page and the 043 * 2nd is the filename.<br> 044 * <br> 045 * Examples:<br> 046 * java ca.bc.webarts.tools.TwoUpPDF myFile.pdf<br> 047 * or<br> 048 * java ca.bc.webarts.tools.TwoUpPDF 0.75 myFile.pdf<br><br> 049 * If you need unequal cropping on each side of your page, use the 050 * ca.bc.webarts.tools.CropPDF class in this package. It provides additional 051 * functioanlity that can be used to create an intermidiate PDF file that 052 * can then be sent to this class fro Two Uping. 053 * <p><b>It does it all in Java (no native code calls) and its FREE!</b></p> 054 * <br>All PDF document handling is done using the freely available iText PDF 055 * Java library - 056 * <a href="http://www.lowagie.com/iText/">http://www.lowagie.com/iText/</a> 057 * <hr><br>License: GNU GPL<pre> 058 * This program is free software; you can redistribute it and/or modify it 059 * under the terms of the GNU General Public License as published by the Free 060 * Software Foundation; version 2 of the License. 061 * 062 * This program is distributed in the hope that it will be useful, but WITHOUT 063 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 064 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 065 * more details. 066 * 067 * You should have received a copy of the GNU General Public License along 068 * with this program; if not, write to the Free Software Foundation, Inc., 069 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.</pre> 070 * 071 * @author TGutwin 072 */ 073public class TwoUpPDF 074{ 075 076 /** Description of the Field */ 077 private static String outFileName_ = "2upOut.pdf"; 078 /** Description of the Field */ 079 private static String inFileName_ = "infile.pdf"; 080 /** Description of the Field */ 081 private static float cropBorder_ = 0.0f; 082 /** The amount to scale a page so it will fit 2Up on the page */ 083 private static float scale_ = (11.0f / 2.0f) / (8.5f - (2.0f * cropBorder_));//0.90f; 084 /** The offset amount to get it placed from the origin of the page.*/ 085 private static int offset_ = ((new Float(62.0f * cropBorder_)).intValue()); 086 /** Description of the Field */ 087 private static double rotation_ = Math.toRadians(0); 088 /** Description of the Field */ 089 private static Rectangle outputPageSize_ = PageSize.LETTER;//PageSize.A4; 090 /** Flags if acroreader is auto launched after this process. */ 091 private static boolean launchAcroread_ = false; 092 /** Flag for double sided printing binding offset on the long side of the page */ 093 private static boolean bindingOffset_ = false; 094 /** 095 * The amount to offset the long side of the page if a double sided print 096 * page offset is requested. (default is 0.75 inches) 097 **/ 098 private static float topOffsetAmount_ = ((new Float(62.0f * 0.5f)).intValue()); 099 private static String acroCmd_ = "/home/tgutwin/bin/acro"; 100 /** Description of the Field */ 101 private static String usage_ = "SYNTAX: TwoUpPDF [-bindingOffset] [pageCropBorderSize] PDFFilename\n" + 102 " where pageCropBorderSize is in inches"; 103 104 105 /** 106 * The main program for the TwoUpPDF class.<br>It Can be called with a single 107 * parameter specifying the PDF file to manipulate.<br> or it can be called 108 * with two paramters: the 1st is the amount to crop off each page and the 109 * 2nd is the filename.<br> 110 * <br> 111 * Examples:<br> 112 * java ca.bc.webarts.tools.TwoUpPDF myFile.pdf<br> 113 * or<br> 114 * java ca.bc.webarts.tools.TwoUpPDF 0.75 myFile.pdf<br> 115 * @param args The command line arguments 116 */ 117 public static void main(String[] args) 118 { 119 // Only the filename was spec'd 120 if (args.length == 1 && args[0].endsWith(".pdf")) 121 { 122 inFileName_ = args[0]; 123 outFileName_ = args[0].substring(0, args[0].length() - 4) + "-2Up.pdf"; 124 } 125 // Crop Border and the Filename 126 else if (args.length == 2 && 127 args[1].endsWith(".pdf")) 128 { 129 try 130 { 131 cropBorder_ = Float.parseFloat(args[0]); 132 offset_ = ((new Float(62.0f * cropBorder_)).intValue()); 133 inFileName_ = args[1]; 134 outFileName_ = args[1].substring(0, args[1].length() - 4) + "-2Up.pdf"; 135 } 136 catch (NumberFormatException numEx) 137 { 138 System.out.println("Page Border Crop Size error: "); 139 System.out.println(usage_); 140 System.exit(1); 141 } 142 } 143 // specify that a double sided printing binding is wanted. 144 else if (args.length == 3 && 145 args[2].endsWith(".pdf")) 146 { 147 try 148 { 149 bindingOffset_ = true; 150 cropBorder_ = Float.parseFloat(args[1]); 151 offset_ = ((new Float(62.0f * cropBorder_)).intValue()); 152 inFileName_ = args[2]; 153 outFileName_ = args[2].substring(0, args[2].length() - 4) + "-2Up.pdf"; 154 } 155 catch (NumberFormatException numEx) 156 { 157 System.out.println("Page Border Crop Size error: "); 158 System.out.println(usage_); 159 System.exit(1); 160 } 161 } 162 else 163 { 164 System.out.println("Filename error: "); 165 System.out.println(usage_); 166 System.exit(1); 167 } 168 169 try 170 { 171 // we create a reader for a certain document 172 System.out.println("Reading: " + inFileName_); 173 PdfReader reader = new PdfReader(inFileName_); 174 175 // we retrieve the total number of pages 176 int numPages = reader.getNumberOfPages(); 177 System.out.println("Preformating a " + numPages + 178 " page PDF file for 2Up display. (scale=" + scale_ + " offset=" + offset_ + ")"); 179 180 float width = outputPageSize_.getWidth(); 181 float height = outputPageSize_.getHeight(); 182 183 // step 1: creation of a document-object 184 Document document = 185 new Document( 186 new Rectangle(height, width), // these are reversed to get a landscape page 187 0, 0, 0, 20);// Margins: left, right,top, bottom 188 189 // step 2: we create a writer that listens to the document 190 System.out.println("Writing: " + outFileName_); 191 FileOutputStream outFileStream = new FileOutputStream(outFileName_); 192 PdfWriter writer = PdfWriter.getInstance(document, outFileStream); 193 194 // step 3: we open the document 195 document.open(); 196 197 // step 4: calculate the new scaling / layout postion 198 PdfContentByte cb = writer.getDirectContent(); 199 System.out.println("There are " + numPages + 200 " pages in the document."); 201 PdfImportedPage leftPage; 202 PdfImportedPage rightPage; 203 int currentPage = 0; 204 205 /* 206 * step 5: Start Copying the pages to the new Doc (in 2Up format) 207 */ 208 /* 209 * ******* ****************************************************** 210 */ 211 System.out.println("Page offset= -" +offset_); 212 boolean currentPageIsOffset = false; 213 while (currentPage < numPages) 214 { 215 document.newPage(); 216 leftPage = writer.getImportedPage(reader, ++currentPage); 217 // Calculate the Transfor parameters to use given the scale and postion 218 scale_ = (height / 2.0f) / (leftPage.getWidth() - (2.0f * cropBorder_)); 219 float cosRotation = (new Float(Math.cos(rotation_))).floatValue(); 220 float sinRotation = (new Float(Math.sin(rotation_))).floatValue(); 221 float a = scale_ * cosRotation; 222 float b = scale_ * sinRotation; 223 float c = -1.0f * scale_ * sinRotation; 224 float d = scale_ * cosRotation; 225 //System.out.println("a= " +a); 226 //System.out.println("b= " +b); 227 //System.out.println("c= " +c); 228 //System.out.println("d= " +d); 229 230 if (bindingOffset_ && currentPageIsOffset) 231 { 232 cb.addTemplate(leftPage, a, b, c, d, -offset_, 233 (topOffsetAmount_-offset_)); 234 } 235 else 236 { 237 cb.addTemplate(leftPage, a, b, c, d, -offset_, -offset_); 238 } 239 240 rightPage = null; 241 if (currentPage < numPages) 242 { 243 rightPage = writer.getImportedPage(reader, ++currentPage); 244 if (bindingOffset_ && currentPageIsOffset) 245 { 246 System.out.println("binding offset= -" +(offset_+topOffsetAmount_)); 247 cb.addTemplate(rightPage, a, b, c, d, (height / 2) - offset_, 248 (topOffsetAmount_-offset_)); 249 } 250 else 251 { 252 cb.addTemplate(rightPage, a, b, c, d, (height / 2) - offset_, -offset_); 253 } 254 } 255 currentPageIsOffset = !currentPageIsOffset; 256 257 // Draw a faint page seperator line between the 2Up pages 258 cb.setRGBColorStroke(200, 200, 2000); 259 cb.moveTo(height / 2, 0); 260 cb.lineTo(height / 2, width); 261 cb.stroke(); 262 } 263 264 // step 6: we close the document 265 document.close(); 266 267 // optional launch the acroreader 268 if (launchAcroread_) 269 { 270 System.out.println("Launching acroread " + outFileName_); 271 String[] appArgs = {(new File(outFileName_)).getAbsolutePath()}; 272 new NativeAppLauncher(acroCmd_, appArgs); 273 } 274 } 275 catch (Exception de) 276 { 277 de.printStackTrace(); 278 } 279 } 280} 281