package bd.amazed.docscissors.doc; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.logging.Level; import javax.swing.ProgressMonitor; import org.apache.commons.io.IOUtils; import org.rr.commons.log.LoggerFactory; import org.rr.commons.mufs.IResourceHandler; import org.rr.commons.mufs.ResourceHandlerFactory; import org.rr.jeborker.metadata.pdf.PDFUtils; import bd.amazed.docscissors.model.PageRectsMap; import com.itextpdf.text.Document; import com.itextpdf.text.DocumentException; import com.itextpdf.text.Rectangle; import com.itextpdf.text.pdf.PdfArray; import com.itextpdf.text.pdf.PdfCopy; import com.itextpdf.text.pdf.PdfDictionary; import com.itextpdf.text.pdf.PdfImportedPage; import com.itextpdf.text.pdf.PdfName; import com.itextpdf.text.pdf.PdfNumber; import com.itextpdf.text.pdf.PdfReader; import com.itextpdf.text.pdf.PdfStamper; /** * * @author Gagan */ class PdfCropper extends DocumentCropper { public PdfCropper(IResourceHandler file) { super(file); } private static com.itextpdf.text.Rectangle getMaxBoundingBox(PdfReader reader, int endPage) { com.itextpdf.text.Rectangle maxBoundingBox = new com.itextpdf.text.Rectangle(0, 0, 0, 0); for (int i = 1; i <= endPage; i++) { com.itextpdf.text.Rectangle boundingBox = reader.getPageSize(i); if (boundingBox.getWidth() > maxBoundingBox.getWidth()) maxBoundingBox.setRight(boundingBox.getWidth()); if (boundingBox.getHeight() > maxBoundingBox.getHeight()) maxBoundingBox.setBottom(boundingBox.getHeight()); } return maxBoundingBox; } @Override public void crop(DocumentInfo pdfFile, File targetFile, PageRectsMap pageRectsMap, int viewWidth, int viewHeight, ProgressMonitor progressMonitor) throws IOException, DocumentException { IResourceHandler originalFile = pdfFile.getOriginalFile(); HashMap<String, String> pdfInfo = pdfFile.getDocInfo(); PdfReader reader1 = PDFUtils.getReader(originalFile.toFile()); PdfReader reader2 = null; float normalizedPdfWidth = pdfFile.getNormalizedWidth(); float normalizedPdfHeight = pdfFile.getNormalizedHeight(); LoggerFactory.getLogger(PdfCropper.class).log(Level.INFO, "Finding ratio : viewSize " + viewWidth + "x" + viewHeight + ", pdf size " + normalizedPdfWidth + "x" + normalizedPdfHeight); double widthRatio = normalizedPdfWidth / viewWidth; double heightRatio = normalizedPdfHeight / viewHeight; if (widthRatio != heightRatio) { System.err.println("WARNING>>> RATION NOT SAME ?! " + widthRatio + " " + heightRatio); } Document document = null; PdfCopy writer = null; PdfStamper stamper = null; IResourceHandler tempFile = null; OutputStream tempFileOut = null; // TODO handle bookmarks // List bookmarks = SimpleBookmark.getBookmark(reader); // if (bookmarks != null) { // if (pageOffset != 0) { // SimpleBookmark.shiftPageNumbers(bookmarks, pageOffset, // null); // } // master.addAll(bookmarks); // } // open the original try { reader1.consolidateNamedDestinations(); int originalPageCount = reader1.getNumberOfPages(); document = new Document(reader1.getPageSizeWithRotation(1)); tempFile = ResourceHandlerFactory.getTemporaryResource("tmp"); writer = new PdfCopy(document, tempFileOut = tempFile.getContentOutputStream(false)); document.open(); PdfImportedPage page; int newPageCount = 0; for (int i = 0; i < originalPageCount;) { ++i; ArrayList<java.awt.Rectangle> cropRects = pageRectsMap.getRects(i); int cropCellCount = 0; if (cropRects != null) { cropCellCount = cropRects.size(); } if (cropCellCount == 0) { cropCellCount = 1; //we will assume there is one crop cell that covers the whole page } newPageCount += cropCellCount; for (int iCell = 0; iCell < cropCellCount; iCell++) { progressMonitor.setNote("Writing page " + ((i - 1) * cropCellCount + iCell) + " of " + newPageCount); progressMonitor.setProgress(i * 100 / originalPageCount); page = writer.getImportedPage(reader1, i); writer.addPage(page); } } document.close(); document = null; reader2 = PDFUtils.getReader(tempFile.toFile()); stamper = new PdfStamper(reader2, new FileOutputStream(targetFile)); int pageCount = reader2.getNumberOfPages(); newPageCount = 0; for (int iOriginalPage = 1; iOriginalPage <= originalPageCount; iOriginalPage++) { normalizedPdfHeight = (int) reader1.getPageSize(iOriginalPage).getHeight(); ArrayList<java.awt.Rectangle> cropRectsInIPDFCoords = pageRectsMap.getConvertedRectsForCropping(iOriginalPage, viewWidth, viewHeight, normalizedPdfWidth, normalizedPdfHeight); int cropCellCount = 0; if (cropRectsInIPDFCoords != null) { cropCellCount = cropRectsInIPDFCoords.size(); } if (cropCellCount == 0) { newPageCount++; // we will still add one full page LoggerFactory.getLogger(PdfCropper.class).log(Level.INFO, "Cropping page " + newPageCount + " ... full page size"); } else { for (int i = 0; i < cropCellCount;) { ++i; newPageCount++; // http://stackoverflow.com/questions/4089757/how-do-i-resize-an-existing-pdf-with-coldfusion-itext progressMonitor.setNote("Cropping page " + newPageCount + " of " + pageCount); progressMonitor.setProgress(newPageCount * 100 / pageCount); if (cropRectsInIPDFCoords != null) { java.awt.Rectangle cropRect = cropRectsInIPDFCoords.get(i - 1); applyCropToPage(reader2, newPageCount, cropRect); } } } } // put the information, like author name etc. stamper.setMoreInfo(pdfInfo); } finally { if (document != null) { document.close(); } if (stamper != null) { stamper.close(); } if (reader1 != null) { reader1.close(); } if (reader2 != null) { reader2.close(); } if(writer != null) { writer.flush(); writer.close(); } IOUtils.closeQuietly(tempFileOut); if (tempFile != null) { tempFile.delete(); } } } private void applyCropToPage(PdfReader reader, int page, java.awt.Rectangle cropRect) { PdfDictionary pdfDictionary = reader.getPageN(page); PdfArray cropCell = new PdfArray(); LoggerFactory.getLogger(PdfCropper.class).log(Level.INFO, "Cropping page " + page + " with " + cropRect); cropCell.add(new PdfNumber(cropRect.x));// lower left x cropCell.add(new PdfNumber(cropRect.y));// lower left y cropCell.add(new PdfNumber(cropRect.x + cropRect.width)); // up right x cropCell.add(new PdfNumber(cropRect.y + cropRect.height));// up righty pdfDictionary.put(PdfName.CROPBOX, cropCell); pdfDictionary.put(PdfName.MEDIABOX, cropCell); pdfDictionary.put(PdfName.TRIMBOX, cropCell); pdfDictionary.put(PdfName.BLEEDBOX, cropCell); } @Override public DocumentInfo getDocumentInfo() throws DocumentException, IOException { PdfReader reader = null; Document doc = null; try { reader = PDFUtils.getReader(mainFile.toFile()); int endPage = reader.getNumberOfPages(); Rectangle maxBoundingBox = getMaxBoundingBox(reader, endPage); // put the information, like author name etc. HashMap<String, String> info = reader.getInfo(); DocumentInfo docFile = new DocumentInfo(mainFile, mainFile, endPage); docFile.setDocInfo(info); docFile.setPageCount(endPage); docFile.setNormalizedWidth(Math.abs(maxBoundingBox.getWidth())); docFile.setNormalizedHeight(Math.abs(maxBoundingBox.getHeight())); return docFile; } finally { if (doc != null) { doc.close(); } if (reader != null) { reader.close(); } } } }