All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jpedal.objects.acroforms.AcroRenderer Maven / Gradle / Ivy

There is a newer version: 20151002
Show newest version
/*
 * ===========================================
 * Java Pdf Extraction Decoding Access Library
 * ===========================================
 *
 * Project Info:  http://www.idrsolutions.com
 * Help section for developers at http://www.idrsolutions.com/support/
 *
 * (C) Copyright 1997-2017 IDRsolutions and Contributors.
 *
 * This file is part of JPedal/JPDF2HTML5
 *
     This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


 *
 * ---------------
 * AcroRenderer.java
 * ---------------
 */
package org.jpedal.objects.acroforms;

import java.awt.image.BufferedImage;
import java.util.*;
import org.jpedal.exception.PdfException;
import org.jpedal.external.ExternalHandlers;
import org.jpedal.io.PdfObjectReader;
import org.jpedal.objects.Javascript;
import org.jpedal.objects.PdfPageData;
import org.jpedal.objects.acroforms.actions.ActionHandler;
import org.jpedal.objects.acroforms.creation.FormFactory;
import org.jpedal.objects.acroforms.creation.SwingFormCreator;
import org.jpedal.objects.acroforms.utils.FormUtils;
import org.jpedal.objects.layers.PdfLayerList;
import org.jpedal.objects.raw.*;
import org.jpedal.parser.FormFlattener;
import org.jpedal.parser.PdfStreamDecoder;
import org.jpedal.parser.PdfStreamDecoderForPrinting;
import org.jpedal.parser.PrintStreamDecoder;
import org.jpedal.utils.LogWriter;
import org.jpedal.utils.StringUtils;


/**
 * Provides top level to forms handling, assisted by separate classes to
 * decode widgets (FormDecoder - default implements Swing set)
 * create Form widgets (implementation of FormFactory),
 * store and render widgets (GUIData),
 * handle Javascript and Actions (Javascript and ActionHandler)
 * and support for Signature object
 */
public class AcroRenderer{
    
    private static final boolean flattenForms,ignoreAllForms;
    
    static{
      
        String s = System.getProperty("org.jpedal.flattenForm");
        
        flattenForms=s!=null && s.equalsIgnoreCase("true");
        
        s = System.getProperty("org.jpedal.ignoreAllForms");
        
        ignoreAllForms=s!=null && s.equalsIgnoreCase("true");
        
    }

    public static boolean FROM_JPDF2FORMS;
    
    FormObject[] Fforms, Aforms;
    
    private PdfObject AcroRes;
    
    private float dpi=72f;
    
    private Object[] CO;
    PdfArrayIterator fieldList;
    private PdfArrayIterator[] annotList;
   
    /**
     * flag to show we ignore forms
     */
    private boolean ignoreForms;

    private boolean alwaysUseXFA;

    /**
     * creates all GUI components from raw data in PDF and stores in GUIData instance
     */
    public FormFactory formFactory;
    
    /**holder for all data (implementations to support Swing and ULC)*/
    public GUIData compData;
    
    /**holds sig object so we can easily retrieve*/
    private Set sigObject;
    private Map sigKeys; //and allow us to trap multiple if in both Annot and Form
    
    /**
     * holds copy of object to access the mediaBox and cropBox values
     */
    private PdfPageData pageData;
    
    /**
     * number of entries in acroFormDataList, each entry can have a button group of more that one button
     * 'A' annot and 'F' form - A is per page, F is total hence 3 variables
     */
    private int[] AfieldCount;
    
    private int ATotalCount,FfieldCount;

    private int additionalOBjectRef;

    private boolean addedMissingPopup;

    /**
     * number of pages in current PDF document
     */
    int pageCount;
    
    /**
     * handle on object reader for decoding objects
     */
    PdfObjectReader currentPdfFile;
    
    /**
     * parses and decodes PDF data into generic data for converting to widgets
     */
    FormStream fDecoder;
    
    /**
     * handles events like URLS, EMAILS
     */
    private ActionHandler formsActionHandler;
    
    /**
     * handles Javascript events
     */
    private Javascript javascript;
    
    /*flag to show if XFA or FDF*/
    boolean hasXFA;
    private boolean isContainXFAStream;
    
    /**
     * flag to show if we use XFA
     */
    private boolean useXFA;

    /**
     * allow us to differentiate underlying PDF form type
     */
    Enum PDFformType;
    
    private SwingFormCreator formCreator;

    /**
     * used to create version without XFA support in XFA version.
     * Should not be used otherwise.
     */
    public AcroRenderer(){}
    
    public void useXFAIfAvailable(final boolean useXFA) {

        this.useXFA=useXFA;
        
    }
    
    /**
     * reset handler (must be called Before page opened)
     * - null Object resets to default
     */
    public void resetHandler(final ActionHandler formsActionHandler, final float dpi, final Javascript javascript) {
        
        this.formsActionHandler=formsActionHandler;
        
        this.dpi=dpi;
        
        this.javascript=javascript;
        
        //pass values down
        if (formFactory != null){
            formFactory.reset(this.getFormResources(), formsActionHandler,pageData,currentPdfFile);
        }
    }
    
    /**
     * make all components invisible on all pages by removing from Display
     */
    public void removeDisplayComponentsFromScreen() {
        
        if(compData!=null) {
            compData.removeAllComponentsFromScreen();
        }
        
    }
    
    /**
     * initialise holders and variables, data structures and get a handle on data object
     */
    public int openFile(final int pageCount, final int insetW, final int insetH, final PdfPageData pageData, final PdfObjectReader currentPdfFile, final PdfObject acroObj) {
        
        this.pageCount = pageCount;
        this.currentPdfFile = currentPdfFile;
        this.pageData = pageData;

        compData.flushFormData();
        
        //explicitly flush
        sigObject=null;
        sigKeys=null;
        
        //track inset on page
        compData.setPageData(pageData,insetW,insetH);
        
        if (acroObj == null) {
            
            FfieldCount = 0;
            
            fieldList=null;
        } else{
            
            //handle XFA
            final PdfObject XFAasStream;
            PdfArrayIterator XFAasArray = null;
            
            XFAasStream=acroObj.getDictionary(PdfDictionary.XFA);
            if(XFAasStream==null){
                XFAasArray=acroObj.getMixedArray(PdfDictionary.XFA);
                
                //empty array
                if(XFAasArray!=null && XFAasArray.getTokenCount()==0) {
                    XFAasArray = null;
                }
            }
            
            hasXFA= XFAasStream!=null || XFAasArray!=null;
            isContainXFAStream = hasXFA;

            /*
             * now read the fields
             */
            fieldList = acroObj.getMixedArray(PdfDictionary.Fields);
            CO = acroObj.getObjectArray(PdfDictionary.CO);
            
            if(fieldList!=null){
                FfieldCount = fieldList.getTokenCount();
                
                AcroRes=acroObj.getDictionary(PdfDictionary.DR);
                
                if(AcroRes!=null) {
                    currentPdfFile.checkResolved(AcroRes);
                }
                
            }else{
                FfieldCount=0;
                AcroRes=null;
            }
            
            /*
             * choose correct decoder for form data
             */
            if (hasXFA && useXFA){
                processXFAFields(acroObj, currentPdfFile, pageData);
            }           
            
            //we need to read list if FDF
            //or redo list if Legacy XFA
            if(!hasXFA) {
                resolveIndirectFieldList(false);
            }
           
        }
        
        resetContainers(true);
        
        return pageCount;
    }

    /**
     * empty implementation in non-XFA AcroRenderer
     * 
     * @param acroObj1
     * @param currentPdfFile1
     * @param pageData1 
     */
    void processXFAFields(final PdfObject acroObj1, final PdfObjectReader currentPdfFile1, final PdfPageData pageData1) {
        throw new RuntimeException("This code (processXFAFields) should never be called");
    }
        
    void resolveIndirectFieldList(final boolean resolveParents){

        //allow for indirect
        while(FfieldCount==1){

            //may have been read before so reset
            fieldList.resetToStart();
            
            final String key=fieldList.getNextValueAsString(false);

            final FormObject kidObject = new FormObject(key);
            currentPdfFile.readObject(kidObject);

            final byte[][] childList =getKid(kidObject, resolveParents);

            if(childList==null) {
                break;
            }

            fieldList=new PdfArrayIterator(childList);
            FfieldCount = fieldList.getTokenCount();
        }
    }
    
    /**
     * initialise holders and variables and get a handle on data object
     * 
* Complicated as Annotations stored on a PAGE basis whereas FORMS stored on * a file basis */ public void resetAnnotData(final int insetW, final int insetH, final PdfPageData pageData, final int page, final PdfObjectReader currentPdfFile, final byte[][] currentAnnotList) { this.currentPdfFile = currentPdfFile; this.pageData = pageData; boolean resetToEmpty = true; addedMissingPopup = false; //track inset on page compData.setPageData(pageData,insetW,insetH); if (currentAnnotList==null) { AfieldCount = null; ATotalCount=0; if(annotList!=null) { annotList[page] = null; } annotList=null; }else{ int pageCount=pageData.getPageCount()+1; if(pageCount<=page) { pageCount = page + 1; } if(annotList==null){ annotList=new PdfArrayIterator[pageCount]; AfieldCount=new int[pageCount]; }else if(page>=annotList.length){ final PdfArrayIterator[] tempList=annotList; final int[] tempCount=AfieldCount; AfieldCount=new int[pageCount]; annotList=new PdfArrayIterator[pageCount]; for(int ii=0;ii formsProcessed=new HashMap(); int Acount=0; if(AfieldCount!=null && AfieldCount.length>page) { Acount = AfieldCount[page]; } Fforms = new FormObject[FfieldCount]; Aforms = new FormObject[Acount]; FormObject formObject; String objRef; int i, count; { //scan list for all relevant values and add to array if valid //0 = forms, 1 = annots final int decodeToForm = 2; for(int forms=0;formspage && annotList[page]!=null){ if(!isContainXFAStream && formFactory.getType()==FormFactory.HTML){ annotList[page].resetToStart(); final Map annotOrder=new HashMap(); final int count2=annotList[page].getTokenCount(); String val; for(int ii=0;ii-1; fieldNum--) { objRef=null; if(forms==0){ if(fieldList!=null) { objRef = fieldList.getNextValueAsString(true); } }else{ if(addedMissingPopup && !annotList[page].hasMoreTokens()){ //Ignore this as we have added our own object that does not need reading //with the PdfArrayIterator. Code positioned like this to explain. //Test File : baseline_screens\cid2\SampleError.pdf }else{ if(annotList.length>page && annotList[page]!=null) { objRef = annotList[page].getNextValueAsString(true); } } } if(objRef==null || ((formsProcessed.get(objRef)!=null || objRef.isEmpty()))) { continue; } try{ formObject=convertRefToFormObject(objRef,page); if(!isAnnotation(formObject)){ continue; } }catch(final Exception e){ LogWriter.writeLog("Exception "+e+" with "+objRef); continue; } /* * Only allows Annotations if in Annots page stream */ if(forms==0 && formObject!=null && formObject.getFormType()==-1){ continue; } if(allowsPopup(formObject) && formObject.getDictionary(PdfDictionary.Popup)==null){ final FormObject po = new FormObject(PdfDictionary.Annot); additionalOBjectRef++; po.setRef((-additionalOBjectRef)+" 0 X"); po.setIntNumber(PdfDictionary.F, 24); //Bit Flag for bits 4+5 (No Zoom, No Rotate) po.setBoolean(PdfDictionary.Open, formObject.getBoolean(PdfDictionary.Open)); po.setConstant(PdfDictionary.Subtype, PdfDictionary.Popup); final float[] rect = formObject.getFloatArray(PdfDictionary.Rect); if(pageData.getRotation(page)%180!=0) { po.setFloatArray(PdfDictionary.Rect, new float[]{rect[2], pageData.getCropBoxHeight(page)-100, rect[2]+160, pageData.getCropBoxHeight(page)}); } else { po.setFloatArray(PdfDictionary.Rect, new float[]{pageData.getCropBoxWidth(page), rect[3] - 100, pageData.getCropBoxWidth(page) + 160, rect[3]}); } po.setStringKey(PdfDictionary.Parent, formObject.getObjectRefAsString().getBytes()); po.setParentPdfObj(formObject); po.setPageNumber(page); formObject.setDictionary(PdfDictionary.Popup, po); final FormObject[] newForms = new FormObject[Aforms.length+1]; for(int ii=0; ii!=Aforms.length; ii++){ newForms[ii] = Aforms[ii]; } newForms[Aforms.length] = po; Aforms = newForms; addedMissingPopup = true; } final byte[][] kids=formObject.getKeyArray(PdfDictionary.Kids); if(kids!=null) //not 'proper' kids so process here { i = flattenKids(page, formsProcessed, formObject, i, forms); } else { i = processFormObject(page, formsProcessed, formObject, objRef, i, forms); } } } } final List unsortedForms= new ArrayList(); final List sortedForms = new ArrayList(); compData.setListForPage(page,unsortedForms,false); compData.setListForPage(page, sortedForms, true); final Map formsCreated = createAndStoreFormComponents(current, unsortedForms, sortedForms, page); if(!formsRasterizedForDisplay()){ // Go through all forms created and run through javascript for initiation try{ //get current page object final String ref = currentPdfFile.getReferenceforPage(page); final PageObject pageObj = new PageObject(ref); currentPdfFile.readObject(pageObj); //call Page Level open commands if (javascript != null && formsActionHandler!=null) { //NOTE: moved here as the Runnable can be executed after forms have been created which is too late. formsActionHandler.O(pageObj,PdfDictionary.AA); formsActionHandler.O(pageObj,PdfDictionary.A);//just in case formsActionHandler.PO(pageObj,PdfDictionary.AA); formsActionHandler.PO(pageObj,PdfDictionary.A);//just in case } if(formFactory.getType()!=FormFactory.HTML && formFactory.getType()!=FormFactory.SVG){ //then initilise each field initJSonFields(formsCreated); } }catch(final Exception e){ LogWriter.writeLog("Exception: " + e.getMessage()); } } } } private Map createAndStoreFormComponents(final PdfStreamDecoder current, final List unsortedForms, final List sortedForms, final int page) { final Map formsCreated=new HashMap(); FormObject[] xfaFormList = null; FormObject formObject; int count; if (hasXFA && useXFA) { xfaFormList = createXFADisplayComponentsForPage(xfaFormList, page); } //XFA, FDF FORMS then ANNOTS final int readToForm = 3; for (int forms = 0; forms < readToForm; forms++) { count = 0; if (forms == 0) { if (xfaFormList != null) { count = xfaFormList.length; } } else if (forms == 1) { if (Fforms == null) { count = 0; } else { //store current order of forms for printing for (final FormObject Fform : Fforms) { if (Fform != null) { unsortedForms.add(Fform); } } //sort forms into size order for display Fforms = FormUtils.sortGroupLargestFirst(Fforms); count = Fforms.length; } } else { //store current order of forms for printing for (final FormObject Aform : Aforms) { if (Aform != null) { unsortedForms.add(Aform); } } //sort forms into size order for display if (!formsRasterizedForDisplay()) { Aforms = FormUtils.sortGroupLargestFirst(Aforms); } if (isContainXFAStream) { final HashMap> tabMap = new HashMap>(); double maxY = 0; for (final FormObject obj : Aforms) { if (obj != null) { final int x = obj.getBoundingRectangle().x; final Double y = obj.getBounding2DRectangleForTabbing().getY(); maxY = Math.max(y, maxY); if (tabMap.containsKey(y)) { final ArrayList fList = tabMap.get(y); int insertion = -1; for (int z = 0; z < fList.size(); z++) { final int nextX = fList.get(z).getBoundingRectangle().x; if (nextX < x) { insertion = z; } } if (insertion == -1) { fList.add(0, obj); } else { fList.add(insertion + 1, obj); } } else { final ArrayList list = new ArrayList(); list.add(obj); tabMap.put(y, list); } } } final FormObject[] finalList = new FormObject[Aforms.length]; int objCount = 0; final Object[] keys = new Object[tabMap.size()]; int cc = 0; for (final Object k : tabMap.keySet().toArray()) { keys[cc] = k; cc++; } Arrays.sort(keys); for (int k = keys.length; k > 0; k--) { final ArrayList objList = tabMap.get(keys[k - 1]); if (objList != null) { for (final FormObject f : objList) { finalList[objCount] = f; objCount++; } } } Aforms = finalList; } count = Aforms.length; } boolean firstPopup = true; for (int k = 0; k < count; k++) { if (forms == 0) { formObject = xfaFormList[k]; } else if (forms == 1) { formObject = Fforms[k]; } else { formObject = Aforms[k]; } if (formObject != null && (formsCreated.get(formObject.getObjectRefAsString()) == null) && page == formObject.getPageNumber()) {// && !formObject.getObjectRefAsString().equals("216 0 R")){ final int type = formFactory.getType(); //NOTE: if this custom form needs redrawing more changediff ReadOnlyTextIcon.MAXSCALEFACTOR to 1; if ((formsRasterizedForDisplay() && current != null) || (type == FormFactory.SVG && formObject.getParameterConstant(PdfDictionary.Subtype) != PdfDictionary.Link) || (formFactory.flattenForms() && !AcroRenderer.isAnnotation(formObject))) { //rasterize any flattened PDF forms here try { getFormFlattener().drawFlattenedForm(current, formObject, type == FormFactory.HTML || type == FormFactory.SVG, (PdfObject) this.getFormResources()[0]); } catch (final PdfException e) { LogWriter.writeLog("Exception: " + e.getMessage()); } } else { createField(formObject); //now we turn the data into a Swing component //set the raw data here so that the field names are the fully qualified names compData.storeRawData(formObject); //store data so user can access formsCreated.put(formObject.getObjectRefAsString(), "x"); //original method we still use for HTML/SVG if (type == FormFactory.HTML || type == FormFactory.SVG || type == FormFactory.JAVAFX) { sortedForms.add(formObject); //neede in display to fix position issues } else if (formObject.getParameterConstant(PdfDictionary.Subtype) == PdfDictionary.Popup) { /* * To match examples the first popup is drawn over all * then we draw all other popups in the pdf order from * the bottom to the one before the top */ if (firstPopup) { sortedForms.add(formObject); firstPopup = false; } else { sortedForms.add(sortedForms.size() - 1, formObject); } } else { sortedForms.add(0, formObject); } } } } } return formsCreated; } /** * Utility method to check if formObject should have a popup * @return True if popup should exist */ static boolean allowsPopup(final FormObject formObject){ switch(formObject.getParameterConstant(PdfDictionary.Subtype)){ case PdfDictionary.Text : // case PdfDictionary.Line : case PdfDictionary.Square : // case PdfDictionary.Circle : // case PdfDictionary.Polygon : // case PdfDictionary.PolyLine : case PdfDictionary.Highlight : case PdfDictionary.Underline : // case PdfDictionary.Squiggly : case PdfDictionary.StrickOut : case PdfDictionary.Stamp : // case PdfDictionary.Caret : // case PdfDictionary.Ink : // case PdfDictionary.FileAttachment : // case PdfDictionary.Sound : // case PdfDictionary.Movie : // case PdfDictionary.Widget : // case PdfDictionary.Screen : // case PdfDictionary.RichMedia: // case PdfDictionary.PrinterMark : // case PdfDictionary.TrapNet : // case PdfDictionary.Watermark : // case PdfDictionary.3D : return true; default : return false; } } /** * Utility method to ensure formObject is actually an annotation before we continue * @return True if annotation */ public static boolean isAnnotation(final FormObject formObject){ if(formObject.getParameterConstant(PdfDictionary.Type)==PdfDictionary.Annot){ return true; } switch(formObject.getParameterConstant(PdfDictionary.Subtype)){ case PdfDictionary.Text : case PdfDictionary.Link : case PdfDictionary.FreeText : case PdfDictionary.Line : case PdfDictionary.Square : case PdfDictionary.Circle : case PdfDictionary.Polygon : case PdfDictionary.PolyLine : case PdfDictionary.Highlight : case PdfDictionary.Underline : case PdfDictionary.Squiggly : case PdfDictionary.StrickOut : case PdfDictionary.Stamp : case PdfDictionary.Caret : case PdfDictionary.Ink : case PdfDictionary.Popup : case PdfDictionary.FileAttachment : case PdfDictionary.Sound : case PdfDictionary.Movie : case PdfDictionary.Widget : case PdfDictionary.Screen : case PdfDictionary.PrinterMark : case PdfDictionary.TrapNet : case PdfDictionary.Watermark : case PdfDictionary.THREE_D : // From the Supplement to the PDF spec case PdfDictionary.RichMedia: case PdfDictionary.Projection : return true; default : return false; } } private void storeSignatures(final FormObject formObject, final int formType) { //if sig object set global sig object so we can access later if(formType == PdfDictionary.Sig){ if(sigObject==null){ //ensure initialised sigObject = new HashSet(); sigKeys=new HashMap(); } if(!sigKeys.containsKey(formObject.getObjectRefAsString())) { //avoid duplicates sigObject.add(formObject); sigKeys.put(formObject.getObjectRefAsString(),"x"); } } } private int flattenKids(final int page, final Map formsProcessed, final FormObject formObject, int i, final int forms) { final byte[][] kidList=formObject.getKeyArray(PdfDictionary.Kids); final int kidCount=kidList.length; //resize to fit if(forms==0){ final int oldCount=Fforms.length; final FormObject[] temp=Fforms; Fforms=new FormObject[oldCount+kidCount-1]; System.arraycopy(temp, 0, Fforms, 0, oldCount); }else{ final int oldCount=Aforms.length; final FormObject[] temp=Aforms; Aforms=new FormObject[oldCount+kidCount-1]; System.arraycopy(temp, 0, Aforms, 0, oldCount); } for (final byte[] aKidList : kidList) { //iterate through all parts final String key = new String(aKidList); //now we have inherited values, read final FormObject childObj = new FormObject(key); //inherit values childObj.copyInheritedValuesFromParent(formObject); currentPdfFile.readObject(childObj); childObj.setRef(key); if (childObj.getKeyArray(PdfDictionary.Kids) == null) { if(!childObj.isAppearanceUsed()){ new FormStream().createAppearanceString(childObj, currentPdfFile); } i = processFormObject(page, formsProcessed, childObj, key, i, forms); } else { i = flattenKids(page, formsProcessed, childObj, i, forms); } } return i; } private int processFormObject(final int page, final Map formsProcessed, final FormObject formObject, final String objRef, int i, final int forms) { boolean isOnPage=false; if(forms==0){ //check page isOnPage = isFormObjectOnPage(formObject, page); } if(forms==1 || isOnPage){ formObject.setPageNumber(page); final String parent=formObject.getStringKey(PdfDictionary.Parent); //clone parent to allow inheritance of values or create new if(parent!=null){ final FormObject parentObj = getParent(parent, formObject); /* * Getting the parent will also make any associated popup objects. * If this is a popup the parent will instead make a copy so that * we have a copy in annot list and one in form object. This is causing * issue in annotation saving and deletion. */ //Overwrite created popup here with the one we already have. if (formObject.getParameterConstant(PdfDictionary.Subtype) == PdfDictionary.Popup) { parentObj.setDictionary(PdfDictionary.Popup, formObject); } //inherited values if(parentObj!=null){ //all values are copied from the parent inside this call formObject.setParent(parent,parentObj,true); } } if(!formObject.isAppearanceUsed()){ fDecoder.createAppearanceString(formObject, currentPdfFile); } //Check that type returns as a valid value to lock out broken objects //Added for case 22215 if (formObject.getParameterConstant(PdfDictionary.Subtype)!=-1){ if(parent!=null) { formObject.setParent(parent);//parent object was added earlier } if(forms==0) { Fforms[i++] = formObject; } else { Aforms[i++] = formObject; } //also flag if(objRef!=null) { formsProcessed.put(objRef, "x"); } } } return i; } private boolean isFormObjectOnPage(final FormObject formObject, final int page){ PdfObject pageObj=formObject.getDictionary(PdfDictionary.P); byte[] pageRef=null; if(pageObj!=null) { pageRef = pageObj.getUnresolvedData(); } if(pageRef==null || pageObj==null){ final String parent=formObject.getStringKey(PdfDictionary.Parent); if(parent!=null){ final PdfObject parentObj = getParent(parent, null); pageObj=parentObj.getDictionary(PdfDictionary.P); if(pageObj!=null) { pageRef = pageObj.getUnresolvedData(); } } } if(pageRef==null){ final byte[][] kidList = getKid(formObject,false); if (kidList!=null && kidList.length>0) { final int kidCount=kidList.length; FormObject kidObject; for(int jj=0;jj formsCreated) { //scan all fields for javascript actions for (final String ref : formsCreated.keySet()) { final FormObject formObject = getFormObject(ref); javascript.execute(formObject, PdfDictionary.K,ActionHandler.FOCUS_EVENT, ' '); } } /** * create a widget to handle fields */ private void createField(final FormObject formObject) { //avoid creation of Swing widgets if we have 2 copies in play on ULC //noinspection PointlessBooleanExpression if(ExternalHandlers.isULCPresent() && formFactory.getType()==FormFactory.SWING){ return; } final Integer widgetType; //no value set final Object retComponent=null; final int formType=formObject.getNameAsConstant(PdfDictionary.FT); //FT final int formFactoryType=formFactory.getType(); //if sig object set global sig object so we can access later storeSignatures(formObject, formType); //check if a popup is associated if(formObject.getDictionary(PdfDictionary.Popup)!=null){ formObject.setActionFlag(FormObject.POPUP); } //flags used to alter interactivity of all fields final boolean readOnly; final boolean required; final boolean noexport; final boolean[] flags = formObject.getFieldFlags();//Ff if (flags != null) { //noinspection UnusedAssignment readOnly = flags[FormObject.READONLY_ID]; //noinspection UnusedAssignment required = flags[FormObject.REQUIRED_ID]; //noinspection UnusedAssignment noexport = flags[FormObject.NOEXPORT_ID]; /* * boolean comb=flags[FormObject.COMB_ID]; * boolean comminOnSelChange=flags[FormObject.COMMITONSELCHANGE_ID]; * boolean donotScrole=flags[FormObject.DONOTSCROLL_ID]; * boolean doNotSpellCheck=flags[FormObject.DONOTSPELLCHECK_ID]; * boolean fileSelect=flags[FormObject.FILESELECT_ID]; * boolean isCombo=flags[FormObject.COMBO_ID]; * boolean isEditable=flags[FormObject.EDIT_ID]; * boolean isMultiline=flags[FormObject.MULTILINE_ID]; * boolean isPushButton=flags[FormObject.PUSHBUTTON_ID]; * boolean isRadio=flags[FormObject.RADIO_ID]; * boolean hasNoToggleToOff=flags[FormObject.NOTOGGLETOOFF_ID]; * boolean hasPassword=flags[FormObject.PASSWORD_ID]; * boolean multiSelect=flags[FormObject.MULTISELECT_ID]; * boolean radioinUnison=flags[FormObject.RADIOINUNISON_ID]; * boolean richtext=flags[FormObject.RICHTEXT_ID]; * boolean sort=flags[FormObject.SORT_ID]; */ } //hard-coded for HTML non-forms if(!ExternalHandlers.isXFAPresent() && (formFactoryType==FormFactory.HTML || formFactoryType==FormFactory.SVG)){ widgetType=FormFactory.ANNOTATION; }else if (formType == PdfDictionary.Btn) {//----------------------------------- BUTTON ---------------------------------------- widgetType=createButtonField(flags); } else { widgetType=createInteractiveField(flags, formType); } formObject.setFormType(widgetType); if(formFactory.getType()==FormFactory.HTML || formFactory.getType()==FormFactory.SVG){ compData.checkGUIObjectResolved(formObject); }else if(retComponent!=null && formFactory.getType()!=FormFactory.SWING){ formObject.setGUIComponent(retComponent,formFactory.getType()); compData.setGUIComp(formObject, retComponent); } } private int createInteractiveField(final boolean[] flags, final int formType) { final int widgetType; switch (formType) { case PdfDictionary.Tx: boolean isMultiline = false, hasPassword = false;// doNotScroll = false, richtext = false, fileSelect = false, doNotSpellCheck = false; if (flags != null) { isMultiline = flags[FormObject.MULTILINE_ID]; hasPassword = flags[FormObject.PASSWORD_ID]; //doNotScroll = flags[FormObject.DONOTSCROLL_ID]; //richtext = flags[FormObject.RICHTEXT_ID]; //fileSelect = flags[FormObject.FILESELECT_ID]; //doNotSpellCheck = flags[FormObject.DONOTSPELLCHECK_ID]; } if (isMultiline) { if (hasPassword) { widgetType = FormFactory.MULTILINEPASSWORD; } else { widgetType = FormFactory.MULTILINETEXT; } } else {//singleLine if (hasPassword) { widgetType = FormFactory.SINGLELINEPASSWORD; } else { widgetType = FormFactory.SINGLELINETEXT; } } break; case PdfDictionary.Ch: //----------------------------------------- CHOICE ---------------------------------------------- //flags used for choice types //20100212 (ms) Unused ones commented out boolean isCombo = false;// multiSelect = false, sort = false, isEditable = false, doNotSpellCheck = false, comminOnSelChange = false; if (flags != null) { isCombo = flags[FormObject.COMBO_ID]; //multiSelect = flags[FormObject.MULTISELECT_ID]; //sort = flags[FormObject.SORT_ID]; //isEditable = flags[FormObject.EDIT_ID]; //doNotSpellCheck = flags[FormObject.DONOTSPELLCHECK_ID]; //comminOnSelChange = flags[FormObject.COMMITONSELCHANGE_ID]; } if (isCombo) {// || (type==XFAFORM && ((XFAFormObject)formObject).choiceShown!=XFAFormObject.CHOICE_ALWAYS)){ widgetType = FormFactory.COMBOBOX; } else {//it is a list widgetType = FormFactory.LIST; } break; case PdfDictionary.Sig: widgetType = FormFactory.SIGNATURE; break; default: //assume annotation if (formType == ANNOTATION) { widgetType = FormFactory.ANNOTATION; break; } return widgetType; } private int createButtonField(final boolean[] flags){ final int widgetType; //flags used for button types //20100212 (ms) Unused ones commented out boolean isPushButton = false, isRadio = false;// hasNoToggleToOff = false, radioinUnison = false; if (flags != null) { isPushButton = flags[FormObject.PUSHBUTTON_ID]; isRadio = flags[FormObject.RADIO_ID]; //hasNoToggleToOff = flags[FormObject.NOTOGGLETOOFF_ID]; //radioinUnison = flags[FormObject.RADIOINUNISON_ID]; } if (isPushButton) { widgetType=FormFactory.PUSHBUTTON; }else if(isRadio){ widgetType=FormFactory.RADIOBUTTON; }else { widgetType=FormFactory.CHECKBOXBUTTON; } return widgetType; } /** * If possible we recommend you work with the Form Objects rather than * resolve GUI components * * null key will return all values * * if pageNumber is -1 it will process whole document, otherwise just that * page * * For a full example of usage please see http://files.idrsolutions.com/samplecode/org/jpedal/examples/acroform/ExtractFormDataAsObject.java.html * * Object[] will vary depending on what ReturnValues enum is passed in and could contain String (Names), FormObject or Component */ public Object[] getFormComponents(final String objectName, final ReturnValues value, final int pageNumber) { switch(value) { case EMBEDDED_FILES: if(currentPdfFile.getNamesLookup()==null){ return new Object[]{}; } return currentPdfFile.getNamesLookup().getEmbeddedFiles(); default: /*make sure all forms decoded*/ if (pageNumber == -1) { for (int p = 1; p < this.pageCount + 1; p++) //add init method and move scaling/rotation to it { createDisplayComponentsForPage(p, null); } } else { createDisplayComponentsForPage(pageNumber, null); } return compData.getFormComponents(objectName, value, pageNumber).toArray(); } } /** * setup object which creates all GUI objects */ public void setFormFactory(final FormFactory newFormFactory) { formFactory = newFormFactory; /* * allow user to create custom structure to hold data */ compData=formFactory.getCustomCompData(); } /** * get GUIData object with all widgets */ public GUIData getCompData() { return compData; } /**return Signature as iterator with one or more objects or null*/ public Iterator getSignatureObjects() { if(sigObject==null) { return null; } else { return sigObject.iterator(); } } public ActionHandler getActionHandler() { return formsActionHandler; } public FormFactory getFormFactory() { return formFactory; } public void setIgnoreForms(final boolean ignoreForms) { this.ignoreForms=ignoreForms; } public boolean ignoreForms() { return ignoreForms || ignoreAllForms; } public void dispose() { AfieldCount = null; fDecoder=null; formsActionHandler=null; if(javascript!=null){ javascript.dispose(); } javascript=null; Fforms=null; Aforms=null; fieldList=null; annotList=null; formFactory=null; if(compData!=null){ compData.dispose(); } compData=null; if(sigObject!=null){ sigObject.clear(); } sigObject=null; if(sigKeys!=null){ sigKeys.clear(); } sigKeys=null; pageData=null; if(currentPdfFile!=null){ currentPdfFile.dispose(); } currentPdfFile=null; fDecoder=null; formCreator = null; } /** * get Iterator with list of all Annots on page or * return null if no Annots - no longer needs * call to decodePage beforehand as checks itself * * @deprecated - getFormComponents(String objectName, ReturnValues value,int pageNumber) recommended * as much more flexible */ @Deprecated public PdfArrayIterator getAnnotsOnPage(final int page) { //check annots decoded - will just return if done createDisplayComponentsForPage(page,null); if(annotList!=null && annotList.length>page && annotList[page]!=null){ annotList[page].resetToStart(); return annotList[page]; }else{ return null; } } /** * returns false if not XFA (or XFA in Legacy mode) * and true if XFA using XFA data * @return */ public boolean isXFA() { return hasXFA; } public boolean useXFA() { return useXFA; } public boolean hasFormsOnPage(final int page) { final boolean hasAnnots=(annotList!=null && annotList.length>page && annotList[page]!=null); final boolean hasForm=(hasXFA && useXFA && fDecoder.hasXFADataSet())||fieldList!=null; return hasAnnots || hasForm; } public Object[] getFormResources() { return new Object[]{AcroRes,CO}; } public boolean formsRasterizedForDisplay() { return compData.formsRasterizedForDisplay(); } /** * get FormObject * @param ref * @return * In all modes except HTML,SVG,JavaFX will decode other forms on pages if not * found */ public FormObject getFormObject(final String ref) { FormObject obj = compData.getRawFormData().get(ref); //if not found now decode all page and retry if (obj == null && formFactory.getType()!=FormFactory.HTML && formFactory.getType()!=FormFactory.SVG) { for (int ii = 1; ii < this.pageCount; ii++) { createDisplayComponentsForPage(ii, null); obj = compData.getRawFormData().get(ref); if (obj != null) { break; } } } return obj; } public void setInsets(final int width, final int height){ compData.setPageData(compData.pageData, width, height); } FormObject convertRefToFormObject(final String objRef, final int page) { FormObject formObject = compData.getRawFormData().get(objRef); if (formObject == null) { formObject = new FormObject(objRef); if(page!=-1) { formObject.setPageRotation(pageData.getRotation(page)); } //formObject.setPDFRef((String)objRef); if (objRef.charAt(objRef.length() - 1) == 'R') { currentPdfFile.readObject(formObject); } else { //changed by Mark as cover <<>> as well as 1 0 R formObject.setStatus(PdfObject.UNDECODED_REF); formObject.setUnresolvedData(StringUtils.toBytes(objRef), -1); currentPdfFile.checkResolved(formObject); } compData.storeRawData(formObject); } return formObject; } /** * Allow user to get ENUM to show type of form * FormTypes (XFA_LEGACY, XFA_DYNAMIC, NON_XFA) * @return */ public Enum getPDFformType() { return PDFformType; } public void alwaysuseXFA(final boolean alwaysUseXFA) { this.alwaysUseXFA=alwaysUseXFA; } public boolean alwaysuseXFA() { return alwaysUseXFA; } public void init(final SwingFormCreator formCreator) { this.formCreator=formCreator; compData=formCreator.getData(); } public PdfStreamDecoder getStreamDecoder(final PdfObjectReader currentPdfFile, final PdfLayerList layer, final boolean isFirst) { if(isFirst){ return new PdfStreamDecoder(currentPdfFile); }else{ return new PdfStreamDecoder(currentPdfFile,layer); } } public boolean showFormWarningMessage(final int page) { boolean warnOnceOnForms=false; if(hasXFA){ warnOnceOnForms=true; System.out.println("[WARNING] This file contains XFA forms that are not supported by this version of JPDF2HTML5. To convert into functional HTML forms and display non-legacy mode page content, JPDF2HTML5 Forms Edition must be used."); }else if(hasFormsOnPage(page)){ warnOnceOnForms=true; System.out.println("[WARNING] This file contains form components that have been rasterized. To convert into functional HTML forms, JPDF2HTML5 Forms Edition must be used."); } return warnOnceOnForms; } FormObject[] createXFADisplayComponentsForPage(final FormObject[] xfaFormList, final int page) { throw new UnsupportedOperationException("createXFADisplayComponentsForPage should never be called"); } public HashMap getPageMapXFA() { throw new UnsupportedOperationException("getPageMapXFA should never be called"); } public byte[] getXMLContentAsBytes(final int dataType) { return null; } public void outputJavascriptXFA(final String path, final String name) { throw new UnsupportedOperationException("outputJavascriptXFA should never be called"); } public PrintStreamDecoder getStreamDecoderForPrinting(final PdfObjectReader currentPdfFile, final PdfLayerList pdfLayerList) { return new PdfStreamDecoderForPrinting(currentPdfFile, pdfLayerList); } public BufferedImage decode(final PdfObject pdfObject, final PdfObjectReader currentPdfFile, final PdfObject XObject, final int subtype, final int width, final int height, final int offsetImage, final float pageScaling) { LogWriter.writeLog("called decode("+pdfObject+", "+ currentPdfFile+", "+ XObject+", "+subtype+", "+width+", "+height+", "+offsetImage+", "+pageScaling); return null; } public FormFlattener getFormFlattener() { return new FormFlattener(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy