package railo.runtime.text.pdf;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.pdfbox.exceptions.CryptographyException;
import org.pdfbox.exceptions.InvalidPasswordException;
import org.pdfbox.pdmodel.PDDocument;
import org.pdfbox.util.PDFText2HTML;
import railo.commons.io.IOUtil;
import railo.commons.io.res.Resource;
import railo.commons.lang.StringUtil;
import railo.runtime.PageContext;
import railo.runtime.exp.ApplicationException;
import railo.runtime.exp.CasterException;
import railo.runtime.exp.PageException;
import railo.runtime.img.Image;
import railo.runtime.op.Caster;
import railo.runtime.op.Constants;
import railo.runtime.op.Decision;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PRAcroForm;
import com.lowagie.text.pdf.PdfCopy;
import com.lowagie.text.pdf.PdfImportedPage;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfWriter;
import com.lowagie.text.pdf.SimpleBookmark;
public class PDFUtil {
public static final int ENCRYPT_RC4_40 = PdfWriter.STANDARD_ENCRYPTION_40;
public static final int ENCRYPT_RC4_128 = PdfWriter.STANDARD_ENCRYPTION_128;
public static final int ENCRYPT_RC4_128M = PdfWriter.STANDARD_ENCRYPTION_128;
public static final int ENCRYPT_AES_128 = PdfWriter.ENCRYPTION_AES_128;
public static final int ENCRYPT_NONE = -1;
private static final int PERMISSION_ALL =
PdfWriter.ALLOW_ASSEMBLY+
PdfWriter.ALLOW_COPY+
PdfWriter.ALLOW_DEGRADED_PRINTING+
PdfWriter.ALLOW_FILL_IN+
PdfWriter.ALLOW_MODIFY_ANNOTATIONS+
PdfWriter.ALLOW_MODIFY_CONTENTS+
PdfWriter.ALLOW_PRINTING+
PdfWriter.ALLOW_SCREENREADERS+PdfWriter.ALLOW_COPY;// muss 2 mal sein, keine ahnung wieso
/**
* convert a string list of permission
* @param strPermissions
* @return
* @throws PageException
*/
public static int toPermissions(String strPermissions) throws PageException {
if(strPermissions==null) return 0;
int permissions=0;
strPermissions=strPermissions.trim();
String[] arr = railo.runtime.type.util.ListUtil.toStringArray(railo.runtime.type.util.ListUtil.listToArrayRemoveEmpty(strPermissions, ','));
for(int i=0;i<arr.length;i++) {
permissions=add(permissions,toPermission(arr[i]));
}
return permissions;
}
/**
* convert a string defintion of a permision in a integer Constant (PdfWriter.ALLOW_XXX)
* @param strPermission
* @return
* @throws ApplicationException
*/
public static int toPermission(String strPermission) throws ApplicationException {
strPermission=strPermission.trim().toLowerCase();
if("allowassembly".equals(strPermission)) return PdfWriter.ALLOW_ASSEMBLY;
else if("none".equals(strPermission)) return 0;
else if("all".equals(strPermission)) return PERMISSION_ALL;
else if("assembly".equals(strPermission)) return PdfWriter.ALLOW_ASSEMBLY;
else if("documentassembly".equals(strPermission)) return PdfWriter.ALLOW_ASSEMBLY;
else if("allowdegradedprinting".equals(strPermission)) return PdfWriter.ALLOW_DEGRADED_PRINTING;
else if("degradedprinting".equals(strPermission)) return PdfWriter.ALLOW_DEGRADED_PRINTING;
else if("printing".equals(strPermission)) return PdfWriter.ALLOW_DEGRADED_PRINTING;
else if("allowfillin".equals(strPermission)) return PdfWriter.ALLOW_FILL_IN;
else if("fillin".equals(strPermission)) return PdfWriter.ALLOW_FILL_IN;
else if("fillingform".equals(strPermission)) return PdfWriter.ALLOW_FILL_IN;
else if("allowmodifyannotations".equals(strPermission)) return PdfWriter.ALLOW_MODIFY_ANNOTATIONS;
else if("modifyannotations".equals(strPermission)) return PdfWriter.ALLOW_MODIFY_ANNOTATIONS;
else if("allowmodifycontents".equals(strPermission)) return PdfWriter.ALLOW_MODIFY_CONTENTS;
else if("modifycontents".equals(strPermission)) return PdfWriter.ALLOW_MODIFY_CONTENTS;
else if("allowcopy".equals(strPermission)) return PdfWriter.ALLOW_COPY;
else if("copy".equals(strPermission)) return PdfWriter.ALLOW_COPY;
else if("copycontent".equals(strPermission)) return PdfWriter.ALLOW_COPY;
else if("allowprinting".equals(strPermission)) return PdfWriter.ALLOW_PRINTING;
else if("printing".equals(strPermission)) return PdfWriter.ALLOW_PRINTING;
else if("allowscreenreaders".equals(strPermission)) return PdfWriter.ALLOW_SCREENREADERS;
else if("screenreaders".equals(strPermission)) return PdfWriter.ALLOW_SCREENREADERS;
else throw new ApplicationException("invalid permission ["+strPermission+"], valid permission values are [AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, AllowFillIn, AllowScreenReaders, AllowAssembly, AllowDegradedPrinting]");
}
private static int add(int permissions, int permission) {
if(permission==0 || (permissions&permission)>0)return permissions;
return permissions+permission;
}
/**
* @param docs
* @param os
* @param removePages if true, pages defined in PDFDocument will be removed, otherwise all other pages will be removed
* @param version
* @throws PageException
* @throws IOException
* @throws DocumentException
*/
public static void concat(PDFDocument[] docs,OutputStream os, boolean keepBookmark,boolean removePages, boolean stopOnError, char version) throws PageException, IOException, DocumentException {
Document document = null;
PdfCopy writer = null;
PdfReader reader;
Set pages;
boolean isInit=false;
PdfImportedPage page;
try {
int pageOffset = 0;
ArrayList master = new ArrayList();
for(int i=0;i<docs.length;i++) {
// we create a reader for a certain document
pages = docs[i].getPages();
try {
reader = docs[i].getPdfReader();
}
catch(Throwable t) {
if(!stopOnError)continue;
throw Caster.toPageException(t);
}
reader.consolidateNamedDestinations();
// we retrieve the total number of pages
int n = reader.getNumberOfPages();
List bookmarks = keepBookmark?SimpleBookmark.getBookmark(reader):null;
if (bookmarks != null) {
removeBookmarks(bookmarks,pages,removePages);
if (pageOffset != 0) SimpleBookmark.shiftPageNumbers(bookmarks, pageOffset, null);
master.addAll(bookmarks);
}
if (!isInit) {
isInit=true;
document = new Document(reader.getPageSizeWithRotation(1));
writer = new PdfCopy(document, os);
if(version!=0)writer.setPdfVersion(version);
document.open();
}
for (int y = 1; y <= n; y++) {
if(pages!=null && removePages==pages.contains(Integer.valueOf(y))){
continue;
}
pageOffset++;
page = writer.getImportedPage(reader, y);
writer.addPage(page);
}
PRAcroForm form = reader.getAcroForm();
if (form != null)
writer.copyAcroForm(reader);
}
if (master.size() > 0)
writer.setOutlines(master);
}
finally {
IOUtil.closeEL(document);
}
}
private static void removeBookmarks(List bookmarks,Set pages, boolean removePages) {
int size = bookmarks.size();
for(int i=size-1;i>=0;i--) {
if(removeBookmarks((Map) bookmarks.get(i),pages, removePages))
bookmarks.remove(i);
}
}
private static boolean removeBookmarks(Map bookmark, Set pages, boolean removePages) {
List kids=(List) bookmark.get("Kids");
if(kids!=null)removeBookmarks(kids,pages,removePages);
Integer page=Caster.toInteger(railo.runtime.type.util.ListUtil.first((String) bookmark.get("Page")," ",true),Constants.INTEGER_MINUS_ONE);
return removePages==(pages!=null && pages.contains(page));
}
public static Set parsePageDefinition(String strPages) throws PageException {
if(StringUtil.isEmpty(strPages)) return null;
HashSet<Integer> set=new HashSet<Integer>();
parsePageDefinition(set, strPages);
return set;
}
public static void parsePageDefinition(Set<Integer> pages, String strPages) throws PageException {
if(StringUtil.isEmpty(strPages)) return;
String[] arr = railo.runtime.type.util.ListUtil.toStringArrayTrim(railo.runtime.type.util.ListUtil.listToArrayRemoveEmpty(strPages, ','));
int index,from,to;
for(int i=0;i<arr.length;i++){
index=arr[i].indexOf('-');
if(index==-1)pages.add(Caster.toInteger(arr[i].trim()));
else {
from=Caster.toIntValue(arr[i].substring(0,index).trim());
to=Caster.toIntValue(arr[i].substring(index+1).trim());
for(int y=from;y<=to;y++){
pages.add(Integer.valueOf(y));
}
}
}
}
public static void encrypt(PDFDocument doc, OutputStream os, String newUserPassword, String newOwnerPassword, int permissions, int encryption) throws ApplicationException, DocumentException, IOException {
byte[] user = newUserPassword==null?null:newUserPassword.getBytes();
byte[] owner = newOwnerPassword==null?null:newOwnerPassword.getBytes();
PdfReader pr = doc.getPdfReader();
List bookmarks = SimpleBookmark.getBookmark(pr);
int n = pr.getNumberOfPages();
Document document = new Document(pr.getPageSizeWithRotation(1));
PdfCopy writer = new PdfCopy(document, os);
if(encryption!=ENCRYPT_NONE)writer.setEncryption(user, owner, permissions, encryption);
document.open();
PdfImportedPage page;
for (int i = 1; i <= n; i++) {
page = writer.getImportedPage(pr, i);
writer.addPage(page);
}
PRAcroForm form = pr.getAcroForm();
if (form != null)writer.copyAcroForm(pr);
if (bookmarks!=null)writer.setOutlines(bookmarks);
document.close();
}
public static HashMap generateGoToBookMark(String title,int page) {
return generateGoToBookMark(title,page, 0, 731);
}
public static HashMap generateGoToBookMark(String title,int page, int x, int y) {
HashMap map=new HashMap();
map.put("Title", title);
map.put("Action", "GoTo");
map.put("Page", page+" XYZ "+x+" "+y+" null");
return map;
}
public static void setChildBookmarks(Map parent, List children) {
Object kids = parent.get("Kids");
if(kids instanceof List){
((List)kids).addAll(children);
}
else parent.put("Kids", children);
}
public static PdfReader toPdfReader(PageContext pc,Object value, String password) throws IOException, PageException {
if(value instanceof PdfReader) return (PdfReader) value;
if(value instanceof PDFDocument) return ((PDFDocument) value).getPdfReader();
if(Decision.isBinary(value)){
if(password!=null)return new PdfReader(Caster.toBinary(value),password.getBytes());
return new PdfReader(Caster.toBinary(value));
}
if(value instanceof Resource) {
if(password!=null)return new PdfReader(IOUtil.toBytes((Resource)value),password.getBytes());
return new PdfReader(IOUtil.toBytes((Resource)value));
}
if(value instanceof String) {
if(password!=null)return new PdfReader(IOUtil.toBytes(Caster.toResource(pc,value,true)),password.getBytes());
return new PdfReader(IOUtil.toBytes((Resource)value));
}
throw new CasterException(value,PdfReader.class);
}
/*public static void main(String[] args) throws IOException {
PdfReader pr = new PdfReader("/Users/mic/Projects/Railo/webroot/jm/test/tags/pdf/Parallels.pdf");
List bm = SimpleBookmark.getBookmark(pr);
print.out(bm);
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
SimpleBookmark.exportToXML(bm, os, "UTF-8",false);
}
finally {
IOUtil.closeEL(os);
}
print.out("*********************************");
print.out(IOUtil.toString(os.toByteArray(), "UTF-8"));
}*/
public static Image toImage(byte[] input,int page) throws PageException, IOException {
return PDF2Image.getInstance().toImage(input, page);
}
public static void writeImages(byte[] input,Set pages,Resource outputDirectory, String prefix,
String format, int scale, boolean overwrite, boolean goodQuality,boolean transparent) throws PageException, IOException {
PDF2Image.getInstance().writeImages(input, pages, outputDirectory, prefix, format, scale, overwrite, goodQuality, transparent);
}
public static Object extractText(PDFDocument doc, Set<Integer> pageNumbers) throws IOException, CryptographyException, InvalidPasswordException {
PDDocument pdDoc = doc.toPDDocument();
//PDPageNode pages = pdDoc.getDocumentCatalog().getPages();
//pages.
//pdDoc.getDocumentCatalog().
/*Iterator<Integer> it = pageNumbers.iterator();
int p;
while(it.hasNext()){
p=it.next().intValue();
pdDoc.getDocumentCatalog().getPages()
}
*/
//print.o(pages);
//pdDoc.
//PDFTextStripperByArea stripper = new PDFTextStripperByArea();
//PDFHighlighter stripper = new PDFHighlighter();
PDFText2HTML stripper = new PDFText2HTML();
//PDFTextStripper stripper = new PDFTextStripper();
StringWriter writer = new StringWriter();
stripper.writeText(pdDoc, writer);
return writer.toString();
}
}