/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.pdfbox.pdmodel.graphics.state;
import java.awt.BasicStroke;
import java.awt.Composite;
import java.awt.geom.Area;
import java.awt.geom.GeneralPath;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.PDLineDashPattern;
import org.apache.pdfbox.pdmodel.graphics.blend.BlendComposite;
import org.apache.pdfbox.pdmodel.graphics.blend.BlendMode;
import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceGray;
import org.apache.pdfbox.util.Matrix;
/**
* The current state of the graphics parameters when executing a content stream.
*
* @author Ben Litchfield
*/
public class PDGraphicsState implements Cloneable
{
private boolean isClippingPathDirty;
private Area clippingPath;
private Matrix currentTransformationMatrix = new Matrix();
private PDColor strokingColor = PDDeviceGray.INSTANCE.getInitialColor();
private PDColor nonStrokingColor = PDDeviceGray.INSTANCE.getInitialColor();
private PDColorSpace strokingColorSpace = PDDeviceGray.INSTANCE;
private PDColorSpace nonStrokingColorSpace = PDDeviceGray.INSTANCE;
private PDTextState textState = new PDTextState();
private float lineWidth = 1;
private int lineCap = BasicStroke.CAP_BUTT;
private int lineJoin = BasicStroke.JOIN_MITER;
private float miterLimit = 10;
private PDLineDashPattern lineDashPattern = new PDLineDashPattern();
private RenderingIntent renderingIntent;
private boolean strokeAdjustment = false;
private BlendMode blendMode = BlendMode.COMPATIBLE;
private PDSoftMask softMask;
private double alphaConstant = 1.0;
private double nonStrokingAlphaConstant = 1.0;
private boolean alphaSource = false;
// DEVICE-DEPENDENT parameters
private boolean overprint = false;
private boolean nonStrokingOverprint = false;
private double overprintMode = 0;
//black generation
//undercolor removal
private COSBase transfer = null;
//halftone
private double flatness = 1.0;
private double smoothness = 0;
/**
* Constructor with a given page size to initialize the clipping path.
* @param page the size of the page
*/
public PDGraphicsState(PDRectangle page)
{
clippingPath = new Area(page.toGeneralPath());
}
/**
* Get the value of the CTM.
*
* @return The current transformation matrix.
*/
public Matrix getCurrentTransformationMatrix()
{
return currentTransformationMatrix;
}
/**
* Set the value of the CTM.
*
* @param value The current transformation matrix.
*/
public void setCurrentTransformationMatrix(Matrix value)
{
currentTransformationMatrix = value;
}
/**
* Get the value of the line width.
*
* @return The current line width.
*/
public float getLineWidth()
{
return lineWidth;
}
/**
* set the value of the line width.
*
* @param value The current line width.
*/
public void setLineWidth(float value)
{
lineWidth = value;
}
/**
* Get the value of the line cap.
*
* @return The current line cap.
*/
public int getLineCap()
{
return lineCap;
}
/**
* set the value of the line cap.
*
* @param value The current line cap.
*/
public void setLineCap(int value)
{
lineCap = value;
}
/**
* Get the value of the line join.
*
* @return The current line join value.
*/
public int getLineJoin()
{
return lineJoin;
}
/**
* Get the value of the line join.
*
* @param value The current line join
*/
public void setLineJoin(int value)
{
lineJoin = value;
}
/**
* Get the value of the miter limit.
*
* @return The current miter limit.
*/
public float getMiterLimit()
{
return miterLimit;
}
/**
* set the value of the miter limit.
*
* @param value The current miter limit.
*/
public void setMiterLimit(float value)
{
miterLimit = value;
}
/**
* Get the value of the stroke adjustment parameter.
*
* @return The current stroke adjustment.
*/
public boolean isStrokeAdjustment()
{
return strokeAdjustment;
}
/**
* set the value of the stroke adjustment.
*
* @param value The value of the stroke adjustment parameter.
*/
public void setStrokeAdjustment(boolean value)
{
strokeAdjustment = value;
}
/**
* Get the value of the stroke alpha constant property.
*
* @return The value of the stroke alpha constant parameter.
*/
public double getAlphaConstant()
{
return alphaConstant;
}
/**
* set the value of the stroke alpha constant property.
*
* @param value The value of the stroke alpha constant parameter.
*/
public void setAlphaConstant(double value)
{
alphaConstant = value;
}
/**
* Get the value of the non-stroke alpha constant property.
*
* @return The value of the non-stroke alpha constant parameter.
* @deprecated use {@link #getNonStrokeAlphaConstant() }
*/
@Deprecated
public double getNonStrokeAlphaConstants()
{
return nonStrokingAlphaConstant;
}
/**
* set the value of the non-stroke alpha constant property.
*
* @param value The value of the non-stroke alpha constant parameter.
* @deprecated use {@link #setNonStrokeAlphaConstant(double) }
*/
@Deprecated
public void setNonStrokeAlphaConstants(double value)
{
nonStrokingAlphaConstant = value;
}
/**
* Get the value of the non-stroke alpha constant property.
*
* @return The value of the non-stroke alpha constant parameter.
*/
public double getNonStrokeAlphaConstant()
{
return nonStrokingAlphaConstant;
}
/**
* set the value of the non-stroke alpha constant property.
*
* @param value The value of the non-stroke alpha constant parameter.
*/
public void setNonStrokeAlphaConstant(double value)
{
nonStrokingAlphaConstant = value;
}
/**
* get the value of the stroke alpha source property.
*
* @return The value of the stroke alpha source parameter.
*/
public boolean isAlphaSource()
{
return alphaSource;
}
/**
* set the value of the alpha source property.
*
* @param value The value of the alpha source parameter.
*/
public void setAlphaSource(boolean value)
{
alphaSource = value;
}
/**
* returns the current softmask
*
* @return softMask
*/
public PDSoftMask getSoftMask()
{
return softMask;
}
/**
* Sets the current soft mask
*
* @param softMask
*/
public void setSoftMask(PDSoftMask softMask)
{
this.softMask = softMask;
}
/**
* Returns the current blend mode
*
* @return the current blend mode
*/
public BlendMode getBlendMode()
{
return blendMode;
}
/**
* Sets the blend mode in the current graphics state
*
* @param blendMode
*/
public void setBlendMode(BlendMode blendMode)
{
this.blendMode = blendMode;
}
/**
* get the value of the overprint property.
*
* @return The value of the overprint parameter.
*/
public boolean isOverprint()
{
return overprint;
}
/**
* set the value of the overprint property.
*
* @param value The value of the overprint parameter.
*/
public void setOverprint(boolean value)
{
overprint = value;
}
/**
* get the value of the non stroking overprint property.
*
* @return The value of the non stroking overprint parameter.
*/
public boolean isNonStrokingOverprint()
{
return nonStrokingOverprint;
}
/**
* set the value of the non stroking overprint property.
*
* @param value The value of the non stroking overprint parameter.
*/
public void setNonStrokingOverprint(boolean value)
{
nonStrokingOverprint = value;
}
/**
* get the value of the overprint mode property.
*
* @return The value of the overprint mode parameter.
*/
public double getOverprintMode()
{
return overprintMode;
}
/**
* set the value of the overprint mode property.
*
* @param value The value of the overprint mode parameter.
*/
public void setOverprintMode(double value)
{
overprintMode = value;
}
/**
* get the value of the flatness property.
*
* @return The value of the flatness parameter.
*/
public double getFlatness()
{
return flatness;
}
/**
* set the value of the flatness property.
*
* @param value The value of the flatness parameter.
*/
public void setFlatness(double value)
{
flatness = value;
}
/**
* get the value of the smoothness property.
*
* @return The value of the smoothness parameter.
*/
public double getSmoothness()
{
return smoothness;
}
/**
* set the value of the smoothness property.
*
* @param value The value of the smoothness parameter.
*/
public void setSmoothness(double value)
{
smoothness = value;
}
/**
* This will get the graphics text state.
*
* @return The graphics text state.
*/
public PDTextState getTextState()
{
return textState;
}
/**
* This will set the graphics text state.
*
* @param value The graphics text state.
*/
public void setTextState(PDTextState value)
{
textState = value;
}
/**
* This will get the current line dash pattern.
*
* @return The line dash pattern.
*/
public PDLineDashPattern getLineDashPattern()
{
return lineDashPattern;
}
/**
* This will set the current line dash pattern.
*
* @param value The new line dash pattern.
*/
public void setLineDashPattern(PDLineDashPattern value)
{
lineDashPattern = value;
}
/**
* This will get the rendering intent.
*
* @see PDExtendedGraphicsState
*
* @return The rendering intent
*/
public RenderingIntent getRenderingIntent()
{
return renderingIntent;
}
/**
* This will set the rendering intent.
*
* @param value The new rendering intent.
*/
public void setRenderingIntent(RenderingIntent value)
{
renderingIntent = value;
}
@Override
public PDGraphicsState clone()
{
try
{
PDGraphicsState clone = (PDGraphicsState)super.clone();
clone.textState = textState.clone();
clone.currentTransformationMatrix = currentTransformationMatrix.clone();
clone.strokingColor = strokingColor; // immutable
clone.nonStrokingColor = nonStrokingColor; // immutable
clone.lineDashPattern = lineDashPattern; // immutable
clone.clippingPath = clippingPath; // not cloned, see intersectClippingPath
clone.isClippingPathDirty = false;
return clone;
}
catch (CloneNotSupportedException e)
{
// should not happen
throw new RuntimeException(e);
}
}
/**
* Returns the stroking color.
*
* @return stroking color
*/
public PDColor getStrokingColor()
{
return strokingColor;
}
/**
* Sets the stroking color.
*
* @param color The new stroking color
*/
public void setStrokingColor(PDColor color)
{
strokingColor = color;
}
/**
* Returns the non-stroking color.
*
* @return The non-stroking color
*/
public PDColor getNonStrokingColor()
{
return nonStrokingColor;
}
/**
* Sets the non-stroking color.
*
* @param color The new non-stroking color
*/
public void setNonStrokingColor(PDColor color)
{
nonStrokingColor = color;
}
/**
* Returns the stroking color space.
*
* @return The stroking color space.
*/
public PDColorSpace getStrokingColorSpace()
{
return strokingColorSpace;
}
/**
* Sets the the stroking color space.
*
* @param colorSpace The new stroking color space.
*/
public void setStrokingColorSpace(PDColorSpace colorSpace)
{
strokingColorSpace = colorSpace;
}
/**
* Returns the non-stroking color space.
*
* @return The non-stroking color space.
*/
public PDColorSpace getNonStrokingColorSpace()
{
return nonStrokingColorSpace;
}
/**
* Sets the the non-stroking color space.
*
* @param colorSpace The new non-stroking color space.
*/
public void setNonStrokingColorSpace(PDColorSpace colorSpace)
{
nonStrokingColorSpace = colorSpace;
}
/**
* Modify the current clipping path by intersecting it with the given path.
* @param path path to intersect with the clipping path
*/
public void intersectClippingPath(GeneralPath path)
{
intersectClippingPath(new Area(path));
}
/**
* Modify the current clipping path by intersecting it with the given path.
* @param area area to intersect with the clipping path
*/
public void intersectClippingPath(Area area)
{
// lazy cloning of clipping path for performance
if (!isClippingPathDirty)
{
// deep copy (can't use clone() as it performs only a shallow copy)
Area cloned = new Area();
cloned.add(clippingPath);
clippingPath = cloned;
isClippingPathDirty = true;
}
// intersection as usual
clippingPath.intersect(area);
}
/**
* This will get the current clipping path. Do not modify this Area object!
*
* @return The current clipping path.
*/
public Area getCurrentClippingPath()
{
return clippingPath;
}
public Composite getStrokingJavaComposite()
{
return BlendComposite.getInstance(blendMode, (float) alphaConstant);
}
public Composite getNonStrokingJavaComposite()
{
return BlendComposite.getInstance(blendMode, (float) nonStrokingAlphaConstant);
}
/**
* This will get the transfer function.
*
* @return The transfer function. According to the PDF specification, this is either a single
* function (which applies to all process colorants) or an array of four functions (which apply
* to the process colorants individually). The name Identity may be used to represent the
* identity function, and the name Default denotes the transfer function that was in effect at
* the start of the page.
*/
public COSBase getTransfer()
{
return transfer;
}
/**
* This will set the transfer function.
*
* @param transfer The transfer function. According to the PDF specification, this is either a
* single function (which applies to all process colorants) or an array of four functions (which
* apply to the process colorants individually). The name Identity may be used to represent the
* identity function, and the name Default denotes the transfer function that was in effect at
* the start of the page.
*/
public void setTransfer(COSBase transfer)
{
this.transfer = transfer;
}
}