Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package org.alfresco.extension.pdftoolkit.service;
- import java.io.File;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.Serializable;
- import java.io.StringWriter;
- import java.nio.charset.Charset;
- import java.security.KeyStore;
- import java.security.KeyStoreException;
- import java.security.NoSuchAlgorithmException;
- import java.security.PrivateKey;
- import java.security.UnrecoverableKeyException;
- import java.security.cert.Certificate;
- import java.security.cert.CertificateException;
- import java.util.ArrayList;
- import java.util.Date;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import java.util.StringTokenizer;
- import java.util.Vector;
- import javax.imageio.ImageIO;
- import org.alfresco.error.AlfrescoRuntimeException;
- import org.alfresco.extension.pdftoolkit.constants.PDFToolkitConstants;
- import org.alfresco.extension.pdftoolkit.model.PDFToolkitModel;
- import org.alfresco.model.ContentModel;
- import org.alfresco.repo.security.authentication.AuthenticationUtil;
- import org.alfresco.repo.template.FreeMarkerProcessor;
- import org.alfresco.repo.template.TemplateNode;
- import org.alfresco.service.ServiceRegistry;
- import org.alfresco.service.cmr.dictionary.DictionaryService;
- import org.alfresco.service.cmr.model.FileExistsException;
- import org.alfresco.service.cmr.model.FileFolderService;
- import org.alfresco.service.cmr.model.FileInfo;
- import org.alfresco.service.cmr.model.FileNotFoundException;
- import org.alfresco.service.cmr.repository.ContentIOException;
- import org.alfresco.service.cmr.repository.ContentReader;
- import org.alfresco.service.cmr.repository.ContentService;
- import org.alfresco.service.cmr.repository.ContentWriter;
- import org.alfresco.service.cmr.repository.NodeRef;
- import org.alfresco.service.cmr.repository.NodeService;
- import org.alfresco.service.cmr.security.AuthenticationService;
- import org.alfresco.service.cmr.security.PersonService;
- import org.alfresco.service.namespace.QName;
- import org.alfresco.util.TempFileProvider;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.apache.pdfbox.exceptions.COSVisitorException;
- import org.apache.pdfbox.pdmodel.PDDocument;
- import org.apache.pdfbox.util.PDFMergerUtility;
- import org.apache.pdfbox.util.Splitter;
- import com.itextpdf.text.Document;
- import com.itextpdf.text.DocumentException;
- import com.itextpdf.text.Image;
- import com.itextpdf.text.Rectangle;
- import com.itextpdf.text.pdf.BaseFont;
- import com.itextpdf.text.pdf.PdfContentByte;
- import com.itextpdf.text.pdf.PdfCopy;
- import com.itextpdf.text.pdf.PdfDictionary;
- import com.itextpdf.text.pdf.PdfName;
- import com.itextpdf.text.pdf.PdfNumber;
- import com.itextpdf.text.pdf.PdfReader;
- import com.itextpdf.text.pdf.PdfSignatureAppearance;
- import com.itextpdf.text.pdf.PdfStamper;
- import com.itextpdf.text.pdf.PdfWriter;
- import org.alfresco.service.cmr.version.Version;
- import org.alfresco.repo.version.VersionModel;
- import org.alfresco.service.cmr.version.VersionType;
- import org.alfresco.service.cmr.coci.CheckOutCheckInService;
- public class PDFToolkitServiceImpl extends PDFToolkitConstants implements PDFToolkitService
- {
- private ServiceRegistry serviceRegistry;
- private NodeService ns;
- private ContentService cs;
- private FileFolderService ffs;
- private DictionaryService ds;
- private PersonService ps;
- private AuthenticationService as;
- private FreeMarkerProcessor freemarkerProcessor = new FreeMarkerProcessor();
- private static Log logger = LogFactory.getLog(PDFToolkitServiceImpl.class);
- // do we need to apply the encryption aspect when we encrypt?
- private boolean useEncryptionAspect = true;
- // do we need to apply the signature aspect when we sign?
- private boolean useSignatureAspect = true;
- // when we create a new document, do we actually create a new one, or copy the source?
- private boolean createNew = false;
- protected CheckOutCheckInService checkOutCheckInService;
- Map<String, Serializable> versionProperties = new HashMap<String, Serializable>();
- @Override
- public NodeRef appendPDF(NodeRef targetNodeRef, Map<String, Serializable> params)
- {
- PDDocument pdf = null;
- PDDocument pdfTarget = null;
- InputStream is = null;
- InputStream tis = null;
- File tempDir = null;
- ContentWriter writer = null;
- NodeRef destinationNode = null;
- try
- {
- NodeRef toAppend = (NodeRef)params.get(PARAM_TARGET_NODE);
- Boolean inplace = true;
- ContentReader append = getReader(toAppend);
- is = append.getContentInputStream();
- ContentReader targetReader = getReader(targetNodeRef);
- tis = targetReader.getContentInputStream();
- String fileName = getFilename(params, targetNodeRef);
- // stream the document in
- pdf = PDDocument.load(is);
- pdfTarget = PDDocument.load(tis);
- // Append the PDFs
- PDFMergerUtility merger = new PDFMergerUtility();
- merger.appendDocument(pdfTarget, pdf);
- merger.setDestinationFileName(fileName);
- merger.mergeDocuments();
- // build a temp dir name based on the ID of the noderef we are
- // importing
- File alfTempDir = TempFileProvider.getTempDir();
- tempDir = new File(alfTempDir.getPath() + File.separatorChar + targetNodeRef.getId());
- tempDir.mkdir();
- pdfTarget.save(tempDir + "" + File.separatorChar + fileName);
- for (File file : tempDir.listFiles())
- {
- try
- {
- if (file.isFile())
- {
- // Get a writer and prep it for putting it back into the repo
- destinationNode = createDestinationNode(fileName,
- (NodeRef)params.get(PARAM_DESTINATION_FOLDER), targetNodeRef, inplace);
- writer = cs.getWriter(destinationNode, ContentModel.PROP_CONTENT, true);
- writer.setEncoding(targetReader.getEncoding()); // original
- // encoding
- writer.setMimetype(FILE_MIMETYPE);
- // Put it in the repo
- writer.putContent(file);
- // Clean up
- file.delete();
- }
- }
- catch (FileExistsException e)
- {
- throw new AlfrescoRuntimeException("Failed to process file.", e);
- }
- }
- }
- catch (COSVisitorException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- finally
- {
- if (pdf != null)
- {
- try
- {
- pdf.close();
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- }
- if (pdfTarget != null)
- {
- try
- {
- pdfTarget.close();
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- }
- if (is != null)
- {
- try
- {
- is.close();
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- }
- if (tempDir != null)
- {
- tempDir.delete();
- }
- }
- return destinationNode;
- }
- @Override
- public NodeRef encryptPDF(NodeRef targetNodeRef, Map<String, Serializable> params)
- {
- PdfStamper stamp = null;
- File tempDir = null;
- ContentWriter writer = null;
- ContentReader targetReader = null;
- NodeRef destinationNode = null;
- try
- {
- // get the parameters
- String userPassword = (String)params.get(PARAM_USER_PASSWORD);
- String ownerPassword = (String)params.get(PARAM_OWNER_PASSWORD);
- Boolean inplace = true;
- //int permissions = buildPermissionMask(params);
- int permissions = 0;
- int encryptionType = Integer.parseInt((String)params.get(PARAM_ENCRYPTION_LEVEL));
- // if metadata is excluded, alter encryption type
- /*if ((Boolean)params.get(PARAM_EXCLUDE_METADATA))
- {
- encryptionType = encryptionType | PdfWriter.DO_NOT_ENCRYPT_METADATA;
- }*/
- // get temp file
- File alfTempDir = TempFileProvider.getTempDir();
- tempDir = new File(alfTempDir.getPath() + File.separatorChar + targetNodeRef.getId());
- tempDir.mkdir();
- File file = new File(tempDir, ffs.getFileInfo(targetNodeRef).getName());
- // get the PDF input stream and create a reader for iText
- targetReader = getReader(targetNodeRef);
- PdfReader reader = new PdfReader(targetReader.getContentInputStream());
- stamp = new PdfStamper(reader, new FileOutputStream(file));
- // encrypt PDF
- stamp.setEncryption(userPassword.getBytes(Charset.forName("UTF-8")), ownerPassword.getBytes(Charset.forName("UTF-8")), permissions, encryptionType);
- stamp.close();
- String fileName = getFilename(params, targetNodeRef);
- // write out to destination
- destinationNode = createDestinationNode(fileName,
- (NodeRef)params.get(PARAM_DESTINATION_FOLDER), targetNodeRef, inplace);
- writer = cs.getWriter(destinationNode, ContentModel.PROP_CONTENT, true);
- writer.setEncoding(targetReader.getEncoding());
- writer.setMimetype(FILE_MIMETYPE);
- writer.putContent(file);
- file.delete();
- //if useAspect is true, store some additional info about the signature in the props
- if(useEncryptionAspect)
- {
- ns.addAspect(destinationNode, PDFToolkitModel.ASPECT_ENCRYPTED, new HashMap<QName, Serializable>());
- ns.setProperty(destinationNode, PDFToolkitModel.PROP_ENCRYPTIONDATE, new java.util.Date());
- ns.setProperty(destinationNode, PDFToolkitModel.PROP_ENCRYPTEDBY, AuthenticationUtil.getRunAsUser());
- }
- versionProperties.put(VersionModel.PROP_VERSION_TYPE, VersionType.MAJOR);
- versionProperties.put(Version.PROP_DESCRIPTION, "Document encrypted done.");
- NodeRef workingNode = checkOutCheckInService.checkout(destinationNode);
- checkOutCheckInService.checkin(workingNode, versionProperties);
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- catch (DocumentException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- finally
- {
- if (tempDir != null)
- {
- try
- {
- tempDir.delete();
- }
- catch (Exception ex)
- {
- throw new AlfrescoRuntimeException(ex.getMessage(), ex);
- }
- }
- if (stamp != null)
- {
- try
- {
- stamp.close();
- }
- catch (Exception ex)
- {
- throw new AlfrescoRuntimeException(ex.getMessage(), ex);
- }
- }
- }
- return destinationNode;
- }
- @Override
- public NodeRef decryptPDF(NodeRef targetNodeRef, Map<String, Serializable> params)
- {
- PdfStamper stamp = null;
- File tempDir = null;
- ContentWriter writer = null;
- ContentReader targetReader = null;
- NodeRef destinationNode = null;
- try
- {
- // get the parameters
- String ownerPassword = (String)params.get(PARAM_OWNER_PASSWORD);
- Boolean inplace = true;
- // get temp file
- File alfTempDir = TempFileProvider.getTempDir();
- tempDir = new File(alfTempDir.getPath() + File.separatorChar + targetNodeRef.getId());
- tempDir.mkdir();
- File file = new File(tempDir, ffs.getFileInfo(targetNodeRef).getName());
- // get the PDF input stream and create a reader for iText
- targetReader = getReader(targetNodeRef);
- PdfReader reader = new PdfReader(targetReader.getContentInputStream(), ownerPassword.getBytes());
- stamp = new PdfStamper(reader, new FileOutputStream(file));
- stamp.close();
- String fileName = getFilename(params, targetNodeRef);
- // write out to destination
- destinationNode = createDestinationNode(fileName,
- (NodeRef)params.get(PARAM_DESTINATION_FOLDER), targetNodeRef, inplace);
- writer = cs.getWriter(destinationNode, ContentModel.PROP_CONTENT, true);
- writer.setEncoding(targetReader.getEncoding());
- writer.setMimetype(FILE_MIMETYPE);
- writer.putContent(file);
- file.delete();
- //if useAspect is true, store some additional info about the signature in the props
- if(useEncryptionAspect)
- {
- ns.removeAspect(destinationNode, PDFToolkitModel.ASPECT_ENCRYPTED);
- }
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- catch (DocumentException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- finally
- {
- if (tempDir != null)
- {
- try
- {
- tempDir.delete();
- }
- catch (Exception ex)
- {
- throw new AlfrescoRuntimeException(ex.getMessage(), ex);
- }
- }
- if (stamp != null)
- {
- try
- {
- stamp.close();
- }
- catch (Exception ex)
- {
- throw new AlfrescoRuntimeException(ex.getMessage(), ex);
- }
- }
- }
- return destinationNode;
- }
- @Override
- public NodeRef signPDF(NodeRef targetNodeRef, Map<String, Serializable> params)
- {
- NodeRef privateKey = (NodeRef)params.get(PARAM_PRIVATE_KEY);
- String location = (String)params.get(PARAM_LOCATION);
- String position = (String)params.get(PARAM_POSITION);
- String reason = (String)params.get(PARAM_REASON);
- String visibility = (String)params.get(PARAM_VISIBILITY);
- String keyPassword = (String)params.get(PARAM_KEY_PASSWORD);
- String keyType = (String)params.get(PARAM_KEY_TYPE);
- int height = getInteger(params.get(PARAM_HEIGHT));
- int width = getInteger(params.get(PARAM_WIDTH));
- int pageNumber = getInteger(params.get(PARAM_PAGE));
- // By default, append the signature as a new PDF revision to avoid
- // invalidating any signatures that might already exist on the doc
- boolean appendToExisting = true;
- if (params.get(PARAM_NEW_REVISION) != null) {
- appendToExisting = Boolean.valueOf(String.valueOf(params.get(PARAM_NEW_REVISION)));
- }
- // New keystore parameters
- String alias = (String)params.get(PARAM_ALIAS);
- String storePassword = (String)params.get(PARAM_STORE_PASSWORD);
- int locationX = getInteger(params.get(PARAM_LOCATION_X));
- int locationY = getInteger(params.get(PARAM_LOCATION_Y));
- Boolean inplace = true;
- File tempDir = null;
- ContentWriter writer = null;
- KeyStore ks = null;
- NodeRef destinationNode = null;
- try
- {
- // get a keystore instance by
- if (keyType == null || keyType.equalsIgnoreCase(KEY_TYPE_DEFAULT))
- {
- ks = KeyStore.getInstance(KeyStore.getDefaultType());
- }
- else if (keyType.equalsIgnoreCase(KEY_TYPE_PKCS12))
- {
- ks = KeyStore.getInstance("pkcs12");
- }
- else
- {
- throw new AlfrescoRuntimeException("Unknown key type " + keyType + " specified");
- }
- // open the reader to the key and load it
- ContentReader keyReader = getReader(privateKey);
- ks.load(keyReader.getContentInputStream(), storePassword.toCharArray());
- // set alias
- // String alias = (String) ks.aliases().nextElement();
- PrivateKey key = (PrivateKey)ks.getKey(alias, keyPassword.toCharArray());
- Certificate[] chain = ks.getCertificateChain(alias);
- // open original pdf
- ContentReader pdfReader = getReader(targetNodeRef);
- PdfReader reader = new PdfReader(pdfReader.getContentInputStream());
- // If the page number is 0 because it couldn't be parsed or for
- // some other reason, set it to the first page, which is 1.
- // If the page number is negative, assume the intent is to "wrap".
- // For example, -1 would always be the last page.
- int numPages = reader.getNumberOfPages();
- if (pageNumber < 1 && pageNumber == 0) {
- pageNumber = 1; // use the first page
- } else {
- // page number is negative
- pageNumber = numPages + 1 + pageNumber;
- if (pageNumber <= 0) pageNumber = 1;
- }
- // if the page number specified is more than the num of pages,
- // use the last page
- if (pageNumber > numPages) {
- pageNumber = numPages;
- }
- // create temp dir to store file
- File alfTempDir = TempFileProvider.getTempDir();
- tempDir = new File(alfTempDir.getPath() + File.separatorChar + targetNodeRef.getId());
- tempDir.mkdir();
- File file = new File(tempDir, ffs.getFileInfo(targetNodeRef).getName());
- FileOutputStream fout = new FileOutputStream(file);
- // When adding a second signature, append must be called on PdfStamper.createSignature
- // to avoid invalidating previous signatures
- PdfStamper stamp = null;
- if (appendToExisting) {
- stamp = PdfStamper.createSignature(reader, fout, '\0', tempDir, true);
- } else {
- stamp = PdfStamper.createSignature(reader, fout, '\0');
- }
- PdfSignatureAppearance sap = stamp.getSignatureAppearance();
- sap.setCrypto(key, chain, null, PdfSignatureAppearance.WINCER_SIGNED);
- // set reason for signature and location of signer
- sap.setReason(reason);
- sap.setLocation(location);
- if (visibility.equalsIgnoreCase(VISIBILITY_VISIBLE))
- {
- //create the signature rectangle using either the provided position or
- //the exact coordinates, if provided
- if(position != null && !position.trim().equalsIgnoreCase("")
- && !position.trim().equalsIgnoreCase(POSITION_MANUAL))
- {
- Rectangle pageRect = reader.getPageSizeWithRotation(pageNumber);
- sap.setVisibleSignature(positionSignature(position, pageRect, width, height), pageNumber, null);
- }
- else
- {
- sap.setVisibleSignature(new Rectangle(locationX, locationY, locationX + width, locationY - height), pageNumber, null);
- }
- }
- stamp.close();
- String fileName = getFilename(params, targetNodeRef);
- destinationNode = createDestinationNode(fileName,
- (NodeRef)params.get(PARAM_DESTINATION_FOLDER), targetNodeRef, inplace);
- writer = cs.getWriter(destinationNode, ContentModel.PROP_CONTENT, true);
- writer.setEncoding(pdfReader.getEncoding());
- writer.setMimetype(FILE_MIMETYPE);
- writer.putContent(file);
- file.delete();
- //if useAspect is true, store some additional info about the signature in the props
- if(useSignatureAspect)
- {
- ns.addAspect(destinationNode, PDFToolkitModel.ASPECT_SIGNED, new HashMap<QName, Serializable>());
- ns.setProperty(destinationNode, PDFToolkitModel.PROP_REASON, reason);
- ns.setProperty(destinationNode, PDFToolkitModel.PROP_LOCATION, location);
- ns.setProperty(destinationNode, PDFToolkitModel.PROP_SIGNATUREDATE, new java.util.Date());
- ns.setProperty(destinationNode, PDFToolkitModel.PROP_SIGNEDBY, AuthenticationUtil.getRunAsUser());
- }
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- catch (KeyStoreException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- catch (ContentIOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- catch (NoSuchAlgorithmException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- catch (CertificateException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- catch (UnrecoverableKeyException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- catch (DocumentException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- finally
- {
- if (tempDir != null)
- {
- try
- {
- tempDir.delete();
- }
- catch (Exception ex)
- {
- throw new AlfrescoRuntimeException(ex.getMessage(), ex);
- }
- }
- }
- return destinationNode;
- }
- @Override
- public NodeRef watermarkPDF(NodeRef targetNodeRef, Map<String, Serializable> params)
- {
- NodeRef destinationNode = null;
- try
- {
- ContentReader targetReader = getReader(targetNodeRef);
- if (params.get(PARAM_WATERMARK_TYPE) != null
- && params.get(PARAM_WATERMARK_TYPE).equals(TYPE_IMAGE))
- {
- NodeRef watermarkNodeRef = (NodeRef)params.get(PARAM_WATERMARK_IMAGE);
- ContentReader watermarkContentReader = getReader(watermarkNodeRef);
- destinationNode = this.imageAction(params, targetNodeRef, watermarkNodeRef, targetReader, watermarkContentReader);
- }
- else if (params.get(PARAM_WATERMARK_TYPE) != null
- && params.get(PARAM_WATERMARK_TYPE).equals(TYPE_TEXT))
- {
- destinationNode = this.textAction(params, targetNodeRef, targetReader);
- }
- }
- catch (AlfrescoRuntimeException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- return destinationNode;
- }
- @Override
- public NodeRef splitPDF(NodeRef targetNodeRef, Map<String, Serializable> params)
- {
- PDDocument pdf = null;
- InputStream is = null;
- File tempDir = null;
- ContentWriter writer = null;
- NodeRef destinationFolder;
- try
- {
- destinationFolder = (NodeRef)params.get(PARAM_DESTINATION_FOLDER);
- ContentReader targetReader = getReader(targetNodeRef);
- // Get the split frequency
- int splitFrequency = 0;
- String splitFrequencyString = params.get(PARAM_SPLIT_FREQUENCY).toString();
- if (!splitFrequencyString.equals(""))
- {
- splitFrequency = Integer.valueOf(splitFrequencyString);
- }
- // Get contentReader inputStream
- is = targetReader.getContentInputStream();
- // stream the document in
- pdf = PDDocument.load(is);
- // split the PDF and put the pages in a list
- Splitter splitter = new Splitter();
- // if the default split is not every page, then set it to the right
- // frequency
- if (splitFrequency > 0)
- {
- splitter.setSplitAtPage(splitFrequency);
- }
- // Split the pages
- List<PDDocument> pdfs = splitter.split(pdf);
- // Lets get reading to walk the list
- Iterator<PDDocument> it = pdfs.iterator();
- // Start page split numbering at
- int page = 1;
- int endPage = 0;
- // build a temp dir name based on the ID of the noderef we are
- // importing
- File alfTempDir = TempFileProvider.getTempDir();
- tempDir = new File(alfTempDir.getPath() + File.separatorChar + targetNodeRef.getId());
- tempDir.mkdir();
- while (it.hasNext())
- {
- // Pulling together the right string split pages
- String pagePlus = "";
- String pg = "_pg";
- // Get the split document and save it into the temp dir with new
- // name
- PDDocument splitpdf = (PDDocument)it.next();
- int pagesInPDF = splitpdf.getNumberOfPages();
- if (splitFrequency > 0)
- {
- endPage = endPage + pagesInPDF;
- pagePlus = "-" + endPage;
- pg = "_pgs";
- }
- // put together the name and save the PDF
- String fileNameSansExt = getFilenameSansExt(targetNodeRef, FILE_EXTENSION);
- splitpdf.save(tempDir + "" + File.separatorChar + fileNameSansExt + pg + page + pagePlus + FILE_EXTENSION);
- // increment page count
- if (splitFrequency > 0)
- {
- page = (page++) + pagesInPDF;
- }
- else
- {
- page++;
- }
- try
- {
- splitpdf.close();
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- }
- for (File file : tempDir.listFiles())
- {
- try
- {
- if (file.isFile())
- {
- // Get a writer and prep it for putting it back into the
- // repo
- NodeRef destinationNode = createDestinationNode(file.getName(),
- destinationFolder, targetNodeRef, false);
- writer = cs.getWriter(destinationNode, ContentModel.PROP_CONTENT, true);
- writer.setEncoding(targetReader.getEncoding()); // original
- // encoding
- writer.setMimetype(FILE_MIMETYPE);
- // Put it in the repo
- writer.putContent(file);
- // Clean up
- file.delete();
- }
- }
- catch (FileExistsException e)
- {
- throw new AlfrescoRuntimeException("Failed to process file.", e);
- }
- }
- }
- catch (COSVisitorException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- finally
- {
- if (pdf != null)
- {
- try
- {
- pdf.close();
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- }
- if (is != null)
- {
- try
- {
- is.close();
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- }
- if (tempDir != null)
- {
- tempDir.delete();
- }
- }
- return destinationFolder;
- }
- @Override
- public NodeRef splitPDFAtPage(NodeRef targetNodeRef, Map<String, Serializable> params)
- {
- PDDocument pdf = null;
- InputStream is = null;
- File tempDir = null;
- ContentWriter writer = null;
- NodeRef destinationFolder;
- try
- {
- destinationFolder = (NodeRef)params.get(PARAM_DESTINATION_FOLDER);
- ContentReader targetReader = getReader(targetNodeRef);
- // Get the split frequency
- int splitPageNumber = 0;
- String splitPage = params.get(PARAM_PAGE).toString();
- if (!splitPage.equals(""))
- {
- try
- {
- splitPageNumber = Integer.valueOf(splitPage);
- }
- catch (NumberFormatException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- }
- // Get contentReader inputStream
- is = targetReader.getContentInputStream();
- // stream the document in
- pdf = PDDocument.load(is);
- // split the PDF and put the pages in a list
- Splitter splitter = new Splitter();
- // Need to adjust the input value to get the split at the right page
- splitter.setSplitAtPage(splitPageNumber - 1);
- // Split the pages
- List<PDDocument> pdfs = splitter.split(pdf);
- // Start page split numbering at
- int page = 1;
- // build a temp dir, name based on the ID of the noderef we are
- // importing
- File alfTempDir = TempFileProvider.getTempDir();
- tempDir = new File(alfTempDir.getPath() + File.separatorChar + targetNodeRef.getId());
- tempDir.mkdir();
- // FLAG: This is ugly.....get the first PDF.
- PDDocument firstPDF = (PDDocument)pdfs.remove(0);
- int pagesInFirstPDF = firstPDF.getNumberOfPages();
- String lastPage = "";
- String pg = "_pg";
- if (pagesInFirstPDF > 1)
- {
- pg = "_pgs";
- lastPage = "-" + pagesInFirstPDF;
- }
- String fileNameSansExt = getFilenameSansExt(targetNodeRef, FILE_EXTENSION);
- firstPDF.save(tempDir + "" + File.separatorChar + fileNameSansExt + pg + page + lastPage + FILE_EXTENSION);
- try
- {
- firstPDF.close();
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- // FLAG: Like I said: "_UGLY_" ..... and it gets worse
- PDDocument secondPDF = null;
- Iterator<PDDocument> its = pdfs.iterator();
- int pagesInSecondPDF = 0;
- while (its.hasNext())
- {
- if (secondPDF != null)
- {
- // Get the split document and save it into the temp dir with
- // new name
- PDDocument splitpdf = (PDDocument)its.next();
- int pagesInThisPDF = splitpdf.getNumberOfPages();
- pagesInSecondPDF = pagesInSecondPDF + pagesInThisPDF;
- PDFMergerUtility merger = new PDFMergerUtility();
- merger.appendDocument(secondPDF, splitpdf);
- merger.mergeDocuments();
- try
- {
- splitpdf.close();
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- }
- else
- {
- secondPDF = (PDDocument)its.next();
- pagesInSecondPDF = secondPDF.getNumberOfPages();
- }
- }
- if (pagesInSecondPDF > 1)
- {
- pg = "_pgs";
- lastPage = "-" + (pagesInSecondPDF + pagesInFirstPDF);
- }
- else
- {
- pg = "_pg";
- lastPage = "";
- }
- // This is where we should save the appended PDF
- // put together the name and save the PDF
- secondPDF.save(tempDir + "" + File.separatorChar + fileNameSansExt + pg + splitPageNumber + lastPage + FILE_EXTENSION);
- for (File file : tempDir.listFiles())
- {
- try
- {
- if (file.isFile())
- {
- // Get a writer and prep it for putting it back into the
- // repo
- NodeRef destinationNode = createDestinationNode(file.getName(),
- destinationFolder, targetNodeRef, false);
- writer = cs.getWriter(destinationNode, ContentModel.PROP_CONTENT, true);
- writer.setEncoding(targetReader.getEncoding()); // original
- // encoding
- writer.setMimetype(FILE_MIMETYPE);
- // Put it in the repo
- writer.putContent(file);
- // Clean up
- file.delete();
- }
- }
- catch (FileExistsException e)
- {
- throw new AlfrescoRuntimeException("Failed to process file.", e);
- }
- }
- }
- catch (COSVisitorException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- finally
- {
- if (pdf != null)
- {
- try
- {
- pdf.close();
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- }
- if (is != null)
- {
- try
- {
- is.close();
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- }
- if (tempDir != null)
- {
- tempDir.delete();
- }
- }
- return destinationFolder;
- }
- @Override
- public NodeRef insertPDF(NodeRef targetNodeRef, Map<String, Serializable> params)
- {
- PDDocument pdf = null;
- PDDocument insertContentPDF = null;
- InputStream is = null;
- InputStream cis = null;
- File tempDir = null;
- ContentWriter writer = null;
- NodeRef destinationNode = null;
- try
- {
- ContentReader targetReader = getReader(targetNodeRef);
- ContentReader insertReader = getReader((NodeRef)params.get(PARAM_TARGET_NODE));
- int insertAt = Integer.valueOf((String)params.get(PARAM_PAGE)).intValue();
- Boolean inplace = true;
- // Get contentReader inputStream
- is = targetReader.getContentInputStream();
- // Get insertContentReader inputStream
- cis = insertReader.getContentInputStream();
- // stream the target document in
- pdf = PDDocument.load(is);
- // stream the insert content document in
- insertContentPDF = PDDocument.load(cis);
- // split the PDF and put the pages in a list
- Splitter splitter = new Splitter();
- // Split the pages
- List<PDDocument> pdfs = splitter.split(pdf);
- // Build the output PDF
- PDFMergerUtility merger = new PDFMergerUtility();
- PDDocument newDocument = new PDDocument();
- for (int i = 0; i < pdfs.size(); i++) {
- if (i == insertAt -1) {
- merger.appendDocument(newDocument, insertContentPDF);
- }
- merger.appendDocument(newDocument, (PDDocument)pdfs.get(i));
- }
- merger.setDestinationFileName(params.get(PARAM_DESTINATION_NAME).toString());
- merger.mergeDocuments();
- // build a temp dir, name based on the ID of the noderef we are
- // importing
- File alfTempDir = TempFileProvider.getTempDir();
- tempDir = new File(alfTempDir.getPath() + File.separatorChar + targetNodeRef.getId());
- tempDir.mkdir();
- String fileName = params.get(PARAM_DESTINATION_NAME).toString();
- PDDocument completePDF = newDocument;
- completePDF.save(tempDir + "" + File.separatorChar + fileName + FILE_EXTENSION);
- try
- {
- completePDF.close();
- newDocument.close();
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- for (File file : tempDir.listFiles())
- {
- try
- {
- if (file.isFile())
- {
- // Get a writer and prep it for putting it back into the
- // repo
- destinationNode = createDestinationNode(file.getName(),
- (NodeRef)params.get(PARAM_DESTINATION_FOLDER), targetNodeRef, inplace);
- writer = cs.getWriter(destinationNode, ContentModel.PROP_CONTENT, true);
- writer.setEncoding(targetReader.getEncoding()); // original
- // encoding
- writer.setMimetype(FILE_MIMETYPE);
- // Put it in the repo
- writer.putContent(file);
- // Clean up
- file.delete();
- }
- }
- catch (FileExistsException e)
- {
- throw new AlfrescoRuntimeException("Failed to process file.", e);
- }
- }
- }
- // TODO add better handling
- catch (COSVisitorException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- finally
- {
- if (pdf != null)
- {
- try
- {
- pdf.close();
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- }
- if (is != null)
- {
- try
- {
- is.close();
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- }
- if (tempDir != null)
- {
- tempDir.delete();
- }
- }
- return destinationNode;
- }
- @Override
- public NodeRef deletePagesFromPDF(NodeRef targetNodeRef, Map<String, Serializable> params)
- {
- String pages = String.valueOf(params.get(PARAM_PAGE));
- return subsetPDFDocument(targetNodeRef, params, pages, true, true);
- }
- @Override
- public NodeRef extractPagesFromPDF(NodeRef targetNodeRef, Map<String, Serializable> params)
- {
- String pages = String.valueOf(params.get(PARAM_PAGE));
- return subsetPDFDocument(targetNodeRef, params, pages, false, false);
- }
- @Override
- public NodeRef rotatePDF(NodeRef targetNodeRef, Map<String, Serializable> params)
- {
- InputStream is = null;
- File tempDir = null;
- ContentWriter writer = null;
- PdfReader pdfReader = null;
- NodeRef destinationNode = null;
- try
- {
- ContentReader targetReader = getReader(targetNodeRef);
- is = targetReader.getContentInputStream();
- File alfTempDir = TempFileProvider.getTempDir();
- tempDir = new File(alfTempDir.getPath() + File.separatorChar + targetNodeRef.getId());
- tempDir.mkdir();
- Boolean inplace = true;
- Integer degrees = Integer.valueOf(String.valueOf(params.get(PARAM_DEGREES)));
- String pages = String.valueOf(params.get(PARAM_PAGE));
- if(degrees % 90 != 0)
- {
- throw new AlfrescoRuntimeException("Rotation degres must be a multiple of 90 (90, 180, 270, etc)");
- }
- String fileName = getFilename(params, targetNodeRef);
- File file = new File(tempDir, ffs.getFileInfo(targetNodeRef).getName());
- pdfReader = new PdfReader(is);
- PdfStamper stamp = new PdfStamper(pdfReader, new FileOutputStream(file));
- int rotation = 0;
- PdfDictionary pageDictionary;
- int numPages = pdfReader.getNumberOfPages();
- for (int pageNum = 1; pageNum <= numPages; pageNum++)
- {
- // only apply stamp to requested pages
- if (checkPage(pages, pageNum, numPages))
- {
- rotation = pdfReader.getPageRotation(pageNum);
- pageDictionary = pdfReader.getPageN(pageNum);
- pageDictionary.put(PdfName.ROTATE, new PdfNumber(rotation + degrees));
- }
- }
- stamp.close();
- pdfReader.close();
- destinationNode = createDestinationNode(fileName,
- (NodeRef)params.get(PARAM_DESTINATION_FOLDER), targetNodeRef, inplace);
- writer = cs.getWriter(destinationNode, ContentModel.PROP_CONTENT, true);
- writer.setEncoding(targetReader.getEncoding());
- writer.setMimetype(FILE_MIMETYPE);
- // Put it in the repository
- writer.putContent(file);
- // Clean up
- file.delete();
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- catch (DocumentException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- catch (Exception e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- finally
- {
- if (pdfReader != null)
- {
- pdfReader.close();
- }
- if (is != null)
- {
- try
- {
- is.close();
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- }
- if (tempDir != null)
- {
- tempDir.delete();
- }
- }
- return destinationNode;
- }
- private NodeRef subsetPDFDocument(NodeRef targetNodeRef, Map<String, Serializable> params, String pages, boolean inplace, boolean delete)
- {
- InputStream is = null;
- File tempDir = null;
- ContentWriter writer = null;
- PdfReader pdfReader = null;
- NodeRef destinationNode = null;
- try
- {
- ContentReader targetReader = getReader(targetNodeRef);
- is = targetReader.getContentInputStream();
- File alfTempDir = TempFileProvider.getTempDir();
- tempDir = new File(alfTempDir.getPath() + File.separatorChar + targetNodeRef.getId());
- tempDir.mkdir();
- //Boolean inplace = inplace;
- String fileName = getFilename(params, targetNodeRef);
- File file = new File(tempDir, ffs.getFileInfo(targetNodeRef).getName());
- pdfReader = new PdfReader(is);
- Document doc = new Document(pdfReader.getPageSizeWithRotation(1));
- PdfCopy copy = new PdfCopy(doc, new FileOutputStream(file));
- doc.open();
- List<Integer> pagelist = parsePageList(pages);
- for (int pageNum = 1; pageNum <= pdfReader.getNumberOfPages(); pageNum++)
- {
- if (pagelist.contains(pageNum) && !delete)
- {
- copy.addPage(copy.getImportedPage(pdfReader, pageNum));
- }
- else if (!pagelist.contains(pageNum) && delete)
- {
- copy.addPage(copy.getImportedPage(pdfReader, pageNum));
- }
- }
- doc.close();
- destinationNode = createDestinationNode(fileName,
- (NodeRef)params.get(PARAM_DESTINATION_FOLDER), targetNodeRef, inplace);
- writer = cs.getWriter(destinationNode, ContentModel.PROP_CONTENT, true);
- writer.setEncoding(targetReader.getEncoding());
- writer.setMimetype(FILE_MIMETYPE);
- // Put it in the repository
- writer.putContent(file);
- // Clean up
- file.delete();
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- catch (DocumentException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- catch (Exception e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- finally
- {
- if (pdfReader != null)
- {
- pdfReader.close();
- }
- if (is != null)
- {
- try
- {
- is.close();
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- }
- if (tempDir != null)
- {
- tempDir.delete();
- }
- }
- return destinationNode;
- }
- private ContentReader getReader(NodeRef nodeRef)
- {
- // first, make sure the node exists
- if (ns.exists(nodeRef) == false)
- {
- // node doesn't exist - can't do anything
- throw new AlfrescoRuntimeException("NodeRef: " + nodeRef + " does not exist");
- }
- // Next check that the node is a sub-type of content
- QName typeQName = ns.getType(nodeRef);
- if (ds.isSubClass(typeQName, ContentModel.TYPE_CONTENT) == false)
- {
- // it is not content, so can't transform
- throw new AlfrescoRuntimeException("The selected node is not a content node");
- }
- // Get the content reader. If it is null, can't do anything here
- ContentReader contentReader = cs.getReader(nodeRef, ContentModel.PROP_CONTENT);
- if(contentReader == null)
- {
- throw new AlfrescoRuntimeException("The content reader for NodeRef: " + nodeRef + "is null");
- }
- return contentReader;
- }
- /**
- * @param ruleAction
- * @param filename
- * @return
- */
- private NodeRef createDestinationNode(String filename, NodeRef destinationParent, NodeRef target, boolean inplace)
- {
- NodeRef destinationNode;
- // if inplace mode is turned on, the destination for the modified content
- // is the original node
- if(inplace)
- {
- return target;
- }
- if(createNew)
- {
- //create a file in the right location
- FileInfo fileInfo = ffs.create(destinationParent, filename, ContentModel.TYPE_CONTENT);
- destinationNode = fileInfo.getNodeRef();
- }
- else
- {
- try
- {
- FileInfo fileInfo = ffs.copy(target, destinationParent, filename);
- destinationNode = fileInfo.getNodeRef();
- }
- catch(FileNotFoundException fnf)
- {
- throw new AlfrescoRuntimeException(fnf.getMessage(), fnf);
- }
- }
- return destinationNode;
- }
- private int getInteger(Serializable val)
- {
- if(val == null)
- {
- return 0;
- }
- try
- {
- return Integer.parseInt(val.toString());
- }
- catch(NumberFormatException nfe)
- {
- return 0;
- }
- }
- private File getTempFile(NodeRef nodeRef)
- {
- File alfTempDir = TempFileProvider.getTempDir();
- File toolkitTempDir = new File(alfTempDir.getPath() + File.separatorChar + nodeRef.getId());
- toolkitTempDir.mkdir();
- File file = new File(toolkitTempDir, ffs.getFileInfo(nodeRef).getName());
- return file;
- }
- private String getFilename(Map<String, Serializable> params, NodeRef targetNodeRef)
- {
- Serializable providedName = params.get(PARAM_DESTINATION_NAME);
- String fileName = null;
- if(providedName != null)
- {
- fileName = String.valueOf(providedName);
- if(!fileName.endsWith(FILE_EXTENSION))
- {
- fileName = fileName + FILE_EXTENSION;
- }
- }
- else
- {
- fileName = String.valueOf(ns.getProperty(targetNodeRef, ContentModel.PROP_NAME));
- }
- return fileName;
- }
- /**
- * Parses the list of pages or page ranges to delete and returns a list of page numbers
- *
- * @param list
- * @return
- */
- private List<Integer> parsePageList(String list)
- {
- List<Integer> pages = new ArrayList<Integer>();
- String[] tokens = list.split(",");
- for(String token : tokens)
- {
- //parse each, if one is not an int, log it but keep going
- try
- {
- pages.add(Integer.parseInt(token));
- }
- catch(NumberFormatException nfe)
- {
- logger.warn("Page list contains non-numeric values");
- }
- }
- return pages;
- }
- /**
- * Build the permissions mask for iText
- *
- * @param options
- * @return
- */
- private int buildPermissionMask(Map<String, Serializable> options)
- {
- int permissions = 0;
- if ((Boolean)options.get(PARAM_ALLOW_PRINT))
- {
- permissions = permissions | PdfWriter.ALLOW_PRINTING;
- }
- if ((Boolean)options.get(PARAM_ALLOW_COPY))
- {
- permissions = permissions | PdfWriter.ALLOW_COPY;
- }
- if ((Boolean)options.get(PARAM_ALLOW_CONTENT_MODIFICATION))
- {
- permissions = permissions | PdfWriter.ALLOW_MODIFY_CONTENTS;
- }
- if ((Boolean)options.get(PARAM_ALLOW_ANNOTATION_MODIFICATION))
- {
- permissions = permissions | PdfWriter.ALLOW_MODIFY_ANNOTATIONS;
- }
- if ((Boolean)options.get(PARAM_ALLOW_SCREEN_READER))
- {
- permissions = permissions | PdfWriter.ALLOW_SCREENREADERS;
- }
- if ((Boolean)options.get(PARAM_ALLOW_DEGRADED_PRINT))
- {
- permissions = permissions | PdfWriter.ALLOW_DEGRADED_PRINTING;
- }
- if ((Boolean)options.get(PARAM_ALLOW_ASSEMBLY))
- {
- permissions = permissions | PdfWriter.ALLOW_ASSEMBLY;
- }
- if ((Boolean)options.get(PARAM_ALLOW_FORM_FILL))
- {
- permissions = permissions | PdfWriter.ALLOW_FILL_IN;
- }
- return permissions;
- }
- /**
- * Create a rectangle for the visible signature using the selected position and signature size
- *
- * @param position
- * @param width
- * @param height
- * @return
- */
- private Rectangle positionSignature(String position, Rectangle pageRect, int width, int height)
- {
- float pageHeight = pageRect.getHeight();
- float pageWidth = pageRect.getWidth();
- Rectangle r = null;
- if (position.equals(POSITION_BOTTOMLEFT))
- {
- r = new Rectangle(0, height, width, 0);
- }
- else if (position.equals(POSITION_BOTTOMRIGHT))
- {
- r = new Rectangle(pageWidth - width, height, pageWidth, 0);
- }
- else if (position.equals(POSITION_TOPLEFT))
- {
- r = new Rectangle(0, pageHeight, width, pageHeight - height);
- }
- else if (position.equals(POSITION_TOPRIGHT))
- {
- r = new Rectangle(pageWidth - width, pageHeight, pageWidth, pageHeight - height);
- }
- else if (position.equals(POSITION_CENTER))
- {
- r = new Rectangle((pageWidth / 2) - (width / 2), (pageHeight / 2) - (height / 2),
- (pageWidth / 2) + (width / 2), (pageHeight / 2) + (height / 2));
- }
- return r;
- }
- /**
- * @param fileName
- * @param extension
- * @return
- */
- private String removeExtension(String fileName, String extension)
- {
- // Does the file have the extension?
- if (fileName != null && fileName.contains(extension))
- {
- // Where does the extension start?
- int extensionStartsAt = fileName.indexOf(extension);
- // Get the Filename sans the extension
- return fileName.substring(0, extensionStartsAt);
- }
- return fileName;
- }
- private String getFilename(NodeRef targetNodeRef)
- {
- FileInfo fileInfo = ffs.getFileInfo(targetNodeRef);
- String filename = fileInfo.getName();
- return filename;
- }
- private String getFilenameSansExt(NodeRef targetNodeRef, String extension)
- {
- String filenameSansExt;
- filenameSansExt = removeExtension(getFilename(targetNodeRef), extension);
- return filenameSansExt;
- }
- /**
- * Applies an image watermark
- *
- * @param reader
- * @param writer
- * @param options
- * @throws Exception
- */
- private NodeRef imageAction(Map<String, Serializable> options, NodeRef targetNodeRef, NodeRef watermarkNodeRef,
- ContentReader actionedUponContentReader, ContentReader watermarkContentReader)
- {
- PdfStamper stamp = null;
- File tempDir = null;
- ContentWriter writer = null;
- NodeRef destinationNode = null;
- try
- {
- File file = getTempFile(targetNodeRef);
- // get the PDF input stream and create a reader for iText
- PdfReader reader = new PdfReader(actionedUponContentReader.getContentInputStream());
- stamp = new PdfStamper(reader, new FileOutputStream(file));
- PdfContentByte pcb;
- // get a com.itextpdf.text.Image object via java.imageio.ImageIO
- Image img = Image.getInstance(ImageIO.read(watermarkContentReader.getContentInputStream()), null);
- // get the PDF pages and position
- String pages = (String)options.get(PARAM_PAGE);
- String position = (String)options.get(PARAM_POSITION);
- String depth = (String)options.get(PARAM_WATERMARK_DEPTH);
- Boolean inplace = true;
- // get the manual positioning options (if provided)
- int locationX = getInteger(options.get(PARAM_LOCATION_X));
- int locationY = getInteger(options.get(PARAM_LOCATION_Y));
- // image requires absolute positioning or an exception will be
- // thrown
- // set image position according to parameter. Use
- // PdfReader.getPageSizeWithRotation
- // to get the canvas size for alignment.
- img.setAbsolutePosition(100f, 100f);
- // stamp each page
- int numpages = reader.getNumberOfPages();
- for (int i = 1; i <= numpages; i++)
- {
- Rectangle r = reader.getPageSizeWithRotation(i);
- // set stamp position
- if (position.equals(POSITION_BOTTOMLEFT))
- {
- img.setAbsolutePosition(0, 0);
- }
- else if (position.equals(POSITION_BOTTOMRIGHT))
- {
- img.setAbsolutePosition(r.getWidth() - img.getWidth(), 0);
- }
- else if (position.equals(POSITION_TOPLEFT))
- {
- img.setAbsolutePosition(0, r.getHeight() - img.getHeight());
- }
- else if (position.equals(POSITION_TOPRIGHT))
- {
- img.setAbsolutePosition(r.getWidth() - img.getWidth(), r.getHeight() - img.getHeight());
- }
- else if (position.equals(POSITION_CENTER))
- {
- img.setAbsolutePosition(getCenterX(r, img), getCenterY(r, img));
- }
- else if (position.equals(POSITION_MANUAL))
- {
- img.setAbsolutePosition(locationX, locationY);
- }
- // if this is an under-text stamp, use getUnderContent.
- // if this is an over-text stamp, usse getOverContent.
- if (depth.equals(DEPTH_OVER))
- {
- pcb = stamp.getOverContent(i);
- }
- else
- {
- pcb = stamp.getUnderContent(i);
- }
- // only apply stamp to requested pages
- if (checkPage(pages, i, numpages))
- {
- pcb.addImage(img);
- }
- }
- stamp.close();
- String fileName = getFilename(options, targetNodeRef);
- // Get a writer and prep it for putting it back into the repo
- //can't use BasePDFActionExecuter.getWriter here need the nodeRef of the destination
- destinationNode = createDestinationNode(fileName,
- (NodeRef)options.get(PARAM_DESTINATION_FOLDER), targetNodeRef, inplace);
- writer = cs.getWriter(destinationNode, ContentModel.PROP_CONTENT, true);
- writer.setEncoding(actionedUponContentReader.getEncoding());
- writer.setMimetype(FILE_MIMETYPE);
- // Put it in the repo
- writer.putContent(file);
- // delete the temp file
- file.delete();
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- catch (DocumentException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- finally
- {
- if (tempDir != null)
- {
- try
- {
- tempDir.delete();
- }
- catch (Exception ex)
- {
- throw new AlfrescoRuntimeException(ex.getMessage(), ex);
- }
- }
- if (stamp != null)
- {
- try
- {
- stamp.close();
- }
- catch (Exception ex)
- {
- throw new AlfrescoRuntimeException(ex.getMessage(), ex);
- }
- }
- }
- return destinationNode;
- }
- /**
- * Applies a text watermark (current date, user name, etc, depending on
- * options)
- *
- * @param reader
- * @param writer
- * @param options
- */
- private NodeRef textAction(Map<String, Serializable> options, NodeRef targetNodeRef, ContentReader actionedUponContentReader)
- {
- PdfStamper stamp = null;
- File tempDir = null;
- ContentWriter writer = null;
- String watermarkText;
- StringTokenizer st;
- Vector<String> tokens = new Vector<String>();
- NodeRef destinationNode = null;
- try
- {
- File file = getTempFile(targetNodeRef);
- // get the PDF input stream and create a reader for iText
- PdfReader reader = new PdfReader(actionedUponContentReader.getContentInputStream());
- stamp = new PdfStamper(reader, new FileOutputStream(file));
- PdfContentByte pcb;
- // get the PDF pages and position
- String pages = (String)options.get(PARAM_PAGE);
- String position = (String)options.get(PARAM_POSITION);
- String depth = (String)options.get(PARAM_WATERMARK_DEPTH);
- int locationX = getInteger(options.get(PARAM_LOCATION_X));
- int locationY = getInteger(options.get(PARAM_LOCATION_Y));
- Boolean inplace = true;
- // create the base font for the text stamp
- BaseFont bf = BaseFont.createFont((String)options.get(PARAM_WATERMARK_FONT), BaseFont.CP1250, BaseFont.EMBEDDED);
- // get watermark text and process template with model
- String templateText = (String)options.get(PARAM_WATERMARK_TEXT);
- Map<String, Object> model = buildWatermarkTemplateModel(targetNodeRef);
- StringWriter watermarkWriter = new StringWriter();
- freemarkerProcessor.processString(templateText, model, watermarkWriter);
- watermarkText = watermarkWriter.getBuffer().toString();
- // tokenize watermark text to support multiple lines and copy tokens
- // to vector for re-use
- st = new StringTokenizer(watermarkText, "\r\n", false);
- while (st.hasMoreTokens())
- {
- tokens.add(st.nextToken());
- }
- // stamp each page
- int numpages = reader.getNumberOfPages();
- for (int i = 1; i <= numpages; i++)
- {
- Rectangle r = reader.getPageSizeWithRotation(i);
- // if this is an under-text stamp, use getUnderContent.
- // if this is an over-text stamp, use getOverContent.
- if (depth.equals(DEPTH_OVER))
- {
- pcb = stamp.getOverContent(i);
- }
- else
- {
- pcb = stamp.getUnderContent(i);
- }
- // set the font and size
- float size = Float.parseFloat((String)options.get(PARAM_WATERMARK_SIZE));
- pcb.setFontAndSize(bf, size);
- // only apply stamp to requested pages
- if (checkPage(pages, i, numpages))
- {
- writeAlignedText(pcb, r, tokens, size, position, locationX, locationY);
- }
- }
- stamp.close();
- String fileName = getFilename(options, targetNodeRef);
- // Get a writer and prep it for putting it back into the repo
- //can't use BasePDFActionExecuter.getWriter here need the nodeRef of the destination
- destinationNode = createDestinationNode(fileName,
- (NodeRef)options.get(PARAM_DESTINATION_FOLDER), targetNodeRef, inplace);
- writer = cs.getWriter(destinationNode, ContentModel.PROP_CONTENT, true);
- writer.setEncoding(actionedUponContentReader.getEncoding());
- writer.setMimetype(FILE_MIMETYPE);
- // Put it in the repo
- writer.putContent(file);
- // delete the temp file
- file.delete();
- }
- catch (IOException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- catch (DocumentException e)
- {
- throw new AlfrescoRuntimeException(e.getMessage(), e);
- }
- finally
- {
- if (tempDir != null)
- {
- try
- {
- tempDir.delete();
- }
- catch (Exception ex)
- {
- throw new AlfrescoRuntimeException(ex.getMessage(), ex);
- }
- }
- if (stamp != null)
- {
- try
- {
- stamp.close();
- }
- catch (Exception ex)
- {
- throw new AlfrescoRuntimeException(ex.getMessage(), ex);
- }
- }
- }
- return destinationNode;
- }
- /**
- * Writes text watermark to one of the 5 preconfigured locations
- *
- * @param pcb
- * @param r
- * @param tokens
- * @param size
- * @param position
- */
- private void writeAlignedText(PdfContentByte pcb, Rectangle r, Vector<String> tokens, float size,
- String position, int locationX, int locationY)
- {
- // get the dimensions of our 'rectangle' for text
- float height = size * tokens.size();
- float width = 0;
- float centerX = 0, startY = 0;
- for (int i = 0; i < tokens.size(); i++)
- {
- if (pcb.getEffectiveStringWidth(tokens.get(i), false) > width)
- {
- width = pcb.getEffectiveStringWidth(tokens.get(i), false);
- }
- }
- // now that we have the width and height, we can calculate the center
- // position for
- // the rectangle that will contain our text.
- if (position.equals(POSITION_BOTTOMLEFT))
- {
- centerX = width / 2 + PAD;
- startY = 0 + PAD + height;
- }
- else if (position.equals(POSITION_BOTTOMRIGHT))
- {
- centerX = r.getWidth() - (width / 2) - PAD;
- startY = 0 + PAD + height;
- }
- else if (position.equals(POSITION_TOPLEFT))
- {
- centerX = width / 2 + PAD;
- startY = r.getHeight() - (PAD * 2);
- }
- else if (position.equals(POSITION_TOPRIGHT))
- {
- centerX = r.getWidth() - (width / 2) - PAD;
- startY = r.getHeight() - (PAD * 2);
- }
- else if (position.equals(POSITION_CENTER))
- {
- centerX = r.getWidth() / 2;
- startY = (r.getHeight() / 2) + (height / 2);
- }
- else if (position.equals(POSITION_MANUAL))
- {
- centerX = r.getWidth() / 2 - locationX;
- startY = locationY;
- }
- // apply text to PDF
- pcb.beginText();
- for (int t = 0; t < tokens.size(); t++)
- {
- pcb.showTextAligned(PdfContentByte.ALIGN_CENTER, tokens.get(t), centerX, startY - (size * t), 0);
- }
- pcb.endText();
- }
- /**
- * Builds a freemarker model which supports a subset of the default model.
- *
- * @param ref
- * @return
- */
- private Map<String, Object> buildWatermarkTemplateModel(NodeRef ref)
- {
- Map<String, Object> model = new HashMap<String, Object>();
- NodeRef person = ps.getPerson(as.getCurrentUserName());
- model.put("person", new TemplateNode(person, serviceRegistry, null));
- NodeRef homespace = (NodeRef)ns.getProperty(person, ContentModel.PROP_HOMEFOLDER);
- model.put("userhome", new TemplateNode(homespace, serviceRegistry, null));
- model.put("document", new TemplateNode(ref, serviceRegistry, null));
- NodeRef parent = ns.getPrimaryParent(ref).getParentRef();
- model.put("space", new TemplateNode(parent, serviceRegistry, null));
- model.put("date", new Date());
- //also add all of the node properties to the model
- model.put("properties", ns.getProperties(ref));
- return model;
- }
- /**
- * Determines whether or not a watermark should be applied to a given page
- *
- * @param pages
- * @param current
- * @param numpages
- * @return
- */
- private boolean checkPage(String pages, int current, int numpages)
- {
- boolean markPage = false;
- if (pages.equals(PAGE_EVEN))
- {
- if (current % 2 == 0)
- {
- markPage = true;
- }
- }
- else if (pages.equals(PAGE_ODD))
- {
- if (current % 2 != 0)
- {
- markPage = true;
- }
- }
- else if (pages.equals(PAGE_FIRST))
- {
- if (current == 1)
- {
- markPage = true;
- }
- }
- else if (pages.equals(PAGE_LAST))
- {
- if (current == numpages)
- {
- markPage = true;
- }
- }
- else if (pages.equals(PAGE_ALL))
- {
- markPage = true;
- }
- else
- {
- // if we get here, a scheme wasn't selected, so we can treat this like a page list
- List<Integer> pageList = parsePageList(pages);
- if(pageList.contains(current))
- {
- markPage = true;
- }
- }
- return markPage;
- }
- /**
- * Gets the X value for centering the watermark image
- *
- * @param r
- * @param img
- * @return
- */
- private float getCenterX(Rectangle r, Image img)
- {
- float x = 0;
- float pdfwidth = r.getWidth();
- float imgwidth = img.getWidth();
- x = (pdfwidth - imgwidth) / 2;
- return x;
- }
- /**
- * Gets the Y value for centering the watermark image
- *
- * @param r
- * @param img
- * @return
- */
- private float getCenterY(Rectangle r, Image img)
- {
- float y = 0;
- float pdfheight = r.getHeight();
- float imgheight = img.getHeight();
- y = (pdfheight - imgheight) / 2;
- return y;
- }
- /**
- * @param serviceRegistry
- */
- public void setServiceRegistry(ServiceRegistry serviceRegistry)
- {
- this.serviceRegistry = serviceRegistry;
- ns = serviceRegistry.getNodeService();
- cs = serviceRegistry.getContentService();
- ffs = serviceRegistry.getFileFolderService();
- ds = serviceRegistry.getDictionaryService();
- ps = serviceRegistry.getPersonService();
- as = serviceRegistry.getAuthenticationService();
- }
- /**
- * Sets whether a PDF action creates a new empty node or copies the source node, preserving
- * the content type, applied aspects and properties
- *
- * @param createNew
- */
- public void setCreateNew(boolean createNew)
- {
- this.createNew = createNew;
- }
- public void setUseSignatureAspect(boolean useSignatureAspect)
- {
- this.useSignatureAspect = useSignatureAspect;
- }
- public void setUseEncryptionAspect(boolean useEncryptionAspect)
- {
- this.useEncryptionAspect = useEncryptionAspect;
- }
- public void setCheckOutCheckInService(
- CheckOutCheckInService checkOutCheckinService) {
- this.checkOutCheckInService = checkOutCheckinService;
- }
- }
Add Comment
Please, Sign In to add comment