| /* |
| * 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$ */ |
| |
| package org.apache.fop.pdf; |
| |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import java.util.List; |
| |
| /** |
| * class representing a PDF Function. |
| * |
| * PDF Functions represent parameterized mathematical formulas and sampled representations with |
| * arbitrary resolution. Functions are used in two areas: device-dependent |
| * rasterization information for halftoning and transfer |
| * functions, and color specification for smooth shading (a PDF 1.3 feature). |
| * |
| * All PDF Functions have a FunctionType (0,2,3, or 4), a Domain, and a Range. |
| */ |
| public class PDFPattern extends PDFPathPaint { |
| |
| /** |
| * The resources associated with this pattern |
| */ |
| protected PDFResources resources; |
| |
| /** |
| * Either one (1) for tiling, or two (2) for shading. |
| */ |
| protected int patternType = 2; // Default |
| |
| /** |
| * The name of the pattern such as "Pa1" or "Pattern1" |
| */ |
| protected String patternName; |
| |
| /** |
| * 1 for colored pattern, 2 for uncolored |
| */ |
| protected int paintType = 2; |
| |
| /** |
| * 1 for constant spacing, 2 for no distortion, and 3 for fast rendering |
| */ |
| protected int tilingType = 1; |
| |
| /** |
| * List of Doubles representing the Bounding box rectangle |
| */ |
| protected List bBox; |
| |
| /** |
| * Horizontal spacing |
| */ |
| protected double xStep = -1; |
| |
| /** |
| * Vertical spacing |
| */ |
| protected double yStep = -1; |
| |
| /** |
| * The Shading object comprising the Type 2 pattern |
| */ |
| protected PDFShading shading; |
| |
| /** |
| * List of Integers represetning the Extended unique Identifier |
| */ |
| protected List xUID; |
| |
| /** |
| * TODO use PDFGState |
| * String representing the extended Graphics state. |
| * Probably will never be used like this. |
| */ |
| protected StringBuffer extGState; |
| |
| /** |
| * List of Doubles representing the Transformation matrix. |
| */ |
| protected List matrix; |
| |
| /** |
| * The stream of a pattern |
| */ |
| protected StringBuffer patternDataStream; |
| |
| /** |
| * Create a tiling pattern (type 1). |
| * |
| * @param theResources the resources associated with this pattern |
| * @param thePatternType the type of pattern, which is 1 for tiling. |
| * @param thePaintType 1 or 2, colored or uncolored. |
| * @param theTilingType 1, 2, or 3, constant spacing, no distortion, or faster tiling |
| * @param theBBox List of Doubles: The pattern cell bounding box |
| * @param theXStep horizontal spacing |
| * @param theYStep vertical spacing |
| * @param theMatrix Optional List of Doubles transformation matrix |
| * @param theXUID Optional vector of Integers that uniquely identify the pattern |
| * @param thePatternDataStream The stream of pattern data to be tiled. |
| */ |
| public PDFPattern(PDFResources theResources, int thePatternType, |
| int thePaintType, int theTilingType, List theBBox, |
| double theXStep, double theYStep, |
| List theMatrix, List theXUID, |
| StringBuffer thePatternDataStream) { |
| super(); |
| this.resources = theResources; |
| // This next parameter is implicit to all constructors, and is |
| // not directly passed. |
| |
| this.patternType = 1; // thePatternType; |
| this.paintType = thePaintType; |
| this.tilingType = theTilingType; |
| this.bBox = theBBox; |
| this.xStep = theXStep; |
| this.yStep = theYStep; |
| this.matrix = theMatrix; |
| this.xUID = theXUID; |
| this.patternDataStream = thePatternDataStream; |
| } |
| |
| /** |
| * Create a type 2 pattern (smooth shading) |
| * |
| * @param thePatternType the type of the pattern, which is 2, smooth shading |
| * @param shading the Shading object that comprises this pattern |
| * @param theXUID optional:the extended unique Identifier if used. |
| * @param theExtGState optional: the extended graphics state, if used. |
| * @param theMatrix Optional:List of Doubles that specify the matrix. |
| */ |
| public PDFPattern(int thePatternType, PDFShading shading, |
| List theXUID, StringBuffer theExtGState, |
| List theMatrix) { |
| super(); |
| |
| this.patternType = 2; // thePatternType; |
| this.shading = shading; |
| this.xUID = theXUID; |
| // this isn't really implemented, so it should always be null. |
| // I just don't want to have to add a new parameter once it is implemented. |
| this.extGState = theExtGState; // always null |
| this.matrix = theMatrix; |
| } |
| |
| /** |
| * Get 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. "Pattern1" or "Pa1" are good examples. |
| */ |
| public void setName(String name) { |
| if (name.indexOf(" ") >= 0) { |
| throw new IllegalArgumentException( |
| "Pattern name must not contain any spaces"); |
| } |
| this.patternName = name; |
| } |
| |
| /** |
| * Get the PDF command for setting to this pattern. |
| * |
| * @param fillNotStroke if true fill otherwise stroke |
| * @return the PDF string for setting the pattern |
| */ |
| public String getColorSpaceOut(boolean fillNotStroke) { |
| if (fillNotStroke) { // fill but no stroke |
| return ("/Pattern cs /" + this.getName() + " scn \n"); |
| } else { // stroke (or border) |
| return ("/Pattern CS /" + this.getName() + " SCN \n"); |
| } |
| } |
| |
| /** |
| * represent as PDF. Whatever the FunctionType is, the correct |
| * representation spits out. The sets of required and optional |
| * attributes are different for each type, but if a required |
| * attribute's object was constructed as null, then no error |
| * is raised. Instead, the malformed PDF that was requested |
| * by the construction is dutifully output. |
| * This policy should be reviewed. |
| * |
| * @param stream the stream to write to |
| * @throws IOException if there is an error writing to the stream |
| * @return the PDF string. |
| */ |
| public int output(OutputStream stream) throws IOException { |
| |
| int vectorSize = 0; |
| int tempInt = 0; |
| byte[] buffer; |
| StringBuffer p = new StringBuffer(64); |
| p.append("<< \n/Type /Pattern \n"); |
| |
| if (this.resources != null) { |
| p.append("/Resources " + this.resources.referencePDF() + " \n"); |
| } |
| |
| p.append("/PatternType " + this.patternType + " \n"); |
| |
| PDFStream pdfStream = null; |
| StreamCache encodedStream = null; |
| |
| if (this.patternType == 1) { |
| p.append("/PaintType " + this.paintType + " \n"); |
| p.append("/TilingType " + this.tilingType + " \n"); |
| |
| if (this.bBox != null) { |
| vectorSize = this.bBox.size(); |
| p.append("/BBox [ "); |
| for (tempInt = 0; tempInt < vectorSize; tempInt++) { |
| p.append(PDFNumber.doubleOut((Double)this.bBox.get(tempInt))); |
| p.append(" "); |
| } |
| p.append("] \n"); |
| } |
| p.append("/XStep " + PDFNumber.doubleOut(Double.valueOf(this.xStep)) |
| + " \n"); |
| p.append("/YStep " + PDFNumber.doubleOut(Double.valueOf(this.yStep)) |
| + " \n"); |
| |
| if (this.matrix != null) { |
| vectorSize = this.matrix.size(); |
| p.append("/Matrix [ "); |
| for (tempInt = 0; tempInt < vectorSize; tempInt++) { |
| p.append(PDFNumber.doubleOut( |
| (Double) this.matrix.get(tempInt), 8)); |
| p.append(" "); |
| } |
| p.append("] \n"); |
| } |
| |
| if (this.xUID != null) { |
| vectorSize = this.xUID.size(); |
| p.append("/XUID [ "); |
| for (tempInt = 0; tempInt < vectorSize; tempInt++) { |
| p.append((this.xUID.get(tempInt)) + " "); |
| } |
| p.append("] \n"); |
| } |
| |
| // don't forget the length of the stream. |
| if (this.patternDataStream != null) { |
| pdfStream = new PDFStream(); |
| pdfStream.setDocument(getDocumentSafely()); |
| pdfStream.add(this.patternDataStream.toString()); |
| pdfStream.setObjectNumber(getObjectNumber()); |
| pdfStream.getFilterList().addDefaultFilters( |
| getDocument().getFilterMap(), |
| PDFFilterList.CONTENT_FILTER); |
| getDocument().applyEncryption(pdfStream); |
| encodedStream = pdfStream.encodeStream(); |
| p.append(pdfStream.getFilterList().buildFilterDictEntries()); |
| p.append("/Length " + encodedStream.getSize() + " \n"); |
| } |
| |
| } else { |
| // if (this.patternType ==2) |
| // Smooth Shading... |
| if (this.shading != null) { |
| p.append("/Shading " + this.shading.referencePDF() + " \n"); |
| } |
| |
| if (this.xUID != null) { |
| vectorSize = this.xUID.size(); |
| p.append("/XUID [ "); |
| for (tempInt = 0; tempInt < vectorSize; tempInt++) { |
| p.append((this.xUID.get(tempInt)) + " "); |
| } |
| p.append("] \n"); |
| } |
| |
| if (this.extGState != null) { |
| p.append("/ExtGState " + this.extGState + " \n"); |
| } |
| |
| if (this.matrix != null) { |
| vectorSize = this.matrix.size(); |
| p.append("/Matrix [ "); |
| for (tempInt = 0; tempInt < vectorSize; tempInt++) { |
| p.append(PDFNumber.doubleOut( |
| (Double) this.matrix.get(tempInt), 8)); |
| p.append(" "); |
| } |
| p.append("] \n"); |
| } |
| } // end of if patterntype =1...else 2. |
| |
| p.append(">> \n"); |
| |
| buffer = encode(p.toString()); |
| int length = buffer.length; |
| stream.write(buffer); |
| |
| // stream representing the function |
| if (pdfStream != null) { |
| length += pdfStream.outputStreamData(encodedStream, stream); |
| } |
| patternDataStream = null; |
| return length; |
| } |
| |
| /** |
| * Output PDF bytes, not used. |
| * @return returns null |
| */ |
| public byte[] toPDF() { |
| return null; |
| } |
| |
| /** {@inheritDoc} */ |
| protected boolean contentEquals(PDFObject obj) { |
| if (obj == null) { |
| return false; |
| } |
| if (obj == this) { |
| return true; |
| } |
| if (!(obj instanceof PDFPattern)) { |
| return false; |
| } |
| PDFPattern patt = (PDFPattern)obj; |
| if (patternType != patt.patternType) { |
| return false; |
| } |
| if (paintType != patt.paintType) { |
| return false; |
| } |
| if (tilingType != patt.tilingType) { |
| return false; |
| } |
| if (xStep != patt.xStep) { |
| return false; |
| } |
| if (yStep != patt.yStep) { |
| return false; |
| } |
| if (bBox != null) { |
| if (!bBox.equals(patt.bBox)) { |
| return false; |
| } |
| } else if (patt.bBox != null) { |
| return false; |
| } |
| if (bBox != null) { |
| if (!bBox.equals(patt.bBox)) { |
| return false; |
| } |
| } else if (patt.bBox != null) { |
| return false; |
| } |
| if (xUID != null) { |
| if (!xUID.equals(patt.xUID)) { |
| return false; |
| } |
| } else if (patt.xUID != null) { |
| return false; |
| } |
| if (extGState != null) { |
| if (!extGState.equals(patt.extGState)) { |
| return false; |
| } |
| } else if (patt.extGState != null) { |
| return false; |
| } |
| if (matrix != null) { |
| if (!matrix.equals(patt.matrix)) { |
| return false; |
| } |
| } else if (patt.matrix != null) { |
| return false; |
| } |
| if (resources != null) { |
| if (!resources.equals(patt.resources)) { |
| return false; |
| } |
| } else if (patt.resources != null) { |
| return false; |
| } |
| if (shading != null) { |
| if (!shading.equals(patt.shading)) { |
| return false; |
| } |
| } else if (patt.shading != null) { |
| return false; |
| } |
| if (patternDataStream != null) { |
| if (!patternDataStream.equals(patt.patternDataStream)) { |
| return false; |
| } |
| } else if (patt.patternDataStream != null) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| } |