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);
}
}