org.apache.xmlgraphics.java2d.ps.PSTilingPattern Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.apache.fop Show documentation
Show all versions of org.apache.fop Show documentation
The core maven build properties
The newest version!
/*
* 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.
*/
/* $Id: PSTilingPattern.java 1809627 2017-09-25 13:42:08Z ssteiner $ */
package org.apache.xmlgraphics.java2d.ps;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.TexturePaint;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.List;
/**
* This class is implementation of PostScript tiling pattern. It allows to make a pattern
* with defined PaintProc or texture.
*
* Originally authored by Jiri Kunhart.
*/
public class PSTilingPattern {
/**
* A code identifying the pattern type that this dictionary describes;
* must be 1 for a tiling pattern
*/
public static final int PATTERN_TYPE_TILING = 1;
/** PostScript constant for a shading pattern (unsupported) */
public static final int PATTERN_TYPE_SHADING = 2;
/** the pattern type of this pattern */
protected int patternType = PATTERN_TYPE_TILING;
//TODO To be moved to a super class once shading patterns are implemented.
/**
* The name of the pattern (for example: "Pattern1" )
*/
protected String patternName;
/**
* The XUID is an extended unique ID -- an array of integers that provides for
* distributed, hierarchical management of the space of unique ID numbers
* (optional)
*/
protected List xUID;
/**
* A PostScript procedure for painting the pattern cell
*/
protected StringBuffer paintProc;
/**
* An array of four numbers in the pattern coordinate system, giving
* the coordinates of the left, bottom, right, and top edges, respectively, of the
* pattern cell's bounding box
*/
protected Rectangle2D bBox;
/**
* The desired horizontal spacing between pattern cells, measured in
* the pattern coordinate system
*/
protected double xStep;
/**
* The desired vertical spacing between pattern cells, measured in
* the pattern coordinate system
*/
protected double yStep;
/**
* A code that determines how the color of the pattern cell is to be
* specified: 1 for colored pattern, 2 for uncolored pattern
*/
protected int paintType = 2;
/**
* A code that controls adjustments to the spacing of tiles relative to
* the device pixel grid:
* 1 for constant spacing,
* 2 for no distortion
* 3 for constant spacing and faster tiling.
*/
protected int tilingType = 1;
/**
* A texture is used for filling shapes
*/
protected TexturePaint texture;
/**
* Constructor for the creation of pattern with defined PaintProc
*
* @param patternName the name of the pattern (for example: "Pattern1" ), if
* the name is null, the pattern should be stored in PSPatternStorage, where the pattern
* gets a name (the pattern without name cannot be use in PS file)
* @param paintProc a postscript procedure for painting the pattern cell
* @param bBox a pattern cell's bounding box
* @param xStep the desired horizontal spacing between pattern cells
* @param yStep the desired vertical spacing between pattern cells
* @param paintType 1 for colored pattern, 2 for uncolored pattern
* @param tilingType adjustments to the spacing of tiles relative to
* the device pixel grid (1,2 or 3)
* @param xUID an extended unique ID (optional)
*/
public PSTilingPattern(String patternName, StringBuffer paintProc, Rectangle bBox,
double xStep, double yStep,
int paintType, int tilingType, List xUID) {
// check the parameters
this.patternName = patternName;
this.paintProc = paintProc;
setBoundingBox(bBox);
setXStep(xStep);
setYStep(yStep);
setPaintType(paintType);
setTilingType(tilingType);
this.xUID = xUID;
}
/**
* Constructor for the creation of pattern with defined texture
*
* @param patternName the name of the pattern (for example: "Pattern1" ), if
* the name is null, the pattern should be stored in PSPatternStorage, where the pattern
* gets a name (a pattern without name cannot be use in PS file)
* @param texture a texture is used for filling a shape
* @param xStep the desired horizontal spacing between pattern cells
* @param yStep yStep the desired vertical spacing between pattern cells
* @param tilingType adjustments to the spacing of tiles relative to
* the device pixel grid (1,2 or 3)
* @param xUID xUID an extended unique ID (optional)
*/
public PSTilingPattern(String patternName, TexturePaint texture, double xStep, double yStep,
int tilingType, List xUID) {
this(patternName, null, new Rectangle(), 1, 1, 1, tilingType, xUID);
this.texture = texture;
Rectangle2D anchor = texture.getAnchorRect();
bBox = new Rectangle2D.Double(
anchor.getX(), anchor.getY(),
anchor.getX() + anchor.getWidth(), anchor.getY() + anchor.getHeight());
// xStep and yStep may be either positive or negative, but not zero => if it is zero,
// we set xStep and yStep in this way that the pattern will be without spaces
this.xStep = (xStep == 0) ? anchor.getWidth() : xStep;
this.yStep = (yStep == 0) ? anchor.getHeight() : yStep;
}
/**
* Gets the name of the pattern
*
* @return String representing the name of the pattern.
*/
public String getName() {
return (this.patternName);
}
/**
* Sets the name of the pattern.
* @param name the name of the pattern. Can be anything without spaces (for example "Pattern1").
*/
public void setName(String name) {
if (name == null) {
throw new NullPointerException("Parameter patternName must not be null");
}
if (name.length() == 0) {
throw new IllegalArgumentException("Parameter patternName must not be empty");
}
if (name.indexOf(" ") >= 0) {
throw new IllegalArgumentException(
"Pattern name must not contain any spaces");
}
this.patternName = name;
}
/**
* Returns the bounding box.
*
* @return a pattern cell's bounding box
*/
public Rectangle2D getBoundingBox() {
return (this.bBox);
}
/**
* Sets the bounding box.
*
* @param bBox a pattern cell's bounding box
*/
public void setBoundingBox(Rectangle2D bBox) {
if (bBox == null) {
throw new NullPointerException("Parameter bBox must not be null");
}
this.bBox = bBox;
}
/**
* Gets the postscript procedure PaintProc
*
* @return the postscript procedure PaintProc
*/
public StringBuffer getPaintProc() {
return (this.paintProc);
}
/**
* Sets the postscript procedure PaintProc
*
* @param paintProc the postscript procedure PaintProc
*/
public void setPaintProc(StringBuffer paintProc) {
this.paintProc = paintProc;
}
/**
* Gets the horizontal spacing between pattern cells
*
* @return the horizontal spacing between pattern cells
*/
public double getXStep() {
return (this.xStep);
}
/**
* Sets the horizontal spacing between pattern cells
*
* @param xStep the horizontal spacing between pattern cells
*/
public void setXStep(double xStep) {
if (xStep == 0) {
throw new IllegalArgumentException("Parameter xStep must not be 0");
}
this.xStep = xStep;
}
/**
* Gets the vertical spacing between pattern cells
*
* @return the vertical spacing between pattern cells
*/
public double getYStep() {
return (this.yStep);
}
/**
* Sets the vertical spacing between pattern cells
*
* @param yStep the vertical spacing between pattern cells
*/
public void setYStep(double yStep) {
if (yStep == 0) {
throw new IllegalArgumentException("Parameter yStep must not be 0");
}
this.yStep = yStep;
}
/**
* Gets the code that determines how the color of the pattern cell is to be
* specified: 1 for colored pattern, 2 for uncolored pattern
*
* @return the paint type
*/
public int getPaintType() {
return (this.paintType);
}
/**
* Sets the code that determines how the color of the pattern cell is to be
* specified: 1 for colored pattern, 2 for uncolored pattern
*
* @param paintType the paint type
*/
public void setPaintType(int paintType) {
if ((paintType != 1) && (paintType != 2)) {
throw new IllegalArgumentException("Parameter paintType must not be "
+ paintType + " (only 1 or 2)");
}
this.paintType = paintType;
}
/**
* Gets a code that controls adjustments to the spacing of tiles relative to
* the device pixel grid: 1 for constant spacing, 2 for no distortion
* 3 for constant spacing and faster tiling
*
* @return the tiling type
*/
public int getTilingType() {
return (this.tilingType);
}
/**
* Sets a code that controls adjustments to the spacing of tiles relative to
* the device pixel grid: 1 for constant spacing, 2 for no distortion
* 3 for constant spacing and faster tiling
*
* @param tilingType the tiling type
*/
public void setTilingType(int tilingType) {
if (!((tilingType <= 3) && (tilingType >= 1))) {
throw new IllegalArgumentException("Parameter tilingType must not be "
+ tilingType + " (only 1, 2 or 3)");
}
this.tilingType = tilingType;
}
/**
* Gets a texture which is used for filling shapes
*
* @return the texture
*/
public TexturePaint getTexturePaint() {
return (this.texture);
}
/**
* Sets a texture which is used for filling shapes
*
* @param texturePaint the texture
*/
public void setTexturePaint(TexturePaint texturePaint) {
this.texture = texturePaint;
}
/**
* Gets an extended unique ID that uniquely identifies the pattern
*
* @return xUID the unique ID
*/
public List getXUID() {
return (this.xUID);
}
/**
* Sets an extended unique ID that uniquely identifies the pattern
*
* @param xUID the unique ID
*/
public void setXUID(List xUID) {
this.xUID = xUID;
}
/**
* Generates postscript code for a pattern
*
* @return The string which contains postscript code of pattern definition
*/
public String toString(boolean acrobatDownsample) {
StringBuffer sb = new StringBuffer("<<\n");
sb.append("/PatternType " + this.patternType + "\n");
sb.append("/PaintType " + paintType + "\n");
sb.append("/TilingType " + tilingType + "\n");
sb.append("/XStep " + xStep + "\n");
sb.append("/YStep " + yStep + "\n");
sb.append("/BBox " + "[" + bBox.getX() + " " + bBox.getY() + " "
+ bBox.getWidth() + " " + bBox.getHeight() + "]" + "\n");
sb.append("/PaintProc\n" + "{\n");
// the PaintProc procedure is expected to consume its dictionary operand !
if ((paintProc == null) || (paintProc.indexOf("pop") != 0)) {
sb.append("pop\n");
}
if (texture != null) {
int width = texture.getImage().getWidth();
int height = texture.getImage().getHeight();
Rectangle2D anchor = texture.getAnchorRect();
if (anchor.getX() != 0 || anchor.getY() != 0) {
sb.append(anchor.getX() + " " + anchor.getY() + " translate\n");
}
double scaleX = anchor.getWidth() / width;
double scaleY = anchor.getHeight() / height;
if (scaleX != 1 || scaleY != 1) {
sb.append(scaleX + " " + scaleY + " scale\n");
}
// define color image: width height bits/comp matrix
// datasrc0 datasrcncomp-1 multi ncomp colorimage
// width height bits/comp matrix
int bits = 8;
if (acrobatDownsample) {
bits = 4;
}
sb.append(width).append(" ").append(height).append(" ").append(bits).append(" ").append("matrix\n");
int [] argb = new int[width * height]; // datasrc0 datasrcncomp-1
getAsRGB().getRGB(0, 0, width, height, argb, 0, width);
writeImage(sb, argb, width, bits);
sb.append(" false 3 colorimage"); // multi ncomp colorimage
} else {
sb.append(paintProc);
}
sb.append("\n} bind \n"); // the end of PaintProc
sb.append(">>\n");
// create pattern instance from prototype
sb.append("matrix\n");
sb.append("makepattern\n");
// save pattern to current dictionary
sb.append("/" + patternName + " exch def\n");
return sb.toString();
}
private void writeImage(StringBuffer sb, int[] argb, int width, int bits) {
int count = 0;
sb.append("{<");
for (int i = 0; i < argb.length; i++) {
if ((i % width == 0) || (count > 249)) {
sb.append('\n');
count = 0; // line should not be longer than 255 characters
}
if (bits == 4) {
Color c = new Color(argb[i]);
int v = c.getRed() / 16;
String s = Integer.toHexString(v);
sb.append(s);
v = c.getGreen() / 16;
s = Integer.toHexString(v);
sb.append(s);
v = c.getBlue() / 16;
s = Integer.toHexString(v);
sb.append(s);
count += 3;
} else {
// delete alpha canal and write to output
StringBuffer sRGB = new StringBuffer(Integer.toHexString(argb[i] & 0x00ffffff));
if (sRGB.length() != 6) {
sRGB.insert(0, "000000"); // zero padding
sRGB = new StringBuffer(sRGB.substring(sRGB.length() - 6));
}
sb.append(sRGB);
count += 6;
}
}
sb.append("\n>}");
}
private BufferedImage getAsRGB() {
BufferedImage img = texture.getImage();
if (img.getType() != BufferedImage.TYPE_INT_RGB) {
BufferedImage buf = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g = buf.createGraphics();
g.setComposite(AlphaComposite.SrcOver);
g.setBackground(Color.white);
g.fillRect(0, 0, img.getWidth(), img.getHeight());
g.drawImage(img, 0, 0, null);
g.dispose();
return buf;
}
return img;
}
/** {@inheritDoc} */
public int hashCode() {
return
0
^ patternType
^ ((xUID != null) ? xUID.hashCode() : 0)
^ ((paintProc != null) ? paintProc.hashCode() : 0)
^ ((bBox != null) ? bBox.hashCode() : 0)
^ Double.valueOf(xStep).hashCode()
^ Double.valueOf(yStep).hashCode()
^ paintType
^ tilingType
^ ((texture != null) ? texture.hashCode() : 0);
}
/**
* Compares two patterns data (except their names).
* {@inheritDoc}
*/
public boolean equals(Object pattern) {
if (pattern == null) {
return false;
}
if (!(pattern instanceof PSTilingPattern)) {
return false;
}
if (this == pattern) {
return true;
}
PSTilingPattern patternObj = (PSTilingPattern) pattern;
if (this.patternType != patternObj.patternType) {
return false;
}
TexturePaint patternTexture = patternObj.getTexturePaint();
if (((patternTexture == null) && (texture != null))
|| ((patternTexture != null) && (texture == null))) {
return false;
}
if ((patternTexture != null) && (texture != null)) {
// compare textures data
int width = texture.getImage().getWidth();
int height = texture.getImage().getHeight();
int widthPattern = patternTexture.getImage().getWidth();
int heightPattern = patternTexture.getImage().getHeight();
if (width != widthPattern) {
return false;
}
if (height != heightPattern) {
return false;
}
int [] rgbData = new int[width * height];
int [] rgbDataPattern = new int[widthPattern * heightPattern];
texture.getImage().getRGB(0, 0, width, height, rgbData, 0, width);
patternTexture.getImage().getRGB(0, 0, widthPattern, heightPattern,
rgbDataPattern, 0, widthPattern);
for (int i = 0; i < rgbData.length; i++) {
if (rgbData[i] != rgbDataPattern[i]) {
return false;
}
}
} else {
// compare PaintProc
if (!paintProc.toString().equals(patternObj.getPaintProc().toString())) {
return false;
}
}
// compare other parameters
if (xStep != patternObj.getXStep()) {
return false;
}
if (yStep != patternObj.getYStep()) {
return false;
}
if (paintType != patternObj.getPaintType()) {
return false;
}
if (tilingType != patternObj.getTilingType()) {
return false;
}
if (!bBox.equals(patternObj.getBoundingBox())) {
return false;
}
if ((xUID != null) && (patternObj.getXUID() != null)) {
if (!xUID.equals(patternObj.getXUID())) {
return false;
}
}
return true;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy