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

org.jpedal.objects.GraphicsState Maven / Gradle / Ivy

/*
 * ===========================================
 * 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-2016 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


 *
 * ---------------
 * GraphicsState.java
 * ---------------
 */
package org.jpedal.objects;
import java.awt.BasicStroke;
import java.awt.Stroke;
import java.awt.geom.Area;
import java.awt.geom.GeneralPath;
import javafx.scene.shape.Shape;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.shape.StrokeLineJoin;
import org.jpedal.color.*;
import org.jpedal.external.ExternalHandlers;
import org.jpedal.fonts.glyph.JavaFXSupport;
import org.jpedal.objects.raw.PdfArrayIterator;
import org.jpedal.objects.raw.PdfDictionary;
import org.jpedal.objects.raw.PdfObject;

/**
 * holds the graphics state as stream decoded
 */
public class GraphicsState 
{

    //hold image co-ords
    public float x,y;

    TextState currentTextState=new TextState();

    //transparency
    private float strokeAlpha=1.0f;
    private float nonstrokeAlpha=1.0f;

    private float maxStrokeAlpha=1.0f;
    private float maxNonstrokeAlpha=1.0f;

    /** copy used for images*/
    public final float[][] lastCTM = new float[3][3];

    //TR value
    private PdfObject TRobj;
    
    private byte[][] TR;

    public PdfObject SMask;

    /**stroke colorspace*/
    public GenericColorSpace strokeColorSpace=new DeviceGrayColorSpace();

    /**nonstroke colorspace*/
    public GenericColorSpace nonstrokeColorSpace=new DeviceGrayColorSpace();

    private boolean hasClipChanged;

    //overprinting
    private boolean op;
    private boolean OP;

    private float OPM;

    private PdfPaint nonstrokeColor=new PdfColor(0,0,0);
    private PdfPaint strokeColor=new PdfColor(0,0,0);

    /**holds current clipping shape*/
    private Area current_clipping_shape;
    private PdfClip current_clip;

    private static final boolean debugClip=false;

    /** CTM which is used for plotting (see pdf
     *  spec for explanation*/
    public float[][] CTM = new float[3][3];
    
    public float[][] scaleFactor;

    /**dash of lines (phase) for drawing*/
    private int current_line_dash_phase;

    /**used for TR effect*/
    private GeneralPath TRmask;

    /**fill type for drawing*/
    private int fill_type;

    /**mitre limit for drawing - Set default limit to 10 as per the PDF spec */
    private int mitre_limit = 10;

    /**dash of lines (array) for drawing*/
    private float[] current_line_dash_array=new float[0];

    /**join style of lines for drawing*/
    private int current_line_cap_style;

    /**width of lines for drawing*/
    private float current_line_width = 1;
    
    /**width of lines to use when outputting to HTML/SVG etc**/
    private int output_line_width = -1;

    /**join of lines for drawing*/
    private int current_line_join_style;

    /**Type of draw to use*/
    private int text_render_type = GraphicsState.FILL;

    /**displacement to allow for negative page displacement*/
    private int minX;//%%

    /**displacement to allow for negative page displacement*/
    private int minY;//%%

    public static final int STROKE = 1;

    public static final int FILL = 2;

    public static final int FILLSTROKE = 3;

    public static final int INVISIBLE = 4;

    public static final int CLIPTEXT=7;

    private int BMvalue=PdfDictionary.Normal;

    public GraphicsState(final GraphicsState gs){

        resetCTM();
        
         BMvalue= gs.BMvalue;
    }
    
    public GraphicsState(){

        resetCTM();
    }

    /**
     * initialise the GraphicsState
     * @param minX
     * @param minY
     */
    public GraphicsState(final int minX, final int minY)
    {
        this.minX=-minX;/*keep%%*/
        this.minY=-minY;/*keep%%*/
        resetCTM();

    }

    public void setMaxAlpha(final int type, final float value){

        switch(type){

            case STROKE:

                this.maxStrokeAlpha=value;
                break;

            case FILL :
                this.maxNonstrokeAlpha=value;
                break;

        }
    }

    public void setAlpha(final int type, float value){

        switch(type){

            case STROKE:

                if(value>maxStrokeAlpha) {
                    value = maxStrokeAlpha;
                }
                this.strokeAlpha=value;
                break;

            case FILL :
                if(value>maxNonstrokeAlpha) {
                    value = maxNonstrokeAlpha;
                }
                this.nonstrokeAlpha=value;
                break;

        }
    }

    /**use STROKE or FILL
     * @param type
     * @return*/
    public float getAlpha(final int type){

	float value=1f;

        switch(type){

            case STROKE:
		if(strokeAlpha>maxStrokeAlpha){
		    value=maxStrokeAlpha;
		}else{
		    value=this.strokeAlpha;
		}
                break;

            case FILL :
		if(nonstrokeAlpha>maxNonstrokeAlpha){
		    value=maxNonstrokeAlpha;
		}else{
		    value=this.nonstrokeAlpha;
		}
                break;

        }

        return value;
    }

    /**use STROKE or FILL
     * @param type
     * @return*/
    public float getAlphaMax(final int type){

        float value=1f;

        switch(type){

            case STROKE:
                value=this.maxStrokeAlpha ;
                break;

            case FILL :
                value=this.maxNonstrokeAlpha;
                break;

        }

        return value;
    }

    /**get stroke op
     * @return*/
    public boolean getNonStrokeOP(){
        return this.op;
    }

    /**get stroke op
     * @return*/
    public float getOPM(){
        return this.OPM;
    }

    public Object[] getTR() {
        if(TRobj==null && TR==null){
            return null;
        }else{
            return new Object[]{TRobj,TR};
        }
    }

    //////////////////////////////////////////////////////////////////////////
    /**
     * set text render type
     * @param text_render_type
     */
    public final void setTextRenderType( final int text_render_type )
    {
        this.text_render_type = text_render_type;

        TRmask=null;
    }

    //////////////////////////////////////////////////////////////////////////
    /**
     * set text render type
     * @return
     */
    public final int getTextRenderType()
    {
        return text_render_type;
    }

    ///////////////////////////////////////////////////////////////////////////
    /**
     * set mitre limit
     * @param mitre_limit
     */
    public final void setMitreLimit( final int mitre_limit )
    {
        this.mitre_limit = mitre_limit;
    }

    /**
     * get line width
     * @return
     */
    public final float getLineWidth()
    {
        return current_line_width;
    }
    
    /**
     * get line width for HTML/SVG etc. value is -1 if not set.
     * @return
     */
    public final int getOutputLineWidth() {
    	return output_line_width;
    }
    
    //////////////////////////////////////////////////////////////////////////
    /**
     * set fill type
     * @param fill_type
     */
    public final void setFillType( final int fill_type )
    {
        this.fill_type = fill_type;
    }
    //////////////////////////////////////////////////////////////////////////
    /**
     * update clip
     * @param current_area
     */
    public final void updateClip( final Area current_area )
    {
        //  System.out.println("Update clip "+current_area.getBounds());
        if( current_clipping_shape == null || current_area==null){
            current_clipping_shape = current_area;
            hasClipChanged=true;
        }else{// if(current_clipping_shape.intersects(current_area.getBounds2D().getX(),current_area.getBounds2D().getY(),
            //current_area.getBounds2D().getWidth(),current_area.getBounds2D().getHeight())){
            current_clipping_shape.intersect( current_area );

            hasClipChanged=true;
        }

        if(debugClip){
            System.out.println("[updateClip]");
            if(current_clipping_shape==null){
                System.out.println("Null shape");
            }else{
                System.out.println("Shape bounds= "+current_clipping_shape.getBounds());
            }
        }
    }

    /**
     * add to clip (used for TR 7)
     * @param current_area
     */
    public final void addClip( final Area current_area )
    {

        if(TRmask==null) {
            TRmask = new GeneralPath();
        }

        TRmask.append(current_area,false);

    }
    //////////////////////////////////////////////////////////////////////////
    /**
     * get the current stroke to be used - basic solid line or pattern
     * @return
     */
    public final Stroke getStroke()
    {

        //hold the stroke for the path
        final Stroke current_stroke;

        //factor in scaling to line width
        float w=current_line_width;
        if(CTM[0][0]!=0) {
            w *= CTM[0][0];
        } else if( CTM[0][1]!=0) {
            w *= CTM[0][1];
        }

        if(w<0) {
            w = -w;
        }

        //check values all in legal boundaries
        if( mitre_limit < 1 ) {
            mitre_limit = 1;
        }

        final int dashCount=current_line_dash_array.length;
        if( dashCount > 0 ){
            //factor in scaling
            final float[] dash=new float[dashCount];
            for(int aa=0;aa 0 ){
            //factor in scaling
            final float[] dash=new float[dashCount];
            for(int aa=0;aa max_y+2) && //2 is margin for error needed on some files
            (current_clipping_shape.getBounds().y>=0)){
                current_clipping_shape = null;

                hasClipChanged=true;

                if(debugClip){
                    System.out.println("[checkWholePageClip] current_clipping_shape="+current_clipping_shape);
                    if(current_clipping_shape==null){
                        System.out.println("Null shape");
                    }else{
                        System.out.println("Shape bounds= "+current_clipping_shape.getBounds());
                    }
                }
        }
    }

    /**
     * set dash array
     * @param current_line_dash_array
     */
    public final void setDashArray( final float[] current_line_dash_array ){
        this.current_line_dash_array = current_line_dash_array;
    }


    /**
     * custom clone method
     */
   
    public final  GraphicsState deepCopy(){
        
        final GraphicsState newGS=new GraphicsState();

        newGS.x=x;
        newGS.y=y;

        if (TR != null) {
            newGS.TR = TR;
        }
        
        if (TRobj != null) {
            newGS.TRobj = TRobj;
        }

        newGS.maxNonstrokeAlpha=maxNonstrokeAlpha;
        newGS.maxStrokeAlpha=maxStrokeAlpha;

        newGS.strokeAlpha = strokeAlpha;
        newGS.nonstrokeAlpha = nonstrokeAlpha;

        newGS.op = op;
        newGS.OP = OP;
        newGS.OPM = OPM;

        newGS.nonstrokeColor = nonstrokeColor;
        newGS.strokeColor = strokeColor;

        if(current_clipping_shape != null) {
            newGS.current_clipping_shape = (Area) current_clipping_shape.clone();
        }

        if(CTM != null){
            for(int i=0;i<3;i++){
                System.arraycopy(CTM[i], 0, newGS.CTM[i], 0, 3);
            }
        }

        newGS.hasClipChanged=hasClipChanged;


        newGS.current_line_dash_phase = current_line_dash_phase;

        if(TRmask != null) {
            newGS.TRmask = (GeneralPath) TRmask.clone();
        }


        newGS.fill_type = fill_type;

        newGS.mitre_limit = mitre_limit;

        if(current_line_dash_array!=null){
            final int size=current_line_dash_array.length;
            newGS.current_line_dash_array=new float[size];
            System.arraycopy(current_line_dash_array, 0, newGS.current_line_dash_array, 0, size);
        }

        newGS.current_line_cap_style = current_line_cap_style;

        newGS.current_line_width = current_line_width;

        newGS.current_line_join_style = current_line_join_style;

        newGS.text_render_type = text_render_type;

        newGS.minX = minX;

        newGS.minY = minY;

        return newGS;
    }

    /**
     * reset CTM
     */
    private void resetCTM()
    {
        //init CTM
        CTM[0][0] = (float)1.0;
        CTM[1][0] = (float)0.0;
        CTM[2][0] = minX;
        CTM[0][1] = (float)0.0;
        CTM[1][1] = (float)1.0;
        CTM[2][1] = minY;
        CTM[0][2] = (float)0.0;
        CTM[1][2] = (float)0.0;
        CTM[2][2] = (float)1.0;

    }

    /**
     * set dash phase
     * @param current_line_dash_phase
     */
    public final void setDashPhase( final int current_line_dash_phase )
    {
        this.current_line_dash_phase = current_line_dash_phase;
    }

    /**
     * get fill type
     * @return
     */
    public final int getFillType()
    {
        return fill_type;
    }

    /**
     * set clipping shape
     * @param new_clip
     */
    public final void setClippingShape( final Area new_clip )
    {
        this.current_clipping_shape = new_clip;

        hasClipChanged=true;

        if(debugClip){
            System.out.println("[setClippingShape]");

            if(current_clipping_shape==null){
                System.out.println("Null shape");
            }else{
                System.out.println("Shape bounds= "+current_clipping_shape.getBounds());
            }
        }

    }
    /**
     * @return Returns the currentNonstrokeColor.
     */
    public PdfPaint getNonstrokeColor() {
        return nonstrokeColor;
    }

    /**
     * @param currentNonstrokeColor The currentNonstrokeColor to set.
     */
    public void setNonstrokeColor(final PdfPaint currentNonstrokeColor) {
        this.nonstrokeColor = currentNonstrokeColor;
    }

    /**
     * @return Returns the strokeColor.
     */
    public PdfPaint getStrokeColor() {
        return strokeColor;
    }

    /**
     * @param strokeColor The strokeColor to set.
     */
    public void setStrokeColor(final PdfPaint strokeColor) {
        this.strokeColor = strokeColor;
    }

    /**
     * tell software if clip has changed and
     * return
     * @return
     */
    public boolean hasClipChanged() {

        final boolean flag=hasClipChanged;

        hasClipChanged=false;
        return flag;
    }

    public void setTextState(final TextState currentTextState) {
        this.currentTextState=currentTextState;
    }

    public TextState getTextState() {
        return currentTextState;
    }
    
    public void updateClip(final Object fxPath) {
        // Initialise when needed
        if(current_clip == null){
             JavaFXSupport fxSupport = ExternalHandlers.getFXHandler();
            if(fxSupport!=null){
                current_clip = fxSupport.getFXClip();
            }
        }
        
        hasClipChanged = current_clip.updateClip(fxPath);
    }
    
    public Shape getFXClippingShape(){
        if (current_clip == null) {
            return null;
        }
        
        return (Shape)current_clip.getClippingShape();
    }

    public int getBMValue() {
        return BMvalue;
    }
    
    public void setBMValue(int bm){
        BMvalue = bm;
    }

    @Override
    public String toString() {
        String str = "GraphicsState : BM:" + BMvalue + " op:" + op + " OP:" + OP
                + " opm:" + OPM + " sAlpha:" + strokeAlpha + " nsAlpha:" + nonstrokeAlpha
                + " msAlpha:" + maxStrokeAlpha + " mnsAlpha:"+maxNonstrokeAlpha+" smask:"+SMask;
        return str;
    }

    public void resetColorSpaces(final int strokeColorData, final int nonStrokeColorData) {

       // System.out.println("reset "+nonstrokeColorSpace+"="+nonStrokeColorData+" ");
        
        if(strokeColorSpace.getID()!=ColorSpaces.Pattern){
             strokeColorSpace.invalidateCaching(strokeColorData);
            strokeColorSpace.setColor(new PdfColor(strokeColorData));
            
        }
        
        if(nonstrokeColorSpace.getID()!=ColorSpaces.Pattern){
            nonstrokeColorSpace.invalidateCaching(nonStrokeColorData);
            nonstrokeColorSpace.setColor(new PdfColor(nonStrokeColorData));
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy