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

org.jpedal.objects.raw.FormStream 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-2015 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


 *
 * ---------------
 * FormStream.java
 * ---------------
 */
package org.jpedal.objects.raw;



import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;
import org.jpedal.external.ExternalHandlers;
import org.jpedal.fonts.FontMappings;
import org.jpedal.fonts.PdfFont;
import org.jpedal.fonts.StandardFonts;
import org.jpedal.io.ObjectStore;
import org.jpedal.io.PdfObjectReader;
import org.jpedal.parser.PdfStreamDecoder;
import org.jpedal.parser.ValueTypes;
import org.jpedal.render.*;
import org.jpedal.utils.LogWriter;


/**
 * can object and creat images, set values in Appearances
 */
public class FormStream {

    public static final boolean debugUnimplemented = false;//to show unimplemented parts*/
    public static final boolean debug = false;//print info to screen

    //only display once
    private static boolean showFontMessage;

    /**
     * exit when an unimplemented feature or error has occured in form/annot code
     */
    public static final boolean exitOnError=false;

    /** handle of file reader for form streams*/
    protected PdfObjectReader currentPdfFile;

    /**
     * flag to show if XFA (will be disabled if XFA from version which is not pure XFA)
     */
    public boolean isXFA;
    
    /**
     * stop anyone creating empty  instance
     */
    public FormStream(){}

    public static final int[] id = {PdfDictionary.A,PdfDictionary.C2,PdfDictionary.Bl,
            PdfDictionary.E, PdfDictionary.X, PdfDictionary.D, PdfDictionary.U, PdfDictionary.Fo,
            PdfDictionary.PO, PdfDictionary.PC, PdfDictionary.PV,
            PdfDictionary.PI, PdfDictionary.O, PdfDictionary.C1, PdfDictionary.K,
            PdfDictionary.F, PdfDictionary.V, PdfDictionary.C2, PdfDictionary.DC,
            PdfDictionary.WS, PdfDictionary.DS, PdfDictionary.WP, PdfDictionary.DP};

    /**
     * takes in a FormObject already populated with values for the child to overwrite
     */
    public void createAppearanceString(final FormObject formObj, final PdfObjectReader inCurrentPdfFile) {

        currentPdfFile = inCurrentPdfFile;
        
        init(formObj);

    }

    private void init(final FormObject formObject) {

        final boolean debug=false;//formObject.getPDFRef().equals("68 0 R");

        if(debug) {
            System.out.println("------------------------------setValues-------------------------------" + formObject + ' ' + formObject.getObjectRefAsString());
        }

        //set Ff flags
        final int Ff=formObject.getInt(PdfDictionary.Ff);
        if(Ff!=PdfDictionary.Unknown) {
            formObject.commandFf(Ff);
        }

        //set Javascript
        resolveAdditionalAction(formObject);

        if(debug) {
            System.out.println("AP=" + formObject.getDictionary(PdfDictionary.AP));
        }


        //at the moment only handles static
        // (and not dynamic which are created at Runtime if
        // formObject.getBoolean(PdfDictionary.NeedAppearances) is true
        setupAPimages(formObject);


        //set H
        final int key = formObject.getNameAsConstant(PdfDictionary.H);
        if(key!=PdfDictionary.Unknown){
            /**
             * highlighting mode
             * done when the mouse is pressed or held down inside the fields active area
             * N nothing
             * I invert the contents
             * O invert the border
             * P display down appearance stream, or if non available offset the normal to look down
             * T same as P
             *
             * this overides the down appearance
             * Default value = I
             */
            if (key==PdfDictionary.T || key==PdfDictionary.P) {
                if (!formObject.hasDownImage()) {
                    formObject.setOffsetDownApp();
                }

            } else if (key==PdfDictionary.N) {
                //do nothing on press
                formObject.setNoDownIcon();

            } else if (key==PdfDictionary.I) {
                //invert the contents colors
                formObject.setInvertForDownIcon();

            }
        }

        //set Fonts

        final String textStream=formObject.getTextStreamValue(PdfDictionary.DA);

        if(textStream!=null){
            decodeFontCommandObj(textStream, formObject);
        }
    }

    /** decodes and stores the ap images */
    public static void setupAPimages(final FormObject formObject) {

        final PdfObject APobjN = formObject.getDictionary(PdfDictionary.AP).getDictionary(PdfDictionary.N);
        //check for null to stop nullpointer on files with no Appearance Images
        if(APobjN!=null){

            formObject.setAppreancesUsed(true);
            formObject.setNormalOnState(formObject.getName(PdfDictionary.AS));

            /**
             * workout default selection
             */
            if(APobjN.getDictionary(PdfDictionary.On) !=null){
                formObject.setNormalOnState("On");
            }else {
                final Map otherValues=APobjN.getOtherDictionaries();
                if(otherValues!=null && !otherValues.isEmpty()){
                    final Iterator keys=otherValues.keySet().iterator();
                    String key;
                    while(keys.hasNext()){
                        key=(String)keys.next();
                        formObject.setNormalOnState(key);
                    }
                }
            }

            //moved to end as flagLastUsed can call the imageicon
            final String defaultState = formObject.getName(PdfDictionary.AS);

            if (defaultState != null && defaultState.equals(formObject.getNormalOnState())) {
                formObject.setSelected(true);
            }
        }

    }

    /**
     * defines actions to be executed on events 'Trigger Events'
     *
     * @Action This is where the raw data is parsed and put into the FormObject
     */
    private void resolveAdditionalAction(final FormObject formObject) {

        /**
         * entries NP, PP, FP, LP never used
         * A action when pressed in active area ?some others should now be ignored?
         * E action when cursor enters active area
         * X action when cursor exits active area
         * D action when cursor button pressed inside active area
         * U action when cursor button released inside active area
         * Fo action on input focus
         * BI action when input focus lost
         * PO action when page containing is opened,
         * 	actions O of pages AA dic, and OpenAction in document catalog should be done first
         * PC action when page is closed, action C from pages AA dic follows this
         * PV action on viewing containing page
         * PI action when no longer visible in viewer
         * K action on - [javascript]
         * 	keystroke in textfield or combobox
         * 	modifys the list box selection
         * 	(can access the keystroke for validity and reject or modify)
         * F the display formatting of the field (e.g 2 decimal places) [javascript]
         * V action when fields value is changed [javascript]
         * C action when another field changes (recalculate this field) [javascript]
         */
        int idValue;

        for (final int anId : id) {

            //store most actions in lookup table to make code shorter/faster
            idValue = anId;

            currentPdfFile.setJavascriptForObject(formObject, PdfDictionary.AA, idValue);
            currentPdfFile.setJavascriptForObject(formObject, PdfDictionary.A, idValue);
        }
    }
    
    /**
     * decode appearance stream and convert into VectorRenderObject we can redraw
     * if width and height are 0 we define the size hear
     * offsetImage - 0= no change, 1= offset, 2= invert image
     * pScaling used by HTML - set to 1 otherwise
     */
    public static BufferedImage decode(final PdfObject formObj, final PdfObjectReader currentPdfFile, final PdfObject XObject, final int subtype,
    		int width, int height, final int offsetImage, final float pageScaling){
    	
        //handle XFA differently
        if(XObject.getObjectType()==PdfDictionary.XFA_APPEARANCE){
            
            return ExternalHandlers.decode(formObj, currentPdfFile, XObject, subtype, width, height, offsetImage, pageScaling);
        }
        
        //NOTE iconRotation kept to keep api but iconRotation is never used and NOT needed
        final boolean useHires=true;

    	currentPdfFile.checkResolved(XObject);
    	try{

    		/**
    		 * generate local object to decode the stream
    		 */
            final ObjectStore localStore = new ObjectStore();


    		/**
    		 * create renderer object
    		 */
    		final T3Renderer glyphDisplay=new T3Display(0,false,20,localStore);
            
    		//fix for hires
    		if(useHires){
                glyphDisplay.setHiResImageForDisplayMode(useHires);
            }

            final PdfStreamDecoder glyphDecoder=new PdfStreamDecoder(currentPdfFile,useHires,null); //switch to hires as well
            glyphDecoder.setParameters(false,true,15,0,false,false);

            glyphDecoder.setStreamType(ValueTypes.FORM);

            glyphDecoder.setObjectValue(ValueTypes.ObjectStore,localStore);

            glyphDecoder.setRenderer(glyphDisplay);

    		/**read any resources*/
    		try{
    			PdfObject Resources =XObject.getDictionary(PdfDictionary.Resources);

                //because N,D,R are very complicated with potentially paired values,
                //Resources can end up here
                //see   baseline_screens/14jul/18093.pdf
                if(Resources==null) {
                    Resources = (PdfObject) XObject.getOtherDictionaries().get("Resources");
                }

    			if (Resources != null) {
                    glyphDecoder.readResources(Resources, false);
                }

    		}catch(final Exception e){
    			LogWriter.writeLog("Exception: " + e.getMessage());
            }

            /**decode the stream*/
    		final byte[] commands=XObject.getDecodedStream();

            final float[] matrix=XObject.getFloatArray(PdfDictionary.Matrix);
            final float[] BBox=XObject.getFloatArray(PdfDictionary.BBox);
    		
            glyphDecoder.setBBox(BBox);
            
            if(commands!=null) {
                glyphDecoder.decodeStreamIntoObjects(commands, false);
            }

    		final boolean ignoreColors=glyphDecoder.ignoreColors;

    		localStore.flush();

    		final org.jpedal.fonts.glyph.T3Glyph form= new org.jpedal.fonts.glyph.T3Glyph(glyphDisplay, 0,0,ignoreColors);

            final float scaling;
    		
    		float rectX1=0,rectY1=0;
    		if(BBox!=null){

                for(int ii=0;ii<4;ii++) {
                    BBox[ii] *= pageScaling;
                }

    			rectX1 = (BBox[0]);
    			rectY1 = (BBox[1]);
                
                //Some files have fractions of a pixel in their size In some cases 
                //this needs to be ignored, other times it should be expanded to a full pixel
                //At the moment this is not required, this note is left as a reminder.
				int boxWidth=(int) (((BBox[2]+0.5f)-BBox[0]));
				if(boxWidth<0) {
                    boxWidth = -boxWidth;
                }
				int boxHeight=(int) (((BBox[3]+0.5f)-BBox[1]));
				if(boxHeight<0) {
                    boxHeight = -boxHeight;
                }

    			if(boxWidth==0 && boxHeight>0) {
                    boxWidth = 1;
                }
    			if(boxWidth>0 && boxHeight==0) {
                    boxHeight = 1;
                }
    			
    			//if the width and height scaling are miles apart then the width and height 
   				//are probably the wrong way round so swap them. and recalc the scalings.
    			float ws = ((float)width)/((float)boxWidth);
				float hs = ((float)height)/((float)boxHeight);
				
				//check if dimensions are correct and alter if not
				final float diff = ws-hs;
				final int diffInt = (int)diff;
				if(diffInt!=0){
					//NOTE width and height sent in need to be rotated
					//as they are not as the image is drawn
					final int tmpI = width;
					width = height;
					height = tmpI;
					
					ws = ((float)width)/((float)boxWidth);
					hs = ((float)height)/((float)boxHeight);
				}
				//NOTE now we re set the width and height to scaled 
				//value of Bounding box to keep the orientation
				
				//if scaling less than 1 use 1
				if(ws<1 || hs<1){
					scaling = 1;
					width = boxWidth;
					height = boxHeight;
				}else {
					//use larger scaling as will produce better image
					if(ws>hs){
						scaling = ws;
						height = (int) (boxHeight*scaling);
					}else {
						scaling = hs;
						width = (int) (boxWidth*scaling);
					}
					
					//make sure image position is scaled
					rectX1*=scaling;
					rectY1*=scaling;
				}
				
    		}else {

    			final float defaultSize = 20;
    			if(heighths){
					scaling = ws;
					height=(int)(defaultSize*scaling);
				}else {
					scaling = hs;
					width=(int)(defaultSize*scaling);
				}
				
				//make sure image position is scaled
				rectX1*=scaling;
				rectY1*=scaling;
    		}
    		
    		if(width==0 || height==0) {
                return null;
            }
    		
    		//This makes ink icons incorrect so commented out
//    		if(scaling>1){
//    			height+=2;
//    			width+=2;
//    		}

    		//if offset
    		if(offsetImage==1){
    			width+=2;
    			height+=2;
    		}
    		
    		final BufferedImage aa;
    		final Graphics2D g2;
    		
            final float a;
            final float b;
            final float c;
            final float d;
            float e;
            float f;
            int offset=height;

            if(matrix!=null){

                //Added for odd case 22179
                //pageScaling!=1 added to lock out of html as when not 1 html baseline is affected
                if (pageScaling==1 && matrix[4] > 0 && matrix[5] > 0) {
                    
//                    final float[] BoundingBox = XObject.getFloatArray(PdfDictionary.BBox);
                    final float[] BBox2 = formObj.getFloatArray(PdfDictionary.Rect);
                    if (BBox2[1] > BBox2[3]) {
                        float t = BBox2[1];
                        BBox2[1] = BBox2[3];
                        BBox2[3] = t;
                    }

                    if (BBox2[0] > BBox2[2]) {
                        float t = BBox2[0];
                        BBox2[0] = BBox2[2];
                        BBox2[2] = t;
                    }
                    
                    matrix[0] = (BBox2[2] - BBox2[0]) / (BBox[2] - BBox[0]);
                    matrix[1] = 0;
                    matrix[2] = 0;
                    matrix[3] = (BBox2[3] - BBox2[1]) / (BBox[3] - BBox[1]);
                    matrix[4] = (BBox2[0] - BBox[0]);
                    matrix[5] = (BBox2[1] - BBox[1]);

                    a = matrix[0];
                    b = matrix[1];
                    c = matrix[2];
                    d = matrix[3];
                    //scale so they offset correctly
                    e = matrix[4];
                    f = matrix[5];
                    //pdfStreamDecoder.gs.CTM = new float[][]{{matrix[0],matrix[1],0},{matrix[2],matrix[3],0},{matrix[4],matrix[5],1}};
                    //newClip=new Area(new Rectangle((int)BBox2[0],(int)BBox2[1],(int)((BBox2[2]-BBox2[0])+2),(int)((BBox2[3]-BBox2[1])+2)));                   
                }else{
                    a = matrix[0];
                    b = matrix[1];
                    c = matrix[2];
                    d = matrix[3];
                    //scale so they offset correctly
                    e = matrix[4] * scaling * pageScaling;
                    f = matrix[5] * scaling * pageScaling;
                }
    			if(c!=0){
    				aa=new BufferedImage(height,width,BufferedImage.TYPE_INT_ARGB);
    				offset=width;
    			}else{
    				aa=new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
    				if(b<0){
    					//already set at this
//	    				if(e!=0f)
//	    					e = matrix[4];
//	    				if(f!=0f)
//	    					f = matrix[5];
    				}else {
    					//rectX1 and rectY1 already have the scaling applied
	    				if(e!=0f) {
                            e = -rectX1;
                        }
	    				if(f!=0f) {
                            f = -rectY1;
                        }
    				}
    				
    			}
    			
    			g2=(Graphics2D) aa.getGraphics();
    		    final AffineTransform flip=new AffineTransform();
    			flip.translate(0, offset);
    			flip.scale(1, -1);
    			g2.setTransform(flip);

    			if(debug) {
                    System.out.println(" rectX1 = " + rectX1 + " rectY1 = " + rectY1 + " width = " + width + " height = " + height);
                }

    			final AffineTransform affineTransform = new AffineTransform(a,b,c,d,e,f);
//				System.out.println("affine="+affineTransform);
    			g2.transform(affineTransform);
    		} else {
    			aa=new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
    			
    			g2=(Graphics2D) aa.getGraphics();

    			final AffineTransform flip=new AffineTransform();
    			flip.translate(0, offset);
    			flip.scale(1, -1);
    			g2.setTransform(flip);
    		}

            if(offsetImage==2)//invert
            {
                g2.scale(-1, -1);
            } else if(offsetImage==1)//offset
            {
                g2.translate(1, 1);
            }
            
            //add transparency for highlights
            if(subtype==PdfDictionary.Highlight) {
                g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
            }

            //carry the sclaing through to the render method
            form.render(0,g2, scaling*pageScaling,true);

    		g2.dispose();

            return aa;

    	}catch(final Exception e){
            LogWriter.writeLog("Exception: " + e.getMessage());
        
    		return null;
    	}catch(final Error e){
            LogWriter.writeLog("Error: " + e.getMessage());
            
            if (ExternalHandlers.throwMissingCIDError && e.getMessage()!=null && e.getMessage().contains("kochi")) {
                throw e;
            }

    		return null;
    	}
    }
    
    public static String decipherTextFromAP(final PdfObjectReader currentPdfFile, final PdfObject Xobject){
    	try{
	
			final ObjectStore localStore = new ObjectStore();
	
			/**
			 * create renderer object
			 */
			final T3Renderer glyphDisplay=new T3Display(0,false,20,localStore);
	
	   		/**
			 * generate local object to decode the stream
			 */

			final PdfStreamDecoder glyphDecoder=new PdfStreamDecoder(currentPdfFile,false,null); //switch to hires as well
            glyphDecoder.setParameters(false,true,15,0,false,false);

            glyphDecoder.setObjectValue(ValueTypes.ObjectStore,localStore);

			glyphDecoder.setRenderer(glyphDisplay);

			/**read any resources*/
			try{
	
				final PdfObject Resources =Xobject.getDictionary(PdfDictionary.Resources);
				if (Resources != null) {
                    glyphDecoder.readResources(Resources, false);
                }
	
			}catch(final Exception e){
                LogWriter.writeLog("Exception: " + e.getMessage());
            }
	
	        /**decode the stream*/
			final byte[] commands=Xobject.getDecodedStream();
	
			String textString="";
	        if(commands!=null) {
                textString = glyphDecoder.decodeStreamIntoObjects(commands, true);
            }
	        if(textString==null || textString.isEmpty()) {
                textString = null;
            }
	
			localStore.flush();
			
			return textString;
    	}catch(final Exception e){
            LogWriter.writeLog("Exception: " + e.getMessage());
            
    		return null;
    	}catch(final Error e){
            LogWriter.writeLog("Error: " + e.getMessage());
            
            if (ExternalHandlers.throwMissingCIDError && e.getMessage()!=null && e.getMessage().contains("kochi")) {
                throw e;
            }
    		return null;
    	}
    }
    
    /**
     * method to rotate an image through a given angle
     * @param src the source image
     * @param rotation the angle to rotate the image through
     * @return the rotated image
     */
    public static BufferedImage rotate(final BufferedImage src, final int rotation) {
        BufferedImage dst;

        if(src == null) {
            return null;
        }

        //if angle is 0 we dont need to do anything
        if(rotation==0) {
            return src;
        }

        final double angle = rotation * Math.PI / 180;

        final int w = src.getWidth();
        final int h = src.getHeight();
        final int newW = (int)(Math.round(h * Math.abs(Math.sin(angle))+w * Math.abs(Math.cos(angle))));
        final int newH = (int)(Math.round(h * Math.abs(Math.cos(angle))+w * Math.abs(Math.sin(angle))));
        final AffineTransform at = AffineTransform.getTranslateInstance((newW-w)/2,(newH-h)/2);
        at.rotate(angle, w/2, h/2);

        dst = new BufferedImage(newW,newH,BufferedImage.TYPE_INT_ARGB);
        final Graphics2D g2 = dst.createGraphics();
        g2.drawRenderedImage(src, at);

        g2.dispose();

        return dst;
    }

     /**/
    /**
     * join the dots and save the image for the inklist annot
     *
     * NO exmaple found i switchover so moved into here for if we need
     *
    private static void commandInkList(Object field, FormObject formObject) {
        //the ink list join the dots array
        if(debug)
            System.out.println("inklist array="+field);

        //current shape object being drawn note we pass in handle on pageLines
        PdfShape currentDrawShape=new PdfShape();
        Rectangle rect = formObject.getBoundingRectangle();

        String paths = (String)field;
        StringTokenizer tok = new StringTokenizer(paths,"[] ",true);
        int countArrays=0;
        boolean isFirstPoint = false;
        String next,first=null,second=null;
        while(tok.hasMoreTokens()){
            next = tok.nextToken();
            if(next.equals("[")){
                countArrays++;
                isFirstPoint = true;
                continue;
            }else if(next.equals("]")){
                countArrays--;
                continue;
            }else if(next.equals(" ")){
                continue;
            }else {
                if(first!=null){
                    second = next;
                }else {
                    first = next;
                    continue;
                }
            }

            if(isFirstPoint){
                currentDrawShape.moveTo(Float.parseFloat(first)-rect.x,Float.parseFloat(second)-rect.y);
                isFirstPoint = false;
            }else{
                currentDrawShape.lineTo(Float.parseFloat(first)-rect.x,Float.parseFloat(second)-rect.y);
            }

            first = null;
        }
//          close for s command
//            currentDrawShape.closeShape();

        org.jpedal.objects.GraphicsState currentGraphicsState= new org.jpedal.objects.GraphicsState();

        Shape currentShape =
                currentDrawShape.generateShapeFromPath(null,
                        currentGraphicsState.CTM,
                        false,null,false,null,currentGraphicsState.getLineWidth(),0);

        Stroke inkStroke = currentGraphicsState.getStroke();

        BufferedImage image = new BufferedImage(rect.width,rect.height,BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = (Graphics2D)image.getGraphics();
        g2.setStroke(inkStroke);
        g2.setColor(Color.red);
        g2.scale(1,-1);
        g2.translate(0,-image.getHeight());
        g2.draw(currentShape);

        g2.dispose();

        formObject.setAppearanceImage(image,PdfDictionary.N,PdfDictionary.Off);
    }/**/

    //////code from DecodeCommand in AnnotStream
    /**{
     //the ink list join the dots array

     //current shape object being drawn note we pass in handle on pageLines
     PdfShape currentDrawShape=new PdfShape();
     Rectangle rect = formObject.getBoundingRectangle();

     String paths = Strip.removeArrayDeleminators((String)field);
     StringTokenizer tok = new StringTokenizer(paths,"[] ",true);

     boolean isFirstPoint = false;
     String next,first=null,second=null;
     while(tok.hasMoreTokens()){
     next = tok.nextToken();
     if(next.equals("[")){
     isFirstPoint = true;
     continue;
     }else if(next.equals("]")){
     continue;
     }else if(next.equals(" ")){
     continue;
     }else {
     if(first!=null){
     second = next;
     }else {
     first = next;
     continue;
     }
     }

     if(isFirstPoint){
     currentDrawShape.moveTo(Float.parseFloat(first)-rect.x,Float.parseFloat(second)-rect.y);
     isFirstPoint = false;
     }else{
     currentDrawShape.lineTo(Float.parseFloat(first)-rect.x,Float.parseFloat(second)-rect.y);
     }

     first = null;
     }
     //          close for s command
     //            currentDrawShape.closeShape();

     org.jpedal.objects.GraphicsState currentGraphicsState=formObject.getGraphicsState();

     Shape currentShape =
     currentDrawShape.generateShapeFromPath(null,
     currentGraphicsState.CTM,
     false,null,false,null,currentGraphicsState.getLineWidth(),0);

     Stroke inkStroke = currentGraphicsState.getStroke();

     BufferedImage image = new BufferedImage(rect.width,rect.height,BufferedImage.TYPE_INT_ARGB);
     Graphics2D g2 = (Graphics2D)image.getGraphics();
     g2.setStroke(inkStroke);
     g2.setColor(Color.red);
     g2.scale(1,-1);
     g2.translate(0,-image.getHeight());
     g2.draw(currentShape);

     g2.dispose();

     //ShowGUIMessage.showGUIMessage("path draw",image,"path drawn");

     formObject.setNormalAppOff(image,null);

     //        }else if(command.equals("RD")){
     //            //rectangle differences left top right bottom order as recieved
     //            //the bounds of the internal object, in from the Rect
     //
     //            StringTokenizer tok = new StringTokenizer(Strip.removeArrayDeleminators((String)field));
     //            float left = Float.parseFloat(tok.nextToken());
     //            float top = Float.parseFloat(tok.nextToken());
     //            float right = Float.parseFloat(tok.nextToken());
     //            float bottom = Float.parseFloat(tok.nextToken());
     //
     //            formObject.setInternalBounds(left,top,right,bottom);
     //        }else {
     //        	notFound = true;
     }
     /*/
    public boolean hasXFADataSet() {
        return false;
    }

    /**
     * takes the PDF commands and creates a font
     */
    public static void decodeFontCommandObj(final String fontStream, final FormObject formObject){

        //now parse the stream into a sequence of tokens
        final StringTokenizer tokens=new StringTokenizer(fontStream,"() []");
        final int tokenCount=tokens.countTokens();
        final String[] tokenValues=new String[tokenCount];
        int i=0;
        while(tokens.hasMoreTokens()){
            tokenValues[i]=tokens.nextToken();
            i++;
        }

        //now work out what it does and build up info
        for(i=tokenCount-1;i>-1;i--){
//			System.out.println(tokenValues[i]+" "+i);

            //look for commands
            if(tokenValues[i].equals("g")){ //set color (takes 1 values
                i--;
                float col=0;
                try{
                    col=Float.parseFloat(handleComma(tokenValues[i]));
                }catch(final Exception e){
                    LogWriter.writeLog("Error in generating g value "+tokenValues[i]+ ' ' +e);
                }

                formObject.setTextColor(new float[]{col});

            }else if(tokenValues[i].equals("Tf")){ //set font (takes 2 values - size and font
                i--;
                int textSize=8;
                try{
                    textSize=(int) Float.parseFloat(handleComma(tokenValues[i]));
//					if(textSize==0)
//						textSize = 0;//TODO check for 0 sizes CHANGE size to best fit on 0
                }catch(final Exception e){
                    LogWriter.writeLog("Error in generating Tf size "+tokenValues[i]+ ' ' +e);
                }

                i--;//decriment for font name
                String font=null;
                try{
                    font=tokenValues[i];
                    if(font.startsWith("/")) {
                        font = font.substring(1);
                    }
                }catch(final Exception e){
                    LogWriter.writeLog("Error in generating Tf font "+tokenValues[i]+"  "+e);
                }

                final PdfFont currentFont=new PdfFont();

                currentFont.setFont(font, textSize);
                
                String fontName=StandardFonts.expandName(font);
                
                final String altName=(String) FontMappings.fontSubstitutionAliasTable.get(fontName.toLowerCase());
                if(altName!=null) {
                    fontName = altName;
                }
                
                formObject.setFontName(fontName);
                formObject.setTextFont(currentFont.getGlyphData().getUnscaledFont());

                formObject.setTextSize(textSize);

            }else if(tokenValues[i].equals("rg") || tokenValues[i].equals("r")){
                i--;
                final float b=Float.parseFloat(handleComma(tokenValues[i]));
                i--;
                final float g=Float.parseFloat(handleComma(tokenValues[i]));
                i--;
                final float r=Float.parseFloat(handleComma(tokenValues[i]));

                formObject.setTextColor(new float[]{r,g,b});

            }else if(tokenValues[i].equals("Sig")){
                LogWriter.writeFormLog("Sig-  UNIMPLEMENTED="+fontStream+"< "+i,debugUnimplemented);
            }else if(tokenValues[i].equals("\\n")){
                //ignore \n
                if(debug) {
                    System.out.println("ignore \\n");
                }
            }else {
                if(!showFontMessage){
                    showFontMessage=true;
                    LogWriter.writeFormLog("{stream} Unknown FONT command "+tokenValues[i]+ ' ' +i+" string="+fontStream,debugUnimplemented);
                }
            }
        }
    }

    private static String handleComma(String tokenValue) {

        //if comma used as full stop remove
        final int comma=tokenValue.indexOf(',');
        if(comma!=-1) {
            tokenValue = tokenValue.substring(0, comma);
        }

        return tokenValue;
    }

    @SuppressWarnings("UnusedDeclaration")
    public byte[] getXFA(final int xfaTemplate) {
        throw new RuntimeException("getXFA Should never be called in base class");
    }

    public boolean isXFA() {
        return isXFA;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy