001    package railo.runtime.tag;
002    
003    import java.awt.Color;
004    import java.awt.image.BufferedImage;
005    import java.io.ByteArrayInputStream;
006    import java.io.ByteArrayOutputStream;
007    import java.io.IOException;
008    import java.io.OutputStream;
009    import java.util.ArrayList;
010    import java.util.HashMap;
011    import java.util.Iterator;
012    import java.util.Map.Entry;
013    import java.util.Set;
014    
015    import org.apache.oro.text.regex.MalformedPatternException;
016    import org.pdfbox.exceptions.CryptographyException;
017    import org.pdfbox.exceptions.InvalidPasswordException;
018    
019    import railo.commons.io.IOUtil;
020    import railo.commons.io.res.Resource;
021    import railo.commons.io.res.filter.ExtensionResourceFilter;
022    import railo.commons.io.res.filter.ResourceFilter;
023    import railo.commons.io.res.util.ResourceUtil;
024    import railo.commons.io.res.util.WildCardFilter;
025    import railo.commons.lang.StringUtil;
026    import railo.runtime.exp.ApplicationException;
027    import railo.runtime.exp.CasterException;
028    import railo.runtime.exp.ExpressionException;
029    import railo.runtime.exp.PageException;
030    import railo.runtime.ext.tag.BodyTagImpl;
031    import railo.runtime.op.Caster;
032    import railo.runtime.op.Decision;
033    import railo.runtime.text.pdf.PDFDocument;
034    import railo.runtime.text.pdf.PDFUtil;
035    import railo.runtime.type.Array;
036    import railo.runtime.type.Collection.Key;
037    import railo.runtime.type.Struct;
038    import railo.runtime.type.util.KeyConstants;
039    import railo.runtime.type.util.ListUtil;
040    
041    import com.lowagie.text.DocumentException;
042    import com.lowagie.text.Image;
043    import com.lowagie.text.pdf.PdfContentByte;
044    import com.lowagie.text.pdf.PdfGState;
045    import com.lowagie.text.pdf.PdfImportedPage;
046    import com.lowagie.text.pdf.PdfReader;
047    import com.lowagie.text.pdf.PdfStamper;
048    import com.lowagie.text.pdf.PdfWriter;
049    import com.lowagie.text.pdf.SimpleBookmark;
050    
051    public class PDF extends BodyTagImpl  {
052    
053            private static final int ACTION_ADD_WATERMARK = 0;
054            private static final int ACTION_DELETE_PAGES = 1;
055            private static final int ACTION_GET_INFO = 2;
056            private static final int ACTION_MERGE = 3;
057            private static final int ACTION_PROCESSDDX = 5;
058            private static final int ACTION_PROTECT = 5;
059            private static final int ACTION_READ = 6;
060            private static final int ACTION_REMOVE_WATERMARK = 7;
061            private static final int ACTION_SET_INFO = 8;
062            private static final int ACTION_THUMBNAIL = 9;
063            private static final int ACTION_WRITE = 10;
064            private static final int ACTION_EXTRACT_TEXT = 11;
065    
066            
067            private static final String FORMAT_JPG ="jpg";
068            private static final String FORMAT_TIFF = "tiff";
069            private static final String FORMAT_PNG = "png";
070            
071            private static final int ORDER_TIME = 0;
072            private static final int ORDER_NAME = 1;
073            
074            private static final int RESOLUTION_HIGH = 0;
075            private static final int RESOLUTION_LOW = 1;
076    
077            private static final int SAVE_OPTION_FULL = 0;
078            private static final int SAVE_OPTION_INCREMENTAL = 1;
079            private static final int SAVE_OPTION_LINEAR = 2;
080            
081            private static final int TYPE_STRING = 1;
082            private static final int TYPE_XML = 2;
083        
084            
085            private static final ExtensionResourceFilter PDF_FILTER = new ExtensionResourceFilter("pdf");
086            private static final int UNDEFINED = Integer.MIN_VALUE;
087            
088            
089            
090            private int action=ACTION_PROCESSDDX;
091            private boolean ascending =false;
092            private Object copyFrom=null;
093            private String ddxFile=null;
094            private Resource destination=null;
095            private Resource directory=null;
096            private int encrypt=PDFUtil.ENCRYPT_RC4_128;
097            private boolean flatten=false;
098            private boolean foreground=false;
099            private String format=FORMAT_JPG;
100            private Object image=null;
101            private Struct info=null;
102            private Struct inputFiles=null;
103            private Struct outputFiles=null;
104            private boolean isBase64=false;
105            private boolean keepBookmark=false;
106            private String name=null;
107            private String newOwnerPassword=null;
108            private String newUserPassword=null;
109            private float opacity=0.3F;
110            private int order=ORDER_TIME;
111            private boolean overwrite=false;
112            private String pages=null;
113            private String password=null;
114            private int permissions=0;
115            private String position=null;
116            private int resolution=RESOLUTION_HIGH;
117            private float rotation=0;
118            private int saveOption=SAVE_OPTION_FULL;
119            private int scale=25;
120            private boolean showOnPrint=false;
121            private Object source =null;
122            private boolean stopOnError=false;
123            private boolean transparent=false;
124            private char version=0;
125            private java.util.List<PDFParamBean> params;
126            private ResourceFilter filter=null;
127            private String imagePrefix=null;
128            private int type=TYPE_XML;
129            
130            @Override
131            public void release() {
132                    super.release();
133                    action=ACTION_PROCESSDDX;
134                    ascending =false;
135                    copyFrom=null;
136                    ddxFile=null;
137                    destination=null;
138                    directory=null;
139                    encrypt=PDFUtil.ENCRYPT_RC4_128;
140                    flatten=false;
141                    foreground=false;
142                    format=FORMAT_JPG;
143                    image=null;
144                    info=null;
145                    inputFiles=null;
146                    outputFiles=null;
147                    isBase64=false;
148                    keepBookmark=false;
149                    name=null;
150                    newOwnerPassword=null;
151                    newUserPassword=null;
152                    opacity=0.3F;
153                    order=ORDER_TIME;
154                    overwrite=false;
155                    pages=null;
156                    password=null;
157                    permissions=0;
158                    position=null;
159                    resolution=RESOLUTION_HIGH;
160                    rotation=0;
161                    saveOption=SAVE_OPTION_FULL;
162                    scale=25;
163                    showOnPrint=false;
164                    source =null;
165                    stopOnError=false;
166                    transparent=false;
167                    version=0;
168                    params=null;
169                    filter=null;
170                    imagePrefix=null;
171                    type=TYPE_XML;
172            }
173            
174            
175            
176            /**
177             * @param imagePrefix the imagePrefix to set
178             */
179            public void setImageprefix(String imagePrefix) {
180                    this.imagePrefix = imagePrefix;
181            }
182    
183    
184    
185            /**
186             * @param action the action to set
187             * @throws ApplicationException 
188             */
189            public void setAction(String strAction) throws ApplicationException {
190                    
191                    strAction=StringUtil.toLowerCase(strAction.trim());
192                    if("addwatermark".equals(strAction))                            action=ACTION_ADD_WATERMARK;
193                    else if("add-watermark".equals(strAction))                      action=ACTION_ADD_WATERMARK;
194                    else if("add_watermark".equals(strAction))                      action=ACTION_ADD_WATERMARK;
195                    else if("deletepages".equals(strAction))                        action=ACTION_DELETE_PAGES;
196                    else if("delete-pages".equals(strAction))                       action=ACTION_DELETE_PAGES;
197                    else if("delete_pages".equals(strAction))                       action=ACTION_DELETE_PAGES;
198                    else if("deletepage".equals(strAction))                         action=ACTION_DELETE_PAGES;
199                    else if("delete-page".equals(strAction))                        action=ACTION_DELETE_PAGES;
200                    else if("delete_page".equals(strAction))                        action=ACTION_DELETE_PAGES;
201                    else if("getinfo".equals(strAction))                            action=ACTION_GET_INFO;
202                    else if("get-info".equals(strAction))                           action=ACTION_GET_INFO;
203                    else if("get_info".equals(strAction))                           action=ACTION_GET_INFO;
204                    else if("merge".equals(strAction))                                      action=ACTION_MERGE;
205                    //else if("processddx".equals(strAction))                               action=ACTION_PROCESSDDX;
206                    //else if("process-ddx".equals(strAction))                      action=ACTION_PROCESSDDX;
207                    //else if("process_ddx".equals(strAction))                      action=ACTION_PROCESSDDX;
208                    else if("protect".equals(strAction))                            action=ACTION_PROTECT;
209                    else if("read".equals(strAction))                                       action=ACTION_READ;
210                    else if("removewatermark".equals(strAction))            action=ACTION_REMOVE_WATERMARK;
211                    else if("removewater-mark".equals(strAction))           action=ACTION_REMOVE_WATERMARK;
212                    else if("removewater_mark".equals(strAction))           action=ACTION_REMOVE_WATERMARK;
213                    else if("setinfo".equals(strAction))                            action=ACTION_SET_INFO;
214                    else if("set-info".equals(strAction))                           action=ACTION_SET_INFO;
215                    else if("set_info".equals(strAction))                           action=ACTION_SET_INFO;
216                    else if("thumbnail".equals(strAction))                          action=ACTION_THUMBNAIL;
217                    else if("write".equals(strAction))                                      action=ACTION_WRITE;
218                    else if("extracttext".equals(strAction))                                        action=ACTION_EXTRACT_TEXT;
219                    else if("extract-text".equals(strAction))                                       action=ACTION_EXTRACT_TEXT;
220                    else if("extract_text".equals(strAction))                                       action=ACTION_EXTRACT_TEXT;
221                    
222                    else throw new ApplicationException("invalid action definition ["+strAction+"], valid actions definitions are " +
223                                    "[addWatermark,deletePages,getInfo,merge,protect,read,removeWatermark,setInfo,thumbnail,write]");
224                    
225            }
226            
227    
228            public void setType(String strType) throws ApplicationException {
229                    
230                    strType=StringUtil.toLowerCase(strType.trim());
231                    if("string".equals(strType))                            type=TYPE_STRING;
232                    else if("text".equals(strType))                         type=TYPE_STRING;
233                    else if("plain".equals(strType))                                type=TYPE_STRING;
234                    else if("xml".equals(strType))                          type=TYPE_XML;
235                    
236                    else throw new ApplicationException("invalid type definition ["+strType+"], valid type definitions are " +
237                                    "[string,xml]");
238                    
239            }
240            
241            /** 
242            *  sets a filter pattern
243            * @param pattern
244             * @throws PageException 
245            **/
246            public void setFilter(String pattern) throws PageException      {
247                if(pattern.trim().length()>0) {
248                try {
249                    this.filter=new WildCardFilter(pattern);
250                } 
251                catch (MalformedPatternException e) {
252                    throw Caster.toPageException(e);
253                }
254            }
255            }
256            
257            /**
258             * @param ascending the ascending to set
259             */
260            public void setAscending(boolean ascending) {
261                    this.ascending = ascending;
262            }
263            /**
264             * @param copyFrom the copyFrom to set
265             * @throws ExpressionException 
266             */
267            public void setCopyfrom(Object copyFrom) throws ExpressionException {
268                    this.copyFrom = copyFrom;//ResourceUtil.toResourceExisting(pageContext, copyFrom);
269            }
270            /**
271             * @param ddxFile the ddxFile to set
272             */
273            public void setDdxfile(String ddxFile) {
274                    this.ddxFile = ddxFile;// MUST
275            }
276            /**
277             * @param destination the destination to set
278             */
279            public void setDestination(String destination) {
280                    this.destination = ResourceUtil.toResourceNotExisting(pageContext, destination);
281            }
282            /**
283             * @param directory the directory to set
284             * @throws ExpressionException 
285             */
286            public void setDirectory(String directory) throws ExpressionException {
287                    this.directory = ResourceUtil.toResourceExisting(pageContext, directory);
288            }
289            /**
290             * @param encrypt the encrypt to set
291             * @throws ApplicationException 
292             */
293            public void setEncrypt(String strEncrypt) throws ApplicationException {
294    
295                    strEncrypt=StringUtil.toLowerCase(strEncrypt.trim());
296                    if("aes128".equals(strEncrypt))                         encrypt=PDFUtil.ENCRYPT_AES_128;        
297                    else if("aes-128".equals(strEncrypt))           encrypt=PDFUtil.ENCRYPT_AES_128;        
298                    else if("aes_128".equals(strEncrypt))           encrypt=PDFUtil.ENCRYPT_AES_128;        
299                    else if("none".equals(strEncrypt))                      encrypt=PDFUtil.ENCRYPT_NONE;           
300                    else if("".equals(strEncrypt))                          encrypt=PDFUtil.ENCRYPT_NONE;           
301                    else if("rc4128".equals(strEncrypt))            encrypt=PDFUtil.ENCRYPT_RC4_128;                
302                    else if("rc4-128".equals(strEncrypt))           encrypt=PDFUtil.ENCRYPT_RC4_128;                
303                    else if("rc4_128".equals(strEncrypt))           encrypt=PDFUtil.ENCRYPT_RC4_128;                
304                    else if("rc4128m".equals(strEncrypt))           encrypt=PDFUtil.ENCRYPT_RC4_128M;               
305                    else if("rc4-128m".equals(strEncrypt))          encrypt=PDFUtil.ENCRYPT_RC4_128M;               
306                    else if("rc4_128m".equals(strEncrypt))          encrypt=PDFUtil.ENCRYPT_RC4_128M;               
307                    else if("rc440".equals(strEncrypt))                     encrypt=PDFUtil.ENCRYPT_RC4_40;         
308                    else if("rc4-40".equals(strEncrypt))            encrypt=PDFUtil.ENCRYPT_RC4_40;         
309                    else if("rc4_40".equals(strEncrypt))            encrypt=PDFUtil.ENCRYPT_RC4_40;         
310                    
311                    
312                    else throw new ApplicationException("invalid encrypt definition ["+strEncrypt+"], valid encrypt definitions are " +
313                                    "[aes_128,none,rc4_128,rc4_128m,rc4_40]");
314            }
315            /**
316             * @param flatten the flatten to set
317             */
318            public void setFlatten(boolean flatten) {
319                    this.flatten = flatten;
320            }
321            /**
322             * @param foreground the foreground to set
323             */
324            public void setForeground(boolean foreground) {
325                    this.foreground = foreground;
326            }
327            /**
328             * @param format the format to set
329             * @throws ApplicationException 
330             */
331            public void setFormat(String strFormat) throws ApplicationException {
332                    strFormat=StringUtil.toLowerCase(strFormat.trim());
333                    if("jpg".equals(strFormat))                                     format=FORMAT_JPG;      
334                    else if("jpeg".equals(strFormat))                       format=FORMAT_JPG;      
335                    else if("jpe".equals(strFormat))                        format=FORMAT_JPG;      
336                    else if("tiff".equals(strFormat))                       format=FORMAT_TIFF;
337                    else if("tif".equals(strFormat))                        format=FORMAT_TIFF;     
338                    else if("png".equals(strFormat))                        format=FORMAT_PNG;      
339                    
340                    else throw new ApplicationException("invalid format definition ["+strFormat+"], valid format definitions are " +
341                                    "[jpg,tiff,png]");
342            }
343            /**
344             * @param image the image to set
345             */
346            public void setImage(Object image) {
347                    this.image = image;// MUST
348            }
349            /**
350             * @param prefix the prefix to set
351             */
352            public void setPrefix(String prefix) {
353                    this.imagePrefix = prefix;
354            }
355            /**
356             * @param info the info to set
357             */
358            public void setInfo(Struct info) {
359                    this.info = info;
360            }
361            /**
362             * @param inputFiles the inputFiles to set
363             */
364            public void setInputfiles(Struct inputFiles) {
365                    this.inputFiles = inputFiles;
366            }
367            /**
368             * @param outputFiles the outputFiles to set
369             */
370            public void setOutputfiles(Struct outputFiles) {
371                    this.outputFiles = outputFiles;
372            }
373            /**
374             * @param isBase64 the isBase64 to set
375             */
376            public void setIsbase64(boolean isBase64) {
377                    this.isBase64 = isBase64;
378            }
379            /**
380             * @param keepBookmark the keepBookmark to set
381             */
382            public void setKeepbookmark(boolean keepBookmark) {
383                    this.keepBookmark = keepBookmark;
384            }
385            /**
386             * @param name the name to set
387             */
388            public void setName(String name) {
389                    this.name = name;
390            }
391            /**
392             * @param newOwnerPassword the newOwnerPassword to set
393             */
394            public void setNewownerpassword(String newOwnerPassword) {
395                    this.newOwnerPassword = newOwnerPassword;
396            }
397            /**
398             * @param newUserPassword the newUserPassword to set
399             */
400            public void setNewuserpassword(String newUserPassword) {
401                    this.newUserPassword = newUserPassword;
402            }
403            /**
404             * @param opacity the opacity to set
405             * @throws ApplicationException 
406             */
407            public void setOpacity(double opacity) throws ApplicationException {
408                    if(opacity<0 || opacity>10) 
409                            throw new ApplicationException("invalid opacity definition ["+Caster.toString(opacity)+"], value should be in range from 0 to 10");
410                    this.opacity = (float) (opacity/10);
411            }
412            /**
413             * @param order the order to set
414             * @throws ApplicationException 
415             */
416            public void setOrder(String strOrder) throws ApplicationException {
417                    strOrder=StringUtil.toLowerCase(strOrder.trim());
418                    if("name".equals(strOrder))                                     order=ORDER_NAME;       
419                    else if("time".equals(strOrder))                        order=ORDER_TIME;       
420                    
421                    else throw new ApplicationException("invalid order definition ["+strOrder+"], valid order definitions are " +
422                                    "[name,time]");
423            }
424            /**
425             * @param overwrite the overwrite to set
426             */
427            public void setOverwrite(boolean overwrite) {
428                    this.overwrite = overwrite;
429            }
430            /**
431             * @param pages the pages to set
432             */
433            public void setPages(String pages) {
434                    this.pages = pages;
435            }
436            /**
437             * @param password the password to set
438             */
439            public void setPassword(String password) {
440                    this.password = password;
441            }
442            /**
443             * @param permissions the permissions to set
444             * @throws PageException 
445             */
446            public void setPermissions(String strPermissions) throws PageException {
447                    permissions=PDFUtil.toPermissions(strPermissions);
448            }       
449            /**
450             * @param position the position to set
451             */
452            public void setPosition(String position) {
453                    this.position = position;//MUST
454            }
455            /**
456             * @param resolution the resolution to set
457             * @throws ApplicationException 
458             */
459            public void setResolution(String strResolution) throws ApplicationException {
460                    strResolution=StringUtil.toLowerCase(strResolution.trim());
461                    if("low".equals(strResolution))                 resolution=RESOLUTION_LOW;      
462                    else if("high".equals(strResolution))   resolution=RESOLUTION_HIGH;     
463                    
464                    else throw new ApplicationException("invalid resolution definition ["+strResolution+"], valid resolution definitions are " +
465                                    "[low,high]");
466            }
467            
468            /**
469             * @param rotation the rotation to set
470             */
471            public void setRotation(double rotation) {
472                    rotation=rotation%360D;
473                    //rotation=rotation/360*6.28318525;
474                    
475                    this.rotation = (float) rotation;
476            }
477            
478            /**
479             * @param saveOption the saveOption to set
480             * @throws ApplicationException 
481             */
482            public void setSaveoption(String strSaveOption) throws ApplicationException {
483                    strSaveOption=StringUtil.toLowerCase(strSaveOption.trim());
484                    if("full".equals(strSaveOption))                        saveOption=SAVE_OPTION_FULL;    
485                    else if("incremental".equals(strSaveOption))saveOption=SAVE_OPTION_INCREMENTAL; 
486                    else if("linear".equals(strSaveOption))         saveOption=SAVE_OPTION_LINEAR;  
487                    
488                    else throw new ApplicationException("invalid saveOption definition ["+strSaveOption+"], valid saveOption definitions are " +
489                                    "[full,linear,incremental]");
490            }
491            
492            /**
493             * @param scale the scale to set
494             * @throws ApplicationException 
495             */
496            public void setScale(double scale) throws ApplicationException {
497                    //if(scale<1 || scale>1000)  this check is now done inside PDF2IMage implementation
498                    //      throw new ApplicationException("invalid scale definition ["+Caster.toString(scale)+"], value should be in range from 1 to 100");
499                    this.scale = (int) scale;
500            }
501            
502            /**
503             * @param showOnPrint the showOnPrint to set
504             */
505            public void setShowonprint(boolean showOnPrint) {
506                    this.showOnPrint = showOnPrint;
507            }
508            
509            /**
510             * @param source the source to set
511             */
512            public void setSource(Object source) {
513                    this.source = source;
514            }
515            /**
516             * @param stopOnError the stopOnError to set
517             */
518            public void setStoponerror(boolean stopOnError) {
519                    this.stopOnError = stopOnError;
520            }
521            /**
522             * @param transparent the transparent to set
523             */
524            public void setTransparent(boolean transparent) {
525                    this.transparent = transparent;
526            }
527            /**
528             * @param version the version to set
529             * @throws ApplicationException 
530             */
531            public void setVersion(double version) throws ApplicationException {
532                    if(1.1 == version)                      this.version='1';       
533                    else if(1.2 == version)         this.version=PdfWriter.VERSION_1_2;     
534                    else if(1.3 == version)         this.version=PdfWriter.VERSION_1_3;     
535                    else if(1.4 == version)         this.version=PdfWriter.VERSION_1_4;     
536                    else if(1.5 == version)         this.version=PdfWriter.VERSION_1_5;     
537                    else if(1.6 == version)         this.version=PdfWriter.VERSION_1_6;     
538                    
539                    else throw new ApplicationException("invalid version definition ["+Caster.toString(version)+"], valid version definitions are " +
540                                    "[1.1, 1.2, 1.3, 1.4, 1.5, 1.6]");
541            }
542            
543            @Override
544            public int doStartTag() throws PageException    {
545                    // RR SerialNumber sn = pageContext.getConfig().getSerialNumber();
546                //if(sn.getVersion()==SerialNumber.VERSION_COMMUNITY)
547                //    throw new SecurityException("no access to this functionality with the "+sn.getStringVersion()+" version of railo");
548                
549                return EVAL_BODY_BUFFERED;
550            }
551    
552            @Override
553            public void doInitBody()        {
554                    
555            }
556            
557            @Override
558            public int doAfterBody()        {
559                    return SKIP_BODY;
560            }
561            
562            @Override
563            public int doEndTag() throws PageException {
564                    try {
565    
566                            if(ACTION_ADD_WATERMARK==action)                        doActionAddWatermark();
567                            else if(ACTION_REMOVE_WATERMARK==action)        doActionRemoveWatermark();
568                            else if(ACTION_READ==action)                            doActionRead();
569                            else if(ACTION_WRITE==action)                           doActionWrite();
570                            else if(ACTION_GET_INFO==action)                        doActionGetInfo();
571                            else if(ACTION_SET_INFO==action)                        doActionSetInfo();
572                            else if(ACTION_MERGE==action)                           doActionMerge();
573                            else if(ACTION_DELETE_PAGES==action)            doActionDeletePages();
574                            else if(ACTION_PROTECT==action)                         doActionProtect();
575                            else if(ACTION_THUMBNAIL==action)                       doActionThumbnail();
576                            else if(ACTION_EXTRACT_TEXT==action)            {
577                                    if(true)throw new ApplicationException("not supported yet, see https://issues.jboss.org/browse/RAILO-1559");
578                                    doActionExtractText();
579                            }
580                            
581                            //else if(ACTION_PROCESSDDX==action)    throw new ApplicationException("action [processddx] not supported");
582                            
583                            
584                            
585                    }
586                    catch (Exception e) {
587                            throw Caster.toPageException(e);
588                    }       
589                    return EVAL_PAGE;
590            }
591            
592            
593            
594            
595            private void doActionWrite() throws PageException, IOException, DocumentException {
596                    required("pdf", "write", "source", source);
597                    required("pdf", "write", "destination", destination);
598                    
599                    if(destination.exists() && !overwrite)
600                            throw new ApplicationException("destination file ["+destination+"] already exists");
601                    
602                    PDFDocument doc = toPDFDocument(source, password, null);
603                    //PdfReader pr = doc.getPdfReader();
604                    // output
605                    boolean destIsSource = doc.getResource()!=null && destination.equals(doc.getResource());
606                    
607                    OutputStream os=null;
608                    if(destIsSource){
609                            os=new ByteArrayOutputStream();
610                    }
611                    else if(destination!=null) {
612                            os=destination.getOutputStream();
613                    }
614                    
615                    try {   
616                            PDFUtil.concat(new PDFDocument[]{doc}, os, true, true, true,version);
617                    }
618                    finally {
619                            IOUtil.closeEL(os);
620                            if(os instanceof ByteArrayOutputStream) {
621                                    if(destination!=null)IOUtil.copy(new ByteArrayInputStream(((ByteArrayOutputStream)os).toByteArray()), destination,true);// MUST overwrite
622                            }
623                    }
624                    
625    /*      
626                    // flatten = "yes|no"
627                // must saveOption = "linear|incremental|full"
628    */
629            }
630    
631    
632    
633            private void doActionThumbnail() throws PageException, IOException, DocumentException {
634                    required("pdf", "thumbnail", "source", source);
635    
636                    PDFDocument doc = toPDFDocument(source, password, null);
637                    PdfReader pr = doc.getPdfReader();
638                    boolean isEnc=pr.isEncrypted();
639                    pr.close();
640                    if(isEnc) {
641                            ByteArrayOutputStream baos = new ByteArrayOutputStream();
642                            //PDFUtil.concat(new PDFDocument[]{doc}, baos, true, true, true, (char)0);
643                            PDFUtil.encrypt(doc,baos,null,null,0,PDFUtil.ENCRYPT_NONE);
644                            baos.close();
645                            doc = new PDFDocument(baos.toByteArray(),doc.getResource(),null);
646                    }
647                    
648                    doc.setPages(pages);
649                    
650                    // scale
651                    if(scale<1)
652                            throw new ApplicationException("value of attribute scale ["+scale+"] should be at least 1");
653                    
654                    // destination
655                    if(destination==null)
656                            destination=ResourceUtil.toResourceNotExisting(pageContext, "thumbnails");
657                    
658                    // imagePrefix
659                    if(imagePrefix==null){
660                            Resource res = doc.getResource();
661                            if(res!=null){
662                                    String n = res.getName();
663                                    int index=n.lastIndexOf('.');
664                                    if(index!=-1)imagePrefix=n.substring(0,index);
665                                    else imagePrefix=n;
666                            }
667                            else imagePrefix="memory";
668                    }
669                    
670                    // MUST password
671                    PDFUtil.writeImages(doc.getRaw(), doc.getPages(), destination, imagePrefix, format, scale,overwrite,
672                                    resolution==RESOLUTION_HIGH,transparent);
673                    
674                    
675                    
676            }
677            
678            
679            
680            
681            private void doActionAddWatermark() throws PageException, IOException, DocumentException {
682                    required("pdf", "addWatermark", "source", source);
683                    if(copyFrom==null && image==null)
684                            throw new ApplicationException("at least one of the following attributes must be defined " +
685                                            "[copyFrom,image]");
686                    
687                    if(destination!=null && destination.exists() && !overwrite)
688                            throw new ApplicationException("destination file ["+destination+"] already exists");
689                    
690                    
691                    // image
692                    Image img=null;
693                    if(image!=null) {
694                            railo.runtime.img.Image ri = railo.runtime.img.Image.createImage(pageContext,image,false,false,true,null);
695                            img=Image.getInstance(ri.getBufferedImage(),null,false);
696                    }
697                    // copy From
698                    else {
699                            byte[] barr;
700                            try{
701                                    Resource res = Caster.toResource(pageContext, copyFrom, true);
702                                    barr=IOUtil.toBytes(res);
703                            }
704                            catch(ExpressionException ee) {
705                                    barr=Caster.toBinary(copyFrom);
706                            }
707                            img=Image.getInstance(PDFUtil.toImage(barr, 1).getBufferedImage(),null,false);
708                            
709                    }
710                    
711                    // position
712                    float x=UNDEFINED,y=UNDEFINED;
713                    if(!StringUtil.isEmpty(position)) {
714                            int index=position.indexOf(',');
715                            if(index==-1)
716                                    throw new ApplicationException("attribute [position] has an invalid value ["+position+"]," +
717                                                    "value should follow one of the following pattern [40,50], [40,] or [,50]");
718                            String strX = position.substring(0,index).trim();
719                            String strY = position.substring(index+1).trim();
720                            if(!StringUtil.isEmpty(strX))x = Caster.toIntValue(strX);
721                            if(!StringUtil.isEmpty(strY))y = Caster.toIntValue(strY);
722                            
723                    }
724                    
725                    
726                    PDFDocument doc = toPDFDocument(source, password, null);
727                    doc.setPages(pages);
728                    PdfReader reader = doc.getPdfReader();
729                    reader.consolidateNamedDestinations();
730                    boolean destIsSource = destination!=null && doc.getResource()!=null && destination.equals(doc.getResource());
731                    java.util.List bookmarks = SimpleBookmark.getBookmark(reader);
732                ArrayList master = new ArrayList(); 
733                    if(bookmarks!=null)master.addAll(bookmarks);
734                
735                    // output
736                    OutputStream os=null;
737                    if(!StringUtil.isEmpty(name) || destIsSource){
738                            os=new ByteArrayOutputStream();
739                    }
740                    else if(destination!=null) {
741                            os=destination.getOutputStream();
742                    }
743                    
744                    try {
745                            
746                            int len = reader.getNumberOfPages();
747                        PdfStamper stamp = new PdfStamper(reader, os);
748                        
749                        if(len >0){
750                            if(x==UNDEFINED || y==UNDEFINED) {
751                                    PdfImportedPage first = stamp.getImportedPage(reader, 1);
752                                    if(y==UNDEFINED)y=(first.getHeight()-img.getHeight())/2;
753                                    if(x==UNDEFINED)x=(first.getWidth()-img.getWidth())/2;          
754                            }
755                            img.setAbsolutePosition(x, y);
756                            //img.setAlignment(Image.ALIGN_JUSTIFIED); ration geht nicht anhand mitte
757                            
758                        }
759                        
760                            // rotation
761                            if(rotation!=0) {
762                                    img.setRotationDegrees(rotation);
763                            }
764                            
765                            Set _pages = doc.getPages();
766                        for (int i=1;i<=len;i++) {
767                            if(_pages!=null && !_pages.contains(Integer.valueOf(i))) continue;
768                            PdfContentByte cb =foreground? stamp.getOverContent(i):stamp.getUnderContent(i);
769                            PdfGState gs1 = new PdfGState();
770                            //print.out("op:"+opacity);
771                            gs1.setFillOpacity(opacity);
772                            //gs1.setStrokeOpacity(opacity);
773                            cb.setGState(gs1);
774                            cb.addImage(img);
775                        }
776                        if(bookmarks!=null)stamp.setOutlines(master);
777                        stamp.close();
778                    }
779                    finally {
780                            IOUtil.closeEL(os);
781                            if(os instanceof ByteArrayOutputStream) {
782                                    if(destination!=null)IOUtil.copy(new ByteArrayInputStream(((ByteArrayOutputStream)os).toByteArray()), destination,true);// MUST overwrite
783                                    if(!StringUtil.isEmpty(name)){
784                                            pageContext.setVariable(name,new PDFDocument(((ByteArrayOutputStream)os).toByteArray(),password));
785                                    }
786                            }
787                    }
788            }
789            
790            private void doActionRemoveWatermark() throws PageException, IOException, DocumentException {
791                    required("pdf", "removeWatermark", "source", source);
792                    
793                    if(destination!=null && destination.exists() && !overwrite)
794                            throw new ApplicationException("destination file ["+destination+"] already exists");
795                    
796                    railo.runtime.img.Image ri = new railo.runtime.img.Image(1,1,BufferedImage.TYPE_INT_RGB,Color.BLACK);
797                    Image img = Image.getInstance(ri.getBufferedImage(),null,false);
798                    img.setAbsolutePosition(1,1);
799                    
800                    
801                    PDFDocument doc = toPDFDocument(source, password, null);
802                    doc.setPages(pages);
803                    PdfReader reader = doc.getPdfReader();
804    
805                    boolean destIsSource = destination!=null && doc.getResource()!=null && destination.equals(doc.getResource());
806                    java.util.List bookmarks = SimpleBookmark.getBookmark(reader);
807                ArrayList master = new ArrayList(); 
808                    if(bookmarks!=null)master.addAll(bookmarks);
809                
810                    // output
811                    OutputStream os=null;
812                    if(!StringUtil.isEmpty(name) || destIsSource){
813                            os=new ByteArrayOutputStream();
814                    }
815                    else if(destination!=null) {
816                            os=destination.getOutputStream();
817                    }
818                    
819                    try {
820                            int len = reader.getNumberOfPages();
821                        PdfStamper stamp = new PdfStamper(reader, os);
822                            
823                            Set _pages = doc.getPages();
824                        for (int i=1;i<=len;i++) {
825                            if(_pages!=null && !_pages.contains(Integer.valueOf(i))) continue;
826                            PdfContentByte cb =foreground? stamp.getOverContent(i):stamp.getUnderContent(i);
827                            PdfGState gs1 = new PdfGState();
828                            gs1.setFillOpacity(0);
829                            cb.setGState(gs1);
830                            cb.addImage(img);
831                        }
832                        if(bookmarks!=null)stamp.setOutlines(master);
833                        stamp.close();
834                    }
835                    finally {
836                            IOUtil.closeEL(os);
837                            if(os instanceof ByteArrayOutputStream) {
838                                    if(destination!=null)IOUtil.copy(new ByteArrayInputStream(((ByteArrayOutputStream)os).toByteArray()), destination,true);// MUST overwrite
839                                    if(!StringUtil.isEmpty(name)){
840                                            pageContext.setVariable(name,new PDFDocument(((ByteArrayOutputStream)os).toByteArray(),password));
841                                    }
842                            }
843                    }
844            }
845            
846            private void doActionDeletePages() throws PageException, IOException, DocumentException {
847                    required("pdf", "deletePage", "pages", pages,true);
848                    required("pdf", "deletePage", "source", source);
849                    
850                    PDFDocument doc = toPDFDocument(source, password, null);
851                    doc.setPages(pages);
852                    
853                    
854                    if(destination==null && StringUtil.isEmpty(name)){
855                            if(doc.getResource()==null)
856                                    throw new ApplicationException("source is not based on a resource, destination attribute is required");
857                            destination=doc.getResource();
858                    }
859                    else if(destination!=null && destination.exists() && !overwrite)
860                            throw new ApplicationException("destination file ["+destination+"] already exists");
861                    
862                    boolean destIsSource = destination!=null && doc.getResource()!=null && destination.equals(doc.getResource());
863                    
864                    // output
865                    OutputStream os=null;
866                    if(!StringUtil.isEmpty(name) || destIsSource){
867                            os=new ByteArrayOutputStream();
868                    }
869                    else if(destination!=null) {
870                            os=destination.getOutputStream();
871                    }
872                    
873                    try {
874                            PDFUtil.concat(new PDFDocument[]{doc}, os, true, true,true,version);
875                    }
876                    finally {
877                            //if(document!=null)document.close();
878                            IOUtil.closeEL(os);
879                            if(os instanceof ByteArrayOutputStream) {
880                                    if(destination!=null)IOUtil.copy(new ByteArrayInputStream(((ByteArrayOutputStream)os).toByteArray()), destination,true);// MUST overwrite
881                                    if(!StringUtil.isEmpty(name)){
882                                            pageContext.setVariable(name,new PDFDocument(((ByteArrayOutputStream)os).toByteArray(),password));
883                                    }
884                            }
885                    }
886            }
887            
888            
889            private void doActionMerge() throws ApplicationException, PageException, IOException, DocumentException {
890                    
891                    if(source==null && params==null && directory==null)
892                            throw new ApplicationException("at least one of the following constellation must be defined" +
893                                            " attribute source, attribute directory or cfpdfparam child tags");
894                    if(destination==null && StringUtil.isEmpty(name,true))
895                            throw new ApplicationException("at least one of the following attributes must be defined " +
896                                            "[destination,name]");
897                    if(destination!=null && !overwrite)
898                            throw new ApplicationException("destination file ["+destination+"] already exists");
899                    
900                    ArrayList docs = new ArrayList();
901                    PDFDocument doc;
902                    boolean isListing=false;
903                    
904                    // source
905                    if(source!=null) {
906                            if(Decision.isArray(source)) {
907                                    Array arr = Caster.toArray(source);
908                                    int len = arr.size();
909                                    for(int i=1;i<=len;i++) {
910                                            docs.add(doc=toPDFDocument(arr.getE(i),password,null));
911                                            doc.setPages(pages);
912                                    }
913                            }
914                            else if(source instanceof String) {
915                                    String[] sources = ListUtil.toStringArrayTrim(ListUtil.listToArrayRemoveEmpty((String)source, ','));
916                                    for(int i=0;i<sources.length;i++) {
917                                            docs.add(doc=toPDFDocument(sources[i],password,null));
918                                            doc.setPages(pages);
919                                    }
920                            }
921                            else docs.add(toPDFDocument(source,password,null));
922                            
923                    }
924                    boolean destIsSource = false;
925                    
926                    // params
927                    if(directory!=null && !directory.isDirectory()) {
928                            if(!directory.exists())
929                                    throw new ApplicationException("defined attribute directory does not exist");
930                            throw new ApplicationException("defined attribute directory is not a directory");
931                    }
932                    if(params!=null) {
933                            Iterator it = params.iterator();
934                            PDFParamBean param;
935                            while(it.hasNext()) {
936                                    param=(PDFParamBean) it.next();
937                                    docs.add(doc=toPDFDocument(param.getSource(), param.getPassword(),directory));
938                                    doc.setPages(param.getPages());
939                            }
940                    }
941                    else if(directory!=null) {
942                            isListing=true;
943                            Resource[] children = ResourceUtil.listResources(directory, filter);
944                            
945                            if(ascending) {
946                                    for(int i=children.length-1;i>=0;i--) {
947                                            if(destination!=null && children[i].equals(destination))        destIsSource=true;
948                                            docs.add(doc=toPDFDocument(children[i],password,null));
949                                            doc.setPages(pages);
950                                    }
951                            }
952                            else {
953                                    for(int i=0;i<children.length;i++) {
954                                            if(destination!=null && children[i].equals(destination))        destIsSource=true;
955                                            docs.add(doc=toPDFDocument(children[i],password,null));
956                                            doc.setPages(pages);
957                                    }
958                            }
959                            
960                    }
961                    
962                    int doclen=docs.size();
963                    if(doclen==0)
964                            throw new ApplicationException("you have to define at leat 1 pdf file");
965                    
966                    // output
967                    OutputStream os=null;
968                    if(!StringUtil.isEmpty(name) || destIsSource){
969                            os=new ByteArrayOutputStream();
970                    }
971                    else if(destination!=null) {
972                            os=destination.getOutputStream();
973                    }
974                    
975                    
976                    /*com.lowagie.text.Document document=null;
977                    PdfCopy copy=null;
978                    PdfReader pr;
979                    Set pages;
980                    int size;*/
981                    
982                    
983                    try {
984                            if(!isListing)stopOnError=true;
985                            PDFUtil.concat((PDFDocument[]) docs.toArray(new PDFDocument[docs.size()]), os, keepBookmark, false,stopOnError,version);
986                            /*
987                            boolean init=false;
988                            for(int d=0;d<doclen;d++) {
989                                    doc=(PDFDocument) docs.get(d);
990                                    pages=doc.getPages();
991                                    try {
992                                            pr=doc.getPdfReader();
993                                            print.out(pr.getCatalog().getKeys());
994                                            
995                                    }
996                                    catch(Throwable t) {
997                                            if(isListing && !stopOnError)continue;
998                                            throw Caster.toPageException(t);
999                                    }
1000                                    print.out("d+"+d);
1001                                    if(!init) {
1002                                            init=true;
1003                                            print.out("set");
1004                                            document = new com.lowagie.text.Document(pr.getPageSizeWithRotation(1));
1005                                            copy = new PdfCopy(document,os);
1006                                            document.open();
1007                                    }
1008                                    size=pr.getNumberOfPages();
1009                                    print.out("pages:"+size);
1010                                    for(int page=1;page<=size;page++) {
1011                                            if(pages==null || pages.contains(Constants.Integer(page))) {
1012                                                    copy.addPage(copy.getImportedPage(pr, page));
1013                                            }
1014                                    }
1015                            }*/
1016                    }
1017                    finally {
1018                            //if(document!=null)document.close();
1019                            IOUtil.closeEL(os);
1020                            if(os instanceof ByteArrayOutputStream) {
1021                                    if(destination!=null)IOUtil.copy(new ByteArrayInputStream(((ByteArrayOutputStream)os).toByteArray()), destination,true);// MUST overwrite
1022                                    if(!StringUtil.isEmpty(name))pageContext.setVariable(name, ((ByteArrayOutputStream)os).toByteArray());
1023                            }
1024                            
1025                    }
1026                    
1027                    
1028            }
1029            private void doActionRead() throws PageException {
1030                    required("pdf", "read", "name", name,true);
1031                    required("pdf", "read", "source", source);
1032                    
1033                    pageContext.setVariable(name, toPDFDocument(source,password,null));
1034            }
1035            
1036            private void doActionProtect() throws PageException, IOException, DocumentException {
1037                    required("pdf", "protect", "source", source);
1038                    
1039                    if(StringUtil.isEmpty(newUserPassword) && StringUtil.isEmpty(newOwnerPassword))
1040                            throw new ApplicationException("at least one of the following attributes must be defined [newUserPassword,newOwnerPassword]");
1041            
1042                    
1043                    PDFDocument doc = toPDFDocument(source,password,null);
1044                    
1045                    if(destination==null){
1046                            destination=doc.getResource();
1047                            if(destination==null)
1048                                    throw new ApplicationException("source is not based on a resource, destination file is required");
1049                    }
1050                    else if(destination.exists() && !overwrite)
1051                            throw new ApplicationException("destination file ["+destination+"] already exists");
1052                    
1053                    boolean destIsSource = doc.getResource()!=null && destination.equals(doc.getResource());
1054                    
1055                    // output
1056                    OutputStream os=null;
1057                    if(destIsSource){
1058                            os=new ByteArrayOutputStream();
1059                    }
1060                    else {
1061                            os=destination.getOutputStream();
1062                    }
1063                    
1064                    
1065                    try{
1066                            PDFUtil.encrypt(doc,os,newUserPassword,newOwnerPassword,permissions,encrypt);
1067                    }
1068                    finally {
1069                            IOUtil.closeEL(os);
1070                            if(os instanceof ByteArrayOutputStream) {
1071                                    IOUtil.copy(new ByteArrayInputStream(((ByteArrayOutputStream)os).toByteArray()), destination,true);// MUST overwrite
1072                            }
1073                            
1074                    }
1075                    
1076            }
1077            
1078    
1079            
1080    
1081            private void doActionSetInfo() throws PageException, IOException, DocumentException {
1082                    required("pdf", "setInfo", "info", info);
1083                    required("pdf", "getInfo", "source", source);
1084                    
1085                    PDFDocument doc = toPDFDocument(source,password,null);
1086                    PdfReader pr = doc.getPdfReader();
1087                    OutputStream os=null;
1088                    try {
1089                            if(destination==null){
1090                                    if(doc.getResource()==null)
1091                                            throw new ApplicationException("source is not based on a resource, destination file is required");
1092                                    destination=doc.getResource();
1093                            }
1094                            else if(destination.exists() && !overwrite)
1095                                    throw new ApplicationException("destination file ["+destination+"] already exists");
1096                            
1097                            PdfStamper stamp = new PdfStamper(pr, os=destination.getOutputStream());
1098                            HashMap moreInfo = new HashMap();
1099                
1100                            //Key[] keys = info.keys();
1101                            Iterator<Entry<Key, Object>> it = info.entryIterator();
1102                            Entry<Key, Object> e;
1103                            while(it.hasNext()) {
1104                                    e = it.next();
1105                                    moreInfo.put(StringUtil.ucFirst(e.getKey().getLowerString()), Caster.toString(e.getValue()));
1106                            }
1107                            // author
1108                            Object value = info.get(KeyConstants._author, null);    
1109                            if(value!=null)moreInfo.put("Author", Caster.toString(value));
1110                            // keywords
1111                            value = info.get("keywords", null);     
1112                            if(value!=null)moreInfo.put("Keywords", Caster.toString(value));
1113                            // title
1114                            value = info.get(KeyConstants._title, null);    
1115                            if(value!=null)moreInfo.put("Title", Caster.toString(value));
1116                            // subject
1117                            value = info.get(KeyConstants._subject, null);  
1118                            if(value!=null)moreInfo.put("Subject", Caster.toString(value));
1119                            // creator
1120                            value = info.get("creator", null);      
1121                            if(value!=null)moreInfo.put("Creator", Caster.toString(value));
1122                            // trapped
1123                            value = info.get("Trapped", null);      
1124                            if(value!=null)moreInfo.put("Trapped", Caster.toString(value));
1125                            // Created
1126                            value = info.get("Created", null);      
1127                            if(value!=null)moreInfo.put("Created", Caster.toString(value));
1128                            // Language
1129                            value = info.get("Language", null);     
1130                            if(value!=null)moreInfo.put("Language", Caster.toString(value));
1131                            
1132                            
1133                            stamp.setMoreInfo(moreInfo);
1134                            stamp.close();
1135                            
1136                    }
1137                    finally {
1138                            IOUtil.closeEL(os);
1139                            pr.close();
1140                    }
1141            }
1142            
1143            private void doActionGetInfo() throws PageException {
1144                    required("pdf", "getInfo", "name", name,true);
1145                    required("pdf", "getInfo", "source", source);
1146                    
1147                    PDFDocument doc = toPDFDocument(source,password,null);
1148                    pageContext.setVariable(name, doc.getInfo());
1149                    
1150            }
1151            private void doActionExtractText() throws PageException, IOException, CryptographyException, InvalidPasswordException {
1152                    required("pdf", "extractText", "name", name,true);
1153                    
1154                    PDFDocument doc = toPDFDocument(source,password,null);
1155                    doc.setPages(pages);
1156                    
1157                    pageContext.setVariable(name, PDFUtil.extractText(doc,doc.getPages()));
1158                    /*
1159                     <cfpdf 
1160     required 
1161        action="extracttext" <!---extract all the words in the PDF.---> 
1162        ***source= "absolute or relative path of the PDF file|PDF document variable| 
1163                cfdocument variable" 
1164        pages = "*" <!----page numbers from where the text needs to be extracted from the 
1165                    PDF document---> 
1166    
1167    optional 
1168        addquads = "add the position or quadrants for the text in the PDF" 
1169        honourspaces = "true|false" 
1170        overwrite = "true" <!---Overwrite the specified object in the PDF document---> 
1171        ***password = "" <!--- PDF document password---> 
1172        type = "string|xml" <!---format in which the text needs to be extracted---> 
1173        one of the following: 
1174        destination = "PDF output file pathname" 
1175        name = "PDF document variable" 
1176        usestructure = "true|false" 
1177                     * */
1178            }
1179            
1180            private Object allowed(boolean encrypted, int permissions, int permission) {
1181                    return (!encrypted || (permissions&permission)>0)?"Allowed":"Not Allowed";
1182            }
1183            
1184    
1185            private PDFDocument toPDFDocument(Object source,String password, Resource directory) throws PageException {
1186                    
1187                    if(source instanceof PDFDocument) 
1188                            return (PDFDocument)source;
1189                    if(Decision.isBinary(source)){
1190                            return new PDFDocument(Caster.toBinary(source),password);
1191                    }
1192                    if(source instanceof Resource){ 
1193                            return new PDFDocument((Resource) source,password);
1194                    }
1195                    if(source instanceof String){
1196                            if(directory!=null) {
1197                                    Resource res = directory.getRealResource((String)source);
1198                                    if(!res.isFile()){
1199                                            Resource res2 = ResourceUtil.toResourceNotExisting(pageContext, (String)source);
1200                                            if(res2.isFile())
1201                                                    res=res2;
1202                                            else 
1203                                                    throw new ExpressionException("file or directory "+res+" not exist");
1204                                    }
1205                                    return new PDFDocument(res,password);   
1206                            }
1207                            return new PDFDocument(ResourceUtil.toResourceExisting(pageContext, (String)source),password);  
1208                    }
1209                    
1210                    throw new CasterException(source,PdfReader.class);
1211            }
1212            
1213            /*private byte[] toBinary(Object source) throws ExpressionException, IOException {
1214                    
1215                    if(source instanceof PDFDocument) 
1216                            return toBinary(((PDFDocument)source).getResource());
1217                    if(Decision.isBinary(source)){
1218                            return Caster.toBinary(source);
1219                    }
1220                    if(source instanceof Resource){ 
1221                            return IOUtil.toBytes((Resource)source);
1222                    }
1223                    if(source instanceof String){
1224                            if(directory!=null) {
1225                                    Resource res = directory.getRealResource((String)source);
1226                                    if(!res.isFile()){
1227                                            Resource res2 = ResourceUtil.toResourceNotExisting(pageContext, (String)source);
1228                                            if(res2.isFile())
1229                                                    res=res2;
1230                                            else 
1231                                                    throw new ExpressionException("file or directory "+res+" not exist");
1232                                    }
1233                                    return IOUtil.toBytes(res);     
1234                            }
1235                            return IOUtil.toBytes(ResourceUtil.toResourceExisting(pageContext, (String)source));    
1236                    }
1237                    
1238                    throw new CasterException(source,PdfReader.class);
1239            }*/
1240            
1241            protected void setParam(PDFParamBean param) {
1242                    if(params==null)
1243                            params=new ArrayList<PDFParamBean>();
1244                    params.add(param);
1245            }
1246            
1247            
1248            
1249    
1250    }