package railo.runtime.tag; import java.awt.Color; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map.Entry; import java.util.Set; import org.apache.oro.text.regex.MalformedPatternException; import org.pdfbox.exceptions.CryptographyException; import org.pdfbox.exceptions.InvalidPasswordException; import railo.commons.io.IOUtil; import railo.commons.io.res.Resource; import railo.commons.io.res.filter.ExtensionResourceFilter; import railo.commons.io.res.filter.ResourceFilter; import railo.commons.io.res.util.ResourceUtil; import railo.commons.io.res.util.WildCardFilter; import railo.commons.lang.StringUtil; import railo.runtime.exp.ApplicationException; import railo.runtime.exp.CasterException; import railo.runtime.exp.ExpressionException; import railo.runtime.exp.PageException; import railo.runtime.ext.tag.BodyTagImpl; import railo.runtime.op.Caster; import railo.runtime.op.Decision; import railo.runtime.text.pdf.PDFDocument; import railo.runtime.text.pdf.PDFUtil; import railo.runtime.type.Array; import railo.runtime.type.Collection.Key; import railo.runtime.type.Struct; import railo.runtime.type.util.KeyConstants; import railo.runtime.type.util.ListUtil; import com.lowagie.text.DocumentException; import com.lowagie.text.Image; import com.lowagie.text.pdf.PdfContentByte; import com.lowagie.text.pdf.PdfGState; import com.lowagie.text.pdf.PdfImportedPage; import com.lowagie.text.pdf.PdfReader; import com.lowagie.text.pdf.PdfStamper; import com.lowagie.text.pdf.PdfWriter; import com.lowagie.text.pdf.SimpleBookmark; public class PDF extends BodyTagImpl { private static final int ACTION_ADD_WATERMARK = 0; private static final int ACTION_DELETE_PAGES = 1; private static final int ACTION_GET_INFO = 2; private static final int ACTION_MERGE = 3; private static final int ACTION_PROCESSDDX = 5; private static final int ACTION_PROTECT = 5; private static final int ACTION_READ = 6; private static final int ACTION_REMOVE_WATERMARK = 7; private static final int ACTION_SET_INFO = 8; private static final int ACTION_THUMBNAIL = 9; private static final int ACTION_WRITE = 10; private static final int ACTION_EXTRACT_TEXT = 11; private static final String FORMAT_JPG ="jpg"; private static final String FORMAT_TIFF = "tiff"; private static final String FORMAT_PNG = "png"; private static final int ORDER_TIME = 0; private static final int ORDER_NAME = 1; private static final int RESOLUTION_HIGH = 0; private static final int RESOLUTION_LOW = 1; private static final int SAVE_OPTION_FULL = 0; private static final int SAVE_OPTION_INCREMENTAL = 1; private static final int SAVE_OPTION_LINEAR = 2; private static final int TYPE_STRING = 1; private static final int TYPE_XML = 2; private static final ExtensionResourceFilter PDF_FILTER = new ExtensionResourceFilter("pdf"); private static final int UNDEFINED = Integer.MIN_VALUE; private int action=ACTION_PROCESSDDX; private boolean ascending =false; private Object copyFrom=null; private String ddxFile=null; private Resource destination=null; private Resource directory=null; private int encrypt=PDFUtil.ENCRYPT_RC4_128; private boolean flatten=false; private boolean foreground=false; private String format=FORMAT_JPG; private Object image=null; private Struct info=null; private Struct inputFiles=null; private Struct outputFiles=null; private boolean isBase64=false; private boolean keepBookmark=false; private String name=null; private String newOwnerPassword=null; private String newUserPassword=null; private float opacity=0.3F; private int order=ORDER_TIME; private boolean overwrite=false; private String pages=null; private String password=null; private int permissions=0; private String position=null; private int resolution=RESOLUTION_HIGH; private float rotation=0; private int saveOption=SAVE_OPTION_FULL; private int scale=25; private boolean showOnPrint=false; private Object source =null; private boolean stopOnError=false; private boolean transparent=false; private char version=0; private java.util.List<PDFParamBean> params; private ResourceFilter filter=null; private String imagePrefix=null; private int type=TYPE_XML; @Override public void release() { super.release(); action=ACTION_PROCESSDDX; ascending =false; copyFrom=null; ddxFile=null; destination=null; directory=null; encrypt=PDFUtil.ENCRYPT_RC4_128; flatten=false; foreground=false; format=FORMAT_JPG; image=null; info=null; inputFiles=null; outputFiles=null; isBase64=false; keepBookmark=false; name=null; newOwnerPassword=null; newUserPassword=null; opacity=0.3F; order=ORDER_TIME; overwrite=false; pages=null; password=null; permissions=0; position=null; resolution=RESOLUTION_HIGH; rotation=0; saveOption=SAVE_OPTION_FULL; scale=25; showOnPrint=false; source =null; stopOnError=false; transparent=false; version=0; params=null; filter=null; imagePrefix=null; type=TYPE_XML; } /** * @param imagePrefix the imagePrefix to set */ public void setImageprefix(String imagePrefix) { this.imagePrefix = imagePrefix; } /** * @param action the action to set * @throws ApplicationException */ public void setAction(String strAction) throws ApplicationException { strAction=StringUtil.toLowerCase(strAction.trim()); if("addwatermark".equals(strAction)) action=ACTION_ADD_WATERMARK; else if("add-watermark".equals(strAction)) action=ACTION_ADD_WATERMARK; else if("add_watermark".equals(strAction)) action=ACTION_ADD_WATERMARK; else if("deletepages".equals(strAction)) action=ACTION_DELETE_PAGES; else if("delete-pages".equals(strAction)) action=ACTION_DELETE_PAGES; else if("delete_pages".equals(strAction)) action=ACTION_DELETE_PAGES; else if("deletepage".equals(strAction)) action=ACTION_DELETE_PAGES; else if("delete-page".equals(strAction)) action=ACTION_DELETE_PAGES; else if("delete_page".equals(strAction)) action=ACTION_DELETE_PAGES; else if("getinfo".equals(strAction)) action=ACTION_GET_INFO; else if("get-info".equals(strAction)) action=ACTION_GET_INFO; else if("get_info".equals(strAction)) action=ACTION_GET_INFO; else if("merge".equals(strAction)) action=ACTION_MERGE; //else if("processddx".equals(strAction)) action=ACTION_PROCESSDDX; //else if("process-ddx".equals(strAction)) action=ACTION_PROCESSDDX; //else if("process_ddx".equals(strAction)) action=ACTION_PROCESSDDX; else if("protect".equals(strAction)) action=ACTION_PROTECT; else if("read".equals(strAction)) action=ACTION_READ; else if("removewatermark".equals(strAction)) action=ACTION_REMOVE_WATERMARK; else if("removewater-mark".equals(strAction)) action=ACTION_REMOVE_WATERMARK; else if("removewater_mark".equals(strAction)) action=ACTION_REMOVE_WATERMARK; else if("setinfo".equals(strAction)) action=ACTION_SET_INFO; else if("set-info".equals(strAction)) action=ACTION_SET_INFO; else if("set_info".equals(strAction)) action=ACTION_SET_INFO; else if("thumbnail".equals(strAction)) action=ACTION_THUMBNAIL; else if("write".equals(strAction)) action=ACTION_WRITE; else if("extracttext".equals(strAction)) action=ACTION_EXTRACT_TEXT; else if("extract-text".equals(strAction)) action=ACTION_EXTRACT_TEXT; else if("extract_text".equals(strAction)) action=ACTION_EXTRACT_TEXT; else throw new ApplicationException("invalid action definition ["+strAction+"], valid actions definitions are " + "[addWatermark,deletePages,getInfo,merge,protect,read,removeWatermark,setInfo,thumbnail,write]"); } public void setType(String strType) throws ApplicationException { strType=StringUtil.toLowerCase(strType.trim()); if("string".equals(strType)) type=TYPE_STRING; else if("text".equals(strType)) type=TYPE_STRING; else if("plain".equals(strType)) type=TYPE_STRING; else if("xml".equals(strType)) type=TYPE_XML; else throw new ApplicationException("invalid type definition ["+strType+"], valid type definitions are " + "[string,xml]"); } /** * sets a filter pattern * @param pattern * @throws PageException **/ public void setFilter(String pattern) throws PageException { if(pattern.trim().length()>0) { try { this.filter=new WildCardFilter(pattern); } catch (MalformedPatternException e) { throw Caster.toPageException(e); } } } /** * @param ascending the ascending to set */ public void setAscending(boolean ascending) { this.ascending = ascending; } /** * @param copyFrom the copyFrom to set * @throws ExpressionException */ public void setCopyfrom(Object copyFrom) throws ExpressionException { this.copyFrom = copyFrom;//ResourceUtil.toResourceExisting(pageContext, copyFrom); } /** * @param ddxFile the ddxFile to set */ public void setDdxfile(String ddxFile) { this.ddxFile = ddxFile;// MUST } /** * @param destination the destination to set */ public void setDestination(String destination) { this.destination = ResourceUtil.toResourceNotExisting(pageContext, destination); } /** * @param directory the directory to set * @throws ExpressionException */ public void setDirectory(String directory) throws ExpressionException { this.directory = ResourceUtil.toResourceExisting(pageContext, directory); } /** * @param encrypt the encrypt to set * @throws ApplicationException */ public void setEncrypt(String strEncrypt) throws ApplicationException { strEncrypt=StringUtil.toLowerCase(strEncrypt.trim()); if("aes128".equals(strEncrypt)) encrypt=PDFUtil.ENCRYPT_AES_128; else if("aes-128".equals(strEncrypt)) encrypt=PDFUtil.ENCRYPT_AES_128; else if("aes_128".equals(strEncrypt)) encrypt=PDFUtil.ENCRYPT_AES_128; else if("none".equals(strEncrypt)) encrypt=PDFUtil.ENCRYPT_NONE; else if("".equals(strEncrypt)) encrypt=PDFUtil.ENCRYPT_NONE; else if("rc4128".equals(strEncrypt)) encrypt=PDFUtil.ENCRYPT_RC4_128; else if("rc4-128".equals(strEncrypt)) encrypt=PDFUtil.ENCRYPT_RC4_128; else if("rc4_128".equals(strEncrypt)) encrypt=PDFUtil.ENCRYPT_RC4_128; else if("rc4128m".equals(strEncrypt)) encrypt=PDFUtil.ENCRYPT_RC4_128M; else if("rc4-128m".equals(strEncrypt)) encrypt=PDFUtil.ENCRYPT_RC4_128M; else if("rc4_128m".equals(strEncrypt)) encrypt=PDFUtil.ENCRYPT_RC4_128M; else if("rc440".equals(strEncrypt)) encrypt=PDFUtil.ENCRYPT_RC4_40; else if("rc4-40".equals(strEncrypt)) encrypt=PDFUtil.ENCRYPT_RC4_40; else if("rc4_40".equals(strEncrypt)) encrypt=PDFUtil.ENCRYPT_RC4_40; else throw new ApplicationException("invalid encrypt definition ["+strEncrypt+"], valid encrypt definitions are " + "[aes_128,none,rc4_128,rc4_128m,rc4_40]"); } /** * @param flatten the flatten to set */ public void setFlatten(boolean flatten) { this.flatten = flatten; } /** * @param foreground the foreground to set */ public void setForeground(boolean foreground) { this.foreground = foreground; } /** * @param format the format to set * @throws ApplicationException */ public void setFormat(String strFormat) throws ApplicationException { strFormat=StringUtil.toLowerCase(strFormat.trim()); if("jpg".equals(strFormat)) format=FORMAT_JPG; else if("jpeg".equals(strFormat)) format=FORMAT_JPG; else if("jpe".equals(strFormat)) format=FORMAT_JPG; else if("tiff".equals(strFormat)) format=FORMAT_TIFF; else if("tif".equals(strFormat)) format=FORMAT_TIFF; else if("png".equals(strFormat)) format=FORMAT_PNG; else throw new ApplicationException("invalid format definition ["+strFormat+"], valid format definitions are " + "[jpg,tiff,png]"); } /** * @param image the image to set */ public void setImage(Object image) { this.image = image;// MUST } /** * @param prefix the prefix to set */ public void setPrefix(String prefix) { this.imagePrefix = prefix; } /** * @param info the info to set */ public void setInfo(Struct info) { this.info = info; } /** * @param inputFiles the inputFiles to set */ public void setInputfiles(Struct inputFiles) { this.inputFiles = inputFiles; } /** * @param outputFiles the outputFiles to set */ public void setOutputfiles(Struct outputFiles) { this.outputFiles = outputFiles; } /** * @param isBase64 the isBase64 to set */ public void setIsbase64(boolean isBase64) { this.isBase64 = isBase64; } /** * @param keepBookmark the keepBookmark to set */ public void setKeepbookmark(boolean keepBookmark) { this.keepBookmark = keepBookmark; } /** * @param name the name to set */ public void setName(String name) { this.name = name; } /** * @param newOwnerPassword the newOwnerPassword to set */ public void setNewownerpassword(String newOwnerPassword) { this.newOwnerPassword = newOwnerPassword; } /** * @param newUserPassword the newUserPassword to set */ public void setNewuserpassword(String newUserPassword) { this.newUserPassword = newUserPassword; } /** * @param opacity the opacity to set * @throws ApplicationException */ public void setOpacity(double opacity) throws ApplicationException { if(opacity<0 || opacity>10) throw new ApplicationException("invalid opacity definition ["+Caster.toString(opacity)+"], value should be in range from 0 to 10"); this.opacity = (float) (opacity/10); } /** * @param order the order to set * @throws ApplicationException */ public void setOrder(String strOrder) throws ApplicationException { strOrder=StringUtil.toLowerCase(strOrder.trim()); if("name".equals(strOrder)) order=ORDER_NAME; else if("time".equals(strOrder)) order=ORDER_TIME; else throw new ApplicationException("invalid order definition ["+strOrder+"], valid order definitions are " + "[name,time]"); } /** * @param overwrite the overwrite to set */ public void setOverwrite(boolean overwrite) { this.overwrite = overwrite; } /** * @param pages the pages to set */ public void setPages(String pages) { this.pages = pages; } /** * @param password the password to set */ public void setPassword(String password) { this.password = password; } /** * @param permissions the permissions to set * @throws PageException */ public void setPermissions(String strPermissions) throws PageException { permissions=PDFUtil.toPermissions(strPermissions); } /** * @param position the position to set */ public void setPosition(String position) { this.position = position;//MUST } /** * @param resolution the resolution to set * @throws ApplicationException */ public void setResolution(String strResolution) throws ApplicationException { strResolution=StringUtil.toLowerCase(strResolution.trim()); if("low".equals(strResolution)) resolution=RESOLUTION_LOW; else if("high".equals(strResolution)) resolution=RESOLUTION_HIGH; else throw new ApplicationException("invalid resolution definition ["+strResolution+"], valid resolution definitions are " + "[low,high]"); } /** * @param rotation the rotation to set */ public void setRotation(double rotation) { rotation=rotation%360D; //rotation=rotation/360*6.28318525; this.rotation = (float) rotation; } /** * @param saveOption the saveOption to set * @throws ApplicationException */ public void setSaveoption(String strSaveOption) throws ApplicationException { strSaveOption=StringUtil.toLowerCase(strSaveOption.trim()); if("full".equals(strSaveOption)) saveOption=SAVE_OPTION_FULL; else if("incremental".equals(strSaveOption))saveOption=SAVE_OPTION_INCREMENTAL; else if("linear".equals(strSaveOption)) saveOption=SAVE_OPTION_LINEAR; else throw new ApplicationException("invalid saveOption definition ["+strSaveOption+"], valid saveOption definitions are " + "[full,linear,incremental]"); } /** * @param scale the scale to set * @throws ApplicationException */ public void setScale(double scale) throws ApplicationException { //if(scale<1 || scale>1000) this check is now done inside PDF2IMage implementation // throw new ApplicationException("invalid scale definition ["+Caster.toString(scale)+"], value should be in range from 1 to 100"); this.scale = (int) scale; } /** * @param showOnPrint the showOnPrint to set */ public void setShowonprint(boolean showOnPrint) { this.showOnPrint = showOnPrint; } /** * @param source the source to set */ public void setSource(Object source) { this.source = source; } /** * @param stopOnError the stopOnError to set */ public void setStoponerror(boolean stopOnError) { this.stopOnError = stopOnError; } /** * @param transparent the transparent to set */ public void setTransparent(boolean transparent) { this.transparent = transparent; } /** * @param version the version to set * @throws ApplicationException */ public void setVersion(double version) throws ApplicationException { if(1.1 == version) this.version='1'; else if(1.2 == version) this.version=PdfWriter.VERSION_1_2; else if(1.3 == version) this.version=PdfWriter.VERSION_1_3; else if(1.4 == version) this.version=PdfWriter.VERSION_1_4; else if(1.5 == version) this.version=PdfWriter.VERSION_1_5; else if(1.6 == version) this.version=PdfWriter.VERSION_1_6; else throw new ApplicationException("invalid version definition ["+Caster.toString(version)+"], valid version definitions are " + "[1.1, 1.2, 1.3, 1.4, 1.5, 1.6]"); } @Override public int doStartTag() throws PageException { // RR SerialNumber sn = pageContext.getConfig().getSerialNumber(); //if(sn.getVersion()==SerialNumber.VERSION_COMMUNITY) // throw new SecurityException("no access to this functionality with the "+sn.getStringVersion()+" version of railo"); return EVAL_BODY_BUFFERED; } @Override public void doInitBody() { } @Override public int doAfterBody() { return SKIP_BODY; } @Override public int doEndTag() throws PageException { try { if(ACTION_ADD_WATERMARK==action) doActionAddWatermark(); else if(ACTION_REMOVE_WATERMARK==action) doActionRemoveWatermark(); else if(ACTION_READ==action) doActionRead(); else if(ACTION_WRITE==action) doActionWrite(); else if(ACTION_GET_INFO==action) doActionGetInfo(); else if(ACTION_SET_INFO==action) doActionSetInfo(); else if(ACTION_MERGE==action) doActionMerge(); else if(ACTION_DELETE_PAGES==action) doActionDeletePages(); else if(ACTION_PROTECT==action) doActionProtect(); else if(ACTION_THUMBNAIL==action) doActionThumbnail(); else if(ACTION_EXTRACT_TEXT==action) { if(true)throw new ApplicationException("not supported yet, see https://issues.jboss.org/browse/RAILO-1559"); doActionExtractText(); } //else if(ACTION_PROCESSDDX==action) throw new ApplicationException("action [processddx] not supported"); } catch (Exception e) { throw Caster.toPageException(e); } return EVAL_PAGE; } private void doActionWrite() throws PageException, IOException, DocumentException { required("pdf", "write", "source", source); required("pdf", "write", "destination", destination); if(destination.exists() && !overwrite) throw new ApplicationException("destination file ["+destination+"] already exists"); PDFDocument doc = toPDFDocument(source, password, null); //PdfReader pr = doc.getPdfReader(); // output boolean destIsSource = doc.getResource()!=null && destination.equals(doc.getResource()); OutputStream os=null; if(destIsSource){ os=new ByteArrayOutputStream(); } else if(destination!=null) { os=destination.getOutputStream(); } try { PDFUtil.concat(new PDFDocument[]{doc}, os, true, true, true,version); } finally { IOUtil.closeEL(os); if(os instanceof ByteArrayOutputStream) { if(destination!=null)IOUtil.copy(new ByteArrayInputStream(((ByteArrayOutputStream)os).toByteArray()), destination,true);// MUST overwrite } } /* // flatten = "yes|no" // must saveOption = "linear|incremental|full" */ } private void doActionThumbnail() throws PageException, IOException, DocumentException { required("pdf", "thumbnail", "source", source); PDFDocument doc = toPDFDocument(source, password, null); PdfReader pr = doc.getPdfReader(); boolean isEnc=pr.isEncrypted(); pr.close(); if(isEnc) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); //PDFUtil.concat(new PDFDocument[]{doc}, baos, true, true, true, (char)0); PDFUtil.encrypt(doc,baos,null,null,0,PDFUtil.ENCRYPT_NONE); baos.close(); doc = new PDFDocument(baos.toByteArray(),doc.getResource(),null); } doc.setPages(pages); // scale if(scale<1) throw new ApplicationException("value of attribute scale ["+scale+"] should be at least 1"); // destination if(destination==null) destination=ResourceUtil.toResourceNotExisting(pageContext, "thumbnails"); // imagePrefix if(imagePrefix==null){ Resource res = doc.getResource(); if(res!=null){ String n = res.getName(); int index=n.lastIndexOf('.'); if(index!=-1)imagePrefix=n.substring(0,index); else imagePrefix=n; } else imagePrefix="memory"; } // MUST password PDFUtil.writeImages(doc.getRaw(), doc.getPages(), destination, imagePrefix, format, scale,overwrite, resolution==RESOLUTION_HIGH,transparent); } private void doActionAddWatermark() throws PageException, IOException, DocumentException { required("pdf", "addWatermark", "source", source); if(copyFrom==null && image==null) throw new ApplicationException("at least one of the following attributes must be defined " + "[copyFrom,image]"); if(destination!=null && destination.exists() && !overwrite) throw new ApplicationException("destination file ["+destination+"] already exists"); // image Image img=null; if(image!=null) { railo.runtime.img.Image ri = railo.runtime.img.Image.createImage(pageContext,image,false,false,true,null); img=Image.getInstance(ri.getBufferedImage(),null,false); } // copy From else { byte[] barr; try{ Resource res = Caster.toResource(pageContext, copyFrom, true); barr=IOUtil.toBytes(res); } catch(ExpressionException ee) { barr=Caster.toBinary(copyFrom); } img=Image.getInstance(PDFUtil.toImage(barr, 1).getBufferedImage(),null,false); } // position float x=UNDEFINED,y=UNDEFINED; if(!StringUtil.isEmpty(position)) { int index=position.indexOf(','); if(index==-1) throw new ApplicationException("attribute [position] has an invalid value ["+position+"]," + "value should follow one of the following pattern [40,50], [40,] or [,50]"); String strX = position.substring(0,index).trim(); String strY = position.substring(index+1).trim(); if(!StringUtil.isEmpty(strX))x = Caster.toIntValue(strX); if(!StringUtil.isEmpty(strY))y = Caster.toIntValue(strY); } PDFDocument doc = toPDFDocument(source, password, null); doc.setPages(pages); PdfReader reader = doc.getPdfReader(); reader.consolidateNamedDestinations(); boolean destIsSource = destination!=null && doc.getResource()!=null && destination.equals(doc.getResource()); java.util.List bookmarks = SimpleBookmark.getBookmark(reader); ArrayList master = new ArrayList(); if(bookmarks!=null)master.addAll(bookmarks); // output OutputStream os=null; if(!StringUtil.isEmpty(name) || destIsSource){ os=new ByteArrayOutputStream(); } else if(destination!=null) { os=destination.getOutputStream(); } try { int len = reader.getNumberOfPages(); PdfStamper stamp = new PdfStamper(reader, os); if(len >0){ if(x==UNDEFINED || y==UNDEFINED) { PdfImportedPage first = stamp.getImportedPage(reader, 1); if(y==UNDEFINED)y=(first.getHeight()-img.getHeight())/2; if(x==UNDEFINED)x=(first.getWidth()-img.getWidth())/2; } img.setAbsolutePosition(x, y); //img.setAlignment(Image.ALIGN_JUSTIFIED); ration geht nicht anhand mitte } // rotation if(rotation!=0) { img.setRotationDegrees(rotation); } Set _pages = doc.getPages(); for (int i=1;i<=len;i++) { if(_pages!=null && !_pages.contains(Integer.valueOf(i))) continue; PdfContentByte cb =foreground? stamp.getOverContent(i):stamp.getUnderContent(i); PdfGState gs1 = new PdfGState(); //print.out("op:"+opacity); gs1.setFillOpacity(opacity); //gs1.setStrokeOpacity(opacity); cb.setGState(gs1); cb.addImage(img); } if(bookmarks!=null)stamp.setOutlines(master); stamp.close(); } finally { IOUtil.closeEL(os); if(os instanceof ByteArrayOutputStream) { if(destination!=null)IOUtil.copy(new ByteArrayInputStream(((ByteArrayOutputStream)os).toByteArray()), destination,true);// MUST overwrite if(!StringUtil.isEmpty(name)){ pageContext.setVariable(name,new PDFDocument(((ByteArrayOutputStream)os).toByteArray(),password)); } } } } private void doActionRemoveWatermark() throws PageException, IOException, DocumentException { required("pdf", "removeWatermark", "source", source); if(destination!=null && destination.exists() && !overwrite) throw new ApplicationException("destination file ["+destination+"] already exists"); railo.runtime.img.Image ri = new railo.runtime.img.Image(1,1,BufferedImage.TYPE_INT_RGB,Color.BLACK); Image img = Image.getInstance(ri.getBufferedImage(),null,false); img.setAbsolutePosition(1,1); PDFDocument doc = toPDFDocument(source, password, null); doc.setPages(pages); PdfReader reader = doc.getPdfReader(); boolean destIsSource = destination!=null && doc.getResource()!=null && destination.equals(doc.getResource()); java.util.List bookmarks = SimpleBookmark.getBookmark(reader); ArrayList master = new ArrayList(); if(bookmarks!=null)master.addAll(bookmarks); // output OutputStream os=null; if(!StringUtil.isEmpty(name) || destIsSource){ os=new ByteArrayOutputStream(); } else if(destination!=null) { os=destination.getOutputStream(); } try { int len = reader.getNumberOfPages(); PdfStamper stamp = new PdfStamper(reader, os); Set _pages = doc.getPages(); for (int i=1;i<=len;i++) { if(_pages!=null && !_pages.contains(Integer.valueOf(i))) continue; PdfContentByte cb =foreground? stamp.getOverContent(i):stamp.getUnderContent(i); PdfGState gs1 = new PdfGState(); gs1.setFillOpacity(0); cb.setGState(gs1); cb.addImage(img); } if(bookmarks!=null)stamp.setOutlines(master); stamp.close(); } finally { IOUtil.closeEL(os); if(os instanceof ByteArrayOutputStream) { if(destination!=null)IOUtil.copy(new ByteArrayInputStream(((ByteArrayOutputStream)os).toByteArray()), destination,true);// MUST overwrite if(!StringUtil.isEmpty(name)){ pageContext.setVariable(name,new PDFDocument(((ByteArrayOutputStream)os).toByteArray(),password)); } } } } private void doActionDeletePages() throws PageException, IOException, DocumentException { required("pdf", "deletePage", "pages", pages,true); required("pdf", "deletePage", "source", source); PDFDocument doc = toPDFDocument(source, password, null); doc.setPages(pages); if(destination==null && StringUtil.isEmpty(name)){ if(doc.getResource()==null) throw new ApplicationException("source is not based on a resource, destination attribute is required"); destination=doc.getResource(); } else if(destination!=null && destination.exists() && !overwrite) throw new ApplicationException("destination file ["+destination+"] already exists"); boolean destIsSource = destination!=null && doc.getResource()!=null && destination.equals(doc.getResource()); // output OutputStream os=null; if(!StringUtil.isEmpty(name) || destIsSource){ os=new ByteArrayOutputStream(); } else if(destination!=null) { os=destination.getOutputStream(); } try { PDFUtil.concat(new PDFDocument[]{doc}, os, true, true,true,version); } finally { //if(document!=null)document.close(); IOUtil.closeEL(os); if(os instanceof ByteArrayOutputStream) { if(destination!=null)IOUtil.copy(new ByteArrayInputStream(((ByteArrayOutputStream)os).toByteArray()), destination,true);// MUST overwrite if(!StringUtil.isEmpty(name)){ pageContext.setVariable(name,new PDFDocument(((ByteArrayOutputStream)os).toByteArray(),password)); } } } } private void doActionMerge() throws ApplicationException, PageException, IOException, DocumentException { if(source==null && params==null && directory==null) throw new ApplicationException("at least one of the following constellation must be defined" + " attribute source, attribute directory or cfpdfparam child tags"); if(destination==null && StringUtil.isEmpty(name,true)) throw new ApplicationException("at least one of the following attributes must be defined " + "[destination,name]"); if(destination!=null && !overwrite) throw new ApplicationException("destination file ["+destination+"] already exists"); ArrayList docs = new ArrayList(); PDFDocument doc; boolean isListing=false; // source if(source!=null) { if(Decision.isArray(source)) { Array arr = Caster.toArray(source); int len = arr.size(); for(int i=1;i<=len;i++) { docs.add(doc=toPDFDocument(arr.getE(i),password,null)); doc.setPages(pages); } } else if(source instanceof String) { String[] sources = ListUtil.toStringArrayTrim(ListUtil.listToArrayRemoveEmpty((String)source, ',')); for(int i=0;i<sources.length;i++) { docs.add(doc=toPDFDocument(sources[i],password,null)); doc.setPages(pages); } } else docs.add(toPDFDocument(source,password,null)); } boolean destIsSource = false; // params if(directory!=null && !directory.isDirectory()) { if(!directory.exists()) throw new ApplicationException("defined attribute directory does not exist"); throw new ApplicationException("defined attribute directory is not a directory"); } if(params!=null) { Iterator it = params.iterator(); PDFParamBean param; while(it.hasNext()) { param=(PDFParamBean) it.next(); docs.add(doc=toPDFDocument(param.getSource(), param.getPassword(),directory)); doc.setPages(param.getPages()); } } else if(directory!=null) { isListing=true; Resource[] children = ResourceUtil.listResources(directory, filter); if(ascending) { for(int i=children.length-1;i>=0;i--) { if(destination!=null && children[i].equals(destination)) destIsSource=true; docs.add(doc=toPDFDocument(children[i],password,null)); doc.setPages(pages); } } else { for(int i=0;i<children.length;i++) { if(destination!=null && children[i].equals(destination)) destIsSource=true; docs.add(doc=toPDFDocument(children[i],password,null)); doc.setPages(pages); } } } int doclen=docs.size(); if(doclen==0) throw new ApplicationException("you have to define at leat 1 pdf file"); // output OutputStream os=null; if(!StringUtil.isEmpty(name) || destIsSource){ os=new ByteArrayOutputStream(); } else if(destination!=null) { os=destination.getOutputStream(); } /*com.lowagie.text.Document document=null; PdfCopy copy=null; PdfReader pr; Set pages; int size;*/ try { if(!isListing)stopOnError=true; PDFUtil.concat((PDFDocument[]) docs.toArray(new PDFDocument[docs.size()]), os, keepBookmark, false,stopOnError,version); /* boolean init=false; for(int d=0;d<doclen;d++) { doc=(PDFDocument) docs.get(d); pages=doc.getPages(); try { pr=doc.getPdfReader(); print.out(pr.getCatalog().getKeys()); } catch(Throwable t) { if(isListing && !stopOnError)continue; throw Caster.toPageException(t); } print.out("d+"+d); if(!init) { init=true; print.out("set"); document = new com.lowagie.text.Document(pr.getPageSizeWithRotation(1)); copy = new PdfCopy(document,os); document.open(); } size=pr.getNumberOfPages(); print.out("pages:"+size); for(int page=1;page<=size;page++) { if(pages==null || pages.contains(Constants.Integer(page))) { copy.addPage(copy.getImportedPage(pr, page)); } } }*/ } finally { //if(document!=null)document.close(); IOUtil.closeEL(os); if(os instanceof ByteArrayOutputStream) { if(destination!=null)IOUtil.copy(new ByteArrayInputStream(((ByteArrayOutputStream)os).toByteArray()), destination,true);// MUST overwrite if(!StringUtil.isEmpty(name))pageContext.setVariable(name, ((ByteArrayOutputStream)os).toByteArray()); } } } private void doActionRead() throws PageException { required("pdf", "read", "name", name,true); required("pdf", "read", "source", source); pageContext.setVariable(name, toPDFDocument(source,password,null)); } private void doActionProtect() throws PageException, IOException, DocumentException { required("pdf", "protect", "source", source); if(StringUtil.isEmpty(newUserPassword) && StringUtil.isEmpty(newOwnerPassword)) throw new ApplicationException("at least one of the following attributes must be defined [newUserPassword,newOwnerPassword]"); PDFDocument doc = toPDFDocument(source,password,null); if(destination==null){ destination=doc.getResource(); if(destination==null) throw new ApplicationException("source is not based on a resource, destination file is required"); } else if(destination.exists() && !overwrite) throw new ApplicationException("destination file ["+destination+"] already exists"); boolean destIsSource = doc.getResource()!=null && destination.equals(doc.getResource()); // output OutputStream os=null; if(destIsSource){ os=new ByteArrayOutputStream(); } else { os=destination.getOutputStream(); } try{ PDFUtil.encrypt(doc,os,newUserPassword,newOwnerPassword,permissions,encrypt); } finally { IOUtil.closeEL(os); if(os instanceof ByteArrayOutputStream) { IOUtil.copy(new ByteArrayInputStream(((ByteArrayOutputStream)os).toByteArray()), destination,true);// MUST overwrite } } } private void doActionSetInfo() throws PageException, IOException, DocumentException { required("pdf", "setInfo", "info", info); required("pdf", "getInfo", "source", source); PDFDocument doc = toPDFDocument(source,password,null); PdfReader pr = doc.getPdfReader(); OutputStream os=null; try { if(destination==null){ if(doc.getResource()==null) throw new ApplicationException("source is not based on a resource, destination file is required"); destination=doc.getResource(); } else if(destination.exists() && !overwrite) throw new ApplicationException("destination file ["+destination+"] already exists"); PdfStamper stamp = new PdfStamper(pr, os=destination.getOutputStream()); HashMap moreInfo = new HashMap(); //Key[] keys = info.keys(); Iterator<Entry<Key, Object>> it = info.entryIterator(); Entry<Key, Object> e; while(it.hasNext()) { e = it.next(); moreInfo.put(StringUtil.ucFirst(e.getKey().getLowerString()), Caster.toString(e.getValue())); } // author Object value = info.get(KeyConstants._author, null); if(value!=null)moreInfo.put("Author", Caster.toString(value)); // keywords value = info.get("keywords", null); if(value!=null)moreInfo.put("Keywords", Caster.toString(value)); // title value = info.get(KeyConstants._title, null); if(value!=null)moreInfo.put("Title", Caster.toString(value)); // subject value = info.get(KeyConstants._subject, null); if(value!=null)moreInfo.put("Subject", Caster.toString(value)); // creator value = info.get("creator", null); if(value!=null)moreInfo.put("Creator", Caster.toString(value)); // trapped value = info.get("Trapped", null); if(value!=null)moreInfo.put("Trapped", Caster.toString(value)); // Created value = info.get("Created", null); if(value!=null)moreInfo.put("Created", Caster.toString(value)); // Language value = info.get("Language", null); if(value!=null)moreInfo.put("Language", Caster.toString(value)); stamp.setMoreInfo(moreInfo); stamp.close(); } finally { IOUtil.closeEL(os); pr.close(); } } private void doActionGetInfo() throws PageException { required("pdf", "getInfo", "name", name,true); required("pdf", "getInfo", "source", source); PDFDocument doc = toPDFDocument(source,password,null); pageContext.setVariable(name, doc.getInfo()); } private void doActionExtractText() throws PageException, IOException, CryptographyException, InvalidPasswordException { required("pdf", "extractText", "name", name,true); PDFDocument doc = toPDFDocument(source,password,null); doc.setPages(pages); pageContext.setVariable(name, PDFUtil.extractText(doc,doc.getPages())); /* <cfpdf required action="extracttext" <!---extract all the words in the PDF.---> ***source= "absolute or relative path of the PDF file|PDF document variable| cfdocument variable" pages = "*" <!----page numbers from where the text needs to be extracted from the PDF document---> optional addquads = "add the position or quadrants for the text in the PDF" honourspaces = "true|false" overwrite = "true" <!---Overwrite the specified object in the PDF document---> ***password = "" <!--- PDF document password---> type = "string|xml" <!---format in which the text needs to be extracted---> one of the following: destination = "PDF output file pathname" name = "PDF document variable" usestructure = "true|false" * */ } private Object allowed(boolean encrypted, int permissions, int permission) { return (!encrypted || (permissions&permission)>0)?"Allowed":"Not Allowed"; } private PDFDocument toPDFDocument(Object source,String password, Resource directory) throws PageException { if(source instanceof PDFDocument) return (PDFDocument)source; if(Decision.isBinary(source)){ return new PDFDocument(Caster.toBinary(source),password); } if(source instanceof Resource){ return new PDFDocument((Resource) source,password); } if(source instanceof String){ if(directory!=null) { Resource res = directory.getRealResource((String)source); if(!res.isFile()){ Resource res2 = ResourceUtil.toResourceNotExisting(pageContext, (String)source); if(res2.isFile()) res=res2; else throw new ExpressionException("file or directory "+res+" not exist"); } return new PDFDocument(res,password); } return new PDFDocument(ResourceUtil.toResourceExisting(pageContext, (String)source),password); } throw new CasterException(source,PdfReader.class); } /*private byte[] toBinary(Object source) throws ExpressionException, IOException { if(source instanceof PDFDocument) return toBinary(((PDFDocument)source).getResource()); if(Decision.isBinary(source)){ return Caster.toBinary(source); } if(source instanceof Resource){ return IOUtil.toBytes((Resource)source); } if(source instanceof String){ if(directory!=null) { Resource res = directory.getRealResource((String)source); if(!res.isFile()){ Resource res2 = ResourceUtil.toResourceNotExisting(pageContext, (String)source); if(res2.isFile()) res=res2; else throw new ExpressionException("file or directory "+res+" not exist"); } return IOUtil.toBytes(res); } return IOUtil.toBytes(ResourceUtil.toResourceExisting(pageContext, (String)source)); } throw new CasterException(source,PdfReader.class); }*/ protected void setParam(PDFParamBean param) { if(params==null) params=new ArrayList<PDFParamBean>(); params.add(param); } }