aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/fop/pdf
diff options
context:
space:
mode:
Diffstat (limited to 'src/java/org/apache/fop/pdf')
-rw-r--r--src/java/org/apache/fop/pdf/AbstractPDFStream.java4
-rw-r--r--src/java/org/apache/fop/pdf/PDFCFFStreamType0C.java74
-rw-r--r--src/java/org/apache/fop/pdf/PDFDictionary.java2
-rw-r--r--src/java/org/apache/fop/pdf/PDFDocument.java54
-rw-r--r--src/java/org/apache/fop/pdf/PDFFactory.java187
-rw-r--r--src/java/org/apache/fop/pdf/PDFFontDescriptor.java2
-rw-r--r--src/java/org/apache/fop/pdf/PDFFunction.java651
-rw-r--r--src/java/org/apache/fop/pdf/PDFIdentifiedDictionary.java42
-rw-r--r--src/java/org/apache/fop/pdf/PDFLayer.java86
-rw-r--r--src/java/org/apache/fop/pdf/PDFNavigator.java93
-rw-r--r--src/java/org/apache/fop/pdf/PDFNavigatorAction.java28
-rw-r--r--src/java/org/apache/fop/pdf/PDFNumber.java8
-rw-r--r--src/java/org/apache/fop/pdf/PDFPaintingState.java34
-rw-r--r--src/java/org/apache/fop/pdf/PDFPattern.java19
-rw-r--r--src/java/org/apache/fop/pdf/PDFResources.java34
-rw-r--r--src/java/org/apache/fop/pdf/PDFSetOCGStateAction.java82
-rw-r--r--src/java/org/apache/fop/pdf/PDFShading.java373
-rw-r--r--src/java/org/apache/fop/pdf/PDFTransitionAction.java79
18 files changed, 1046 insertions, 806 deletions
diff --git a/src/java/org/apache/fop/pdf/AbstractPDFStream.java b/src/java/org/apache/fop/pdf/AbstractPDFStream.java
index 41eed4885..13bd1bda1 100644
--- a/src/java/org/apache/fop/pdf/AbstractPDFStream.java
+++ b/src/java/org/apache/fop/pdf/AbstractPDFStream.java
@@ -143,7 +143,7 @@ public abstract class AbstractPDFStream extends PDFObject {
*/
protected int outputStreamData(StreamCache encodedStream, OutputStream out) throws IOException {
int length = 0;
- byte[] p = encode("stream\n");
+ byte[] p = encode("\nstream\n");
out.write(p);
length += p.length;
@@ -186,7 +186,7 @@ public abstract class AbstractPDFStream extends PDFObject {
throws IOException {
int bytesWritten = 0;
//Stream header
- byte[] buf = encode("stream\n");
+ byte[] buf = encode("\nstream\n");
out.write(buf);
bytesWritten += buf.length;
diff --git a/src/java/org/apache/fop/pdf/PDFCFFStreamType0C.java b/src/java/org/apache/fop/pdf/PDFCFFStreamType0C.java
new file mode 100644
index 000000000..53f0b36b4
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFCFFStreamType0C.java
@@ -0,0 +1,74 @@
+/*
+ * 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;
+
+/**
+ * PDFStream for embeddable OpenType CFF fonts.
+ */
+public class PDFCFFStreamType0C extends AbstractPDFFontStream {
+
+ private byte[] cffData;
+ private boolean fullEmbed;
+
+ /**
+ * Main constructor
+ * @param fullEmbed Determines whether the font is fully embedded
+ */
+ public PDFCFFStreamType0C(boolean fullEmbed) {
+ super();
+ this.fullEmbed = fullEmbed;
+ }
+
+ protected int getSizeHint() throws IOException {
+ if (this.cffData != null) {
+ return cffData.length;
+ } else {
+ return 0; //no hint available
+ }
+ }
+
+ /** {@inheritDoc} */
+ protected void outputRawStreamData(OutputStream out) throws IOException {
+ out.write(this.cffData);
+ }
+
+ /** {@inheritDoc} */
+ protected void populateStreamDict(Object lengthEntry) {
+ String type = (fullEmbed) ? "OpenType" : "CIDFontType0C";
+ put("Subtype", new PDFName(type));
+ super.populateStreamDict(lengthEntry);
+ }
+
+ /**
+ * Sets the CFF font data.
+ * @param data the font payload
+ * @param size size of the payload
+ * @throws IOException in case of an I/O problem
+ */
+ public void setData(byte[] data, int size) throws IOException {
+ this.cffData = new byte[size];
+ System.arraycopy(data, 0, this.cffData, 0, size);
+ }
+
+}
+
diff --git a/src/java/org/apache/fop/pdf/PDFDictionary.java b/src/java/org/apache/fop/pdf/PDFDictionary.java
index 6bacd31a3..ae0b950fd 100644
--- a/src/java/org/apache/fop/pdf/PDFDictionary.java
+++ b/src/java/org/apache/fop/pdf/PDFDictionary.java
@@ -131,7 +131,7 @@ public class PDFDictionary extends PDFObject {
} else {
textBuffer.append('\n');
}
- textBuffer.append(">>\n");
+ textBuffer.append(">>");
}
}
diff --git a/src/java/org/apache/fop/pdf/PDFDocument.java b/src/java/org/apache/fop/pdf/PDFDocument.java
index ff9f61201..bcd54fcb9 100644
--- a/src/java/org/apache/fop/pdf/PDFDocument.java
+++ b/src/java/org/apache/fop/pdf/PDFDocument.java
@@ -155,6 +155,12 @@ public class PDFDocument {
private List<PDFLaunch> launches = new ArrayList<PDFLaunch>();
+ private List<PDFLayer> layers;
+
+ private List<PDFNavigator> navigators;
+
+ private List<PDFNavigatorAction> navigatorActions;
+
private PDFFactory factory;
private FileIDGenerator fileIDGenerator;
@@ -477,6 +483,24 @@ public class PDFDocument {
if (obj instanceof PDFGoToRemote) {
this.gotoremotes.add((PDFGoToRemote) obj);
}
+ if (obj instanceof PDFLayer) {
+ if (this.layers == null) {
+ this.layers = new ArrayList<PDFLayer>();
+ }
+ this.layers.add((PDFLayer) obj);
+ }
+ if (obj instanceof PDFNavigator) {
+ if (this.navigators == null) {
+ this.navigators = new ArrayList<PDFNavigator>();
+ }
+ this.navigators.add((PDFNavigator) obj);
+ }
+ if (obj instanceof PDFNavigatorAction) {
+ if (this.navigatorActions == null) {
+ this.navigatorActions = new ArrayList<PDFNavigatorAction>();
+ }
+ this.navigatorActions.add((PDFNavigatorAction) obj);
+ }
}
/**
@@ -890,6 +914,34 @@ public class PDFDocument {
}
/**
+ *
+ */
+ public PDFReference resolveExtensionReference(String id) {
+ if (layers != null) {
+ for (PDFLayer layer : layers) {
+ if (layer.hasId(id)) {
+ return layer.makeReference();
+ }
+ }
+ }
+ if (navigators != null) {
+ for (PDFNavigator navigator : navigators) {
+ if (navigator.hasId(id)) {
+ return navigator.makeReference();
+ }
+ }
+ }
+ if (navigatorActions != null) {
+ for (PDFNavigatorAction action : navigatorActions) {
+ if (action.hasId(id)) {
+ return action.makeReference();
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
* Writes out the entire document
*
* @param stream the OutputStream to output the document to
@@ -1009,7 +1061,7 @@ public class PDFDocument {
streamIndirectObjects(trailerObjects, stream);
TrailerDictionary trailerDictionary = createTrailerDictionary();
long startxref = trailerOutputHelper.outputCrossReferenceObject(stream, trailerDictionary);
- String trailer = "startxref\n" + startxref + "\n%%EOF\n";
+ String trailer = "\nstartxref\n" + startxref + "\n%%EOF\n";
stream.write(encode(trailer));
}
diff --git a/src/java/org/apache/fop/pdf/PDFFactory.java b/src/java/org/apache/fop/pdf/PDFFactory.java
index 1756f1d56..070630274 100644
--- a/src/java/org/apache/fop/pdf/PDFFactory.java
+++ b/src/java/org/apache/fop/pdf/PDFFactory.java
@@ -56,6 +56,8 @@ import org.apache.fop.fonts.SingleByteEncoding;
import org.apache.fop.fonts.SingleByteFont;
import org.apache.fop.fonts.Typeface;
import org.apache.fop.fonts.truetype.FontFileReader;
+import org.apache.fop.fonts.truetype.OFFontLoader;
+import org.apache.fop.fonts.truetype.OTFSubSetFile;
import org.apache.fop.fonts.truetype.TTFSubSetFile;
import org.apache.fop.fonts.type1.PFBData;
import org.apache.fop.fonts.type1.PFBParser;
@@ -308,12 +310,7 @@ public class PDFFactory {
theFunctionDataStream,
theFilter);
- PDFFunction oldfunc = getDocument().findFunction(function);
- if (oldfunc == null) {
- getDocument().registerObject(function);
- } else {
- function = oldfunc;
- }
+ function = registerFunction(function);
return (function);
}
@@ -350,12 +347,7 @@ public class PDFFactory {
PDFFunction function = new PDFFunction(theFunctionType, theDomain,
theRange, theCZero, theCOne,
theInterpolationExponentN);
- PDFFunction oldfunc = getDocument().findFunction(function);
- if (oldfunc == null) {
- getDocument().registerObject(function);
- } else {
- function = oldfunc;
- }
+ function = registerFunction(function);
return (function);
}
@@ -405,12 +397,7 @@ public class PDFFactory {
theRange, theFunctions,
theBounds, theEncode);
- PDFFunction oldfunc = getDocument().findFunction(function);
- if (oldfunc == null) {
- getDocument().registerObject(function);
- } else {
- function = oldfunc;
- }
+ function = registerFunction(function);
return (function);
}
@@ -432,14 +419,23 @@ public class PDFFactory {
theRange,
theFunctionDataStream);
+ function = registerFunction(function);
+ return (function);
+
+ }
+
+ /**
+ * Registers a function against the document
+ * @param function The function to register
+ */
+ public PDFFunction registerFunction(PDFFunction function) {
PDFFunction oldfunc = getDocument().findFunction(function);
if (oldfunc == null) {
getDocument().registerObject(function);
} else {
function = oldfunc;
}
- return (function);
-
+ return function;
}
/* ========================= shadings ================================== */
@@ -479,20 +475,7 @@ public class PDFFactory {
theBBox, theAntiAlias, theDomain,
theMatrix, theFunction);
- PDFShading oldshad = getDocument().findShading(shading);
- if (oldshad == null) {
- getDocument().registerObject(shading);
- } else {
- shading = oldshad;
- }
-
- // add this shading to resources
- if (res != null) {
- res.getPDFResources().addShading(shading);
- } else {
- getDocument().getResources().addShading(shading);
- }
-
+ shading = registerShading(res, shading);
return (shading);
}
@@ -532,18 +515,7 @@ public class PDFFactory {
theDomain, theFunction,
theExtend);
- PDFShading oldshad = getDocument().findShading(shading);
- if (oldshad == null) {
- getDocument().registerObject(shading);
- } else {
- shading = oldshad;
- }
-
- if (res != null) {
- res.getPDFResources().addShading(shading);
- } else {
- getDocument().getResources().addShading(shading);
- }
+ shading = registerShading(res, shading);
return (shading);
}
@@ -589,18 +561,7 @@ public class PDFFactory {
theBitsPerFlag, theDecode,
theFunction);
- PDFShading oldshad = getDocument().findShading(shading);
- if (oldshad == null) {
- getDocument().registerObject(shading);
- } else {
- shading = oldshad;
- }
-
- if (res != null) {
- res.getPDFResources().addShading(shading);
- } else {
- getDocument().getResources().addShading(shading);
- }
+ shading = registerShading(res, shading);
return (shading);
}
@@ -643,6 +604,17 @@ public class PDFFactory {
theBitsPerComponent, theDecode,
theVerticesPerRow, theFunction);
+ shading = registerShading(res, shading);
+
+ return (shading);
+ }
+
+ /**
+ * Registers a shading object against the document
+ * @param res The PDF resource context
+ * @param shading The shading object to be registered
+ */
+ public PDFShading registerShading(PDFResourceContext res, PDFShading shading) {
PDFShading oldshad = getDocument().findShading(shading);
if (oldshad == null) {
getDocument().registerObject(shading);
@@ -650,13 +622,13 @@ public class PDFFactory {
shading = oldshad;
}
+ // add this shading to resources
if (res != null) {
res.getPDFResources().addShading(shading);
} else {
getDocument().getResources().addShading(shading);
}
-
- return (shading);
+ return shading;
}
/* ========================= patterns ================================== */
@@ -705,6 +677,22 @@ public class PDFFactory {
return (pattern);
}
+ public PDFPattern registerPattern(PDFResourceContext res, PDFPattern pattern) {
+ PDFPattern oldpatt = getDocument().findPattern(pattern);
+ if (oldpatt == null) {
+ getDocument().registerObject(pattern);
+ } else {
+ pattern = oldpatt;
+ }
+
+ if (res != null) {
+ res.getPDFResources().addPattern(pattern);
+ } else {
+ getDocument().getResources().addPattern(pattern);
+ }
+ return pattern;
+ }
+
/**
* Make a smooth shading pattern
*
@@ -1387,15 +1375,15 @@ public class PDFFactory {
int firstChar = singleByteFont.getFirstChar();
int lastChar = singleByteFont.getLastChar();
nonBase14.setWidthMetrics(firstChar,
- lastChar,
- new PDFArray(null, metrics.getWidths()));
+ lastChar,
+ new PDFArray(null, metrics.getWidths()));
//Handle encoding
SingleByteEncoding mapping = singleByteFont.getEncoding();
if (singleByteFont.isSymbolicFont()) {
//no encoding, use the font's encoding
if (forceToUnicode) {
- generateToUnicodeCmap(nonBase14, mapping);
+ generateToUnicodeCmap(nonBase14, mapping);
}
} else if (PDFEncoding.isPredefinedEncoding(mapping.getName())) {
font.setEncoding(mapping.getName());
@@ -1403,7 +1391,7 @@ public class PDFFactory {
//believed.
} else {
Object pdfEncoding = createPDFEncoding(mapping,
- singleByteFont.getFontName());
+ singleByteFont.getFontName());
if (pdfEncoding instanceof PDFEncoding) {
font.setEncoding((PDFEncoding)pdfEncoding);
} else {
@@ -1518,7 +1506,8 @@ public class PDFFactory {
// Check if the font is embeddable
if (desc.isEmbeddable()) {
- AbstractPDFStream stream = makeFontFile(desc);
+ AbstractPDFStream stream = makeFontFile(desc, fontPrefix);
+
if (stream != null) {
descriptor.setFontFile(desc.getFontType(), stream);
getDocument().registerObject(stream);
@@ -1564,7 +1553,7 @@ public class PDFFactory {
* @param desc FontDescriptor of the font.
* @return PDFStream The embedded font file
*/
- public AbstractPDFStream makeFontFile(FontDescriptor desc) {
+ public AbstractPDFStream makeFontFile(FontDescriptor desc, String fontPrefix) {
if (desc.getFontType() == FontType.OTHER) {
throw new IllegalArgumentException("Trying to embed unsupported font type: "
+ desc.getFontType());
@@ -1578,20 +1567,24 @@ public class PDFFactory {
if (in == null) {
return null;
} else {
- AbstractPDFStream embeddedFont;
+ AbstractPDFStream embeddedFont = null;
if (desc.getFontType() == FontType.TYPE0) {
MultiByteFont mbfont = (MultiByteFont) font;
FontFileReader reader = new FontFileReader(in);
byte[] fontBytes;
+ String header = OFFontLoader.readHeader(reader);
+ boolean isCFF = mbfont.isOTFFile();
if (font.getEmbeddingMode() == EmbeddingMode.FULL) {
fontBytes = reader.getAllBytes();
+ if (isCFF) {
+ //Ensure version 1.6 for full OTF CFF embedding
+ document.setPDFVersion(Version.V1_6);
+ }
} else {
- TTFSubSetFile ttfFile = new TTFSubSetFile();
- ttfFile.readFont(reader, mbfont.getTTCName(), mbfont.getUsedGlyphs());
- fontBytes = ttfFile.getFontSubset();
+ fontBytes = getFontSubsetBytes(reader, mbfont, header, fontPrefix, desc,
+ isCFF);
}
- embeddedFont = new PDFTTFStream(fontBytes.length);
- ((PDFTTFStream) embeddedFont).setData(fontBytes, fontBytes.length);
+ embeddedFont = getFontStream(font, fontBytes, isCFF);
} else if (desc.getFontType() == FontType.TYPE1) {
PFBParser parser = new PFBParser();
PFBData pfb = parser.parsePFB(in);
@@ -1621,6 +1614,32 @@ public class PDFFactory {
}
}
+ private byte[] getFontSubsetBytes(FontFileReader reader, MultiByteFont mbfont, String header,
+ String fontPrefix, FontDescriptor desc, boolean isCFF) throws IOException {
+ if (isCFF) {
+ OTFSubSetFile otfFile = new OTFSubSetFile();
+ otfFile.readFont(reader, fontPrefix + desc.getEmbedFontName(), header, mbfont);
+ return otfFile.getFontSubset();
+ } else {
+ TTFSubSetFile otfFile = new TTFSubSetFile();
+ otfFile.readFont(reader, mbfont.getTTCName(), header, mbfont.getUsedGlyphs());
+ return otfFile.getFontSubset();
+ }
+ }
+
+ private AbstractPDFStream getFontStream(CustomFont font, byte[] fontBytes, boolean isCFF)
+ throws IOException {
+ AbstractPDFStream embeddedFont;
+ if (isCFF) {
+ embeddedFont = new PDFCFFStreamType0C(font.getEmbeddingMode() == EmbeddingMode.FULL);
+ ((PDFCFFStreamType0C) embeddedFont).setData(fontBytes, fontBytes.length);
+ } else {
+ embeddedFont = new PDFTTFStream(fontBytes.length);
+ ((PDFTTFStream) embeddedFont).setData(fontBytes, fontBytes.length);
+ }
+ return embeddedFont;
+ }
+
private CustomFont getCustomFont(FontDescriptor desc) {
Typeface tempFont;
if (desc instanceof LazyFont) {
@@ -1788,4 +1807,28 @@ public class PDFFactory {
return obj;
}
+ public PDFLayer makeLayer(String id) {
+ PDFLayer layer = new PDFLayer(id);
+ getDocument().registerObject(layer);
+ return layer;
+ }
+
+ public PDFSetOCGStateAction makeSetOCGStateAction(String id) {
+ PDFSetOCGStateAction action = new PDFSetOCGStateAction(id);
+ getDocument().registerObject(action);
+ return action;
+ }
+
+ public PDFTransitionAction makeTransitionAction(String id) {
+ PDFTransitionAction action = new PDFTransitionAction(id);
+ getDocument().registerObject(action);
+ return action;
+ }
+
+ public PDFNavigator makeNavigator(String id) {
+ PDFNavigator navigator = new PDFNavigator(id);
+ getDocument().registerObject(navigator);
+ return navigator;
+ }
+
}
diff --git a/src/java/org/apache/fop/pdf/PDFFontDescriptor.java b/src/java/org/apache/fop/pdf/PDFFontDescriptor.java
index ec4e99101..73dbebc3f 100644
--- a/src/java/org/apache/fop/pdf/PDFFontDescriptor.java
+++ b/src/java/org/apache/fop/pdf/PDFFontDescriptor.java
@@ -102,6 +102,8 @@ public class PDFFontDescriptor extends PDFDictionary {
public void setFontFile(FontType subtype, AbstractPDFStream fontfile) {
if (subtype == FontType.TYPE1) {
put("FontFile", fontfile);
+ } else if (fontfile instanceof PDFCFFStreamType0C) {
+ put("FontFile3", fontfile);
} else {
put("FontFile2", fontfile);
}
diff --git a/src/java/org/apache/fop/pdf/PDFFunction.java b/src/java/org/apache/fop/pdf/PDFFunction.java
index f424569b9..09cbd9708 100644
--- a/src/java/org/apache/fop/pdf/PDFFunction.java
+++ b/src/java/org/apache/fop/pdf/PDFFunction.java
@@ -22,6 +22,10 @@ package org.apache.fop.pdf;
// Java...
import java.util.List;
+import org.apache.fop.render.shading.Function;
+import org.apache.fop.render.shading.FunctionDelegate;
+import org.apache.fop.render.shading.FunctionPattern;
+
/**
* class representing a PDF Function.
*
@@ -33,126 +37,9 @@ import java.util.List;
*
* All PDF Functions have a FunctionType (0,2,3, or 4), a Domain, and a Range.
*/
-public class PDFFunction extends PDFObject {
- // Guts common to all function types
-
- /**
- * Required: The Type of function (0,2,3,4) default is 0.
- */
- protected int functionType = 0; // Default
-
- /**
- * Required: 2 * m Array of Double numbers which are possible inputs to the function
- */
- protected List domain = null;
-
- /**
- * Required: 2 * n Array of Double numbers which are possible outputs to the function
- */
- protected List range = null;
-
- /* ********************TYPE 0***************************** */
- // FunctionType 0 specific function guts
-
- /**
- * Required: Array containing the Integer size of the Domain and Range, respectively.
- * Note: This is really more like two seperate integers, sizeDomain, and sizeRange,
- * but since they're expressed as an array in PDF, my implementation reflects that.
- */
- protected List size = null;
-
- /**
- * Required for Type 0: Number of Bits used to represent each sample value.
- * Limited to 1,2,4,8,12,16,24, or 32
- */
- protected int bitsPerSample = 1;
-
- /**
- * Optional for Type 0: order of interpolation between samples.
- * Limited to linear (1) or cubic (3). Default is 1
- */
- protected int order = 1;
-
- /**
- * Optional for Type 0: A 2 * m array of Doubles which provides a
- * linear mapping of input values to the domain.
- *
- * Required for Type 3: A 2 * k array of Doubles that, taken
- * in pairs, map each subset of the domain defined by Domain
- * and the Bounds array to the domain of the corresponding function.
- * Should be two values per function, usually (0,1),
- * as in [0 1 0 1] for 2 functions.
- */
- protected List encode = null;
-
- /**
- * Optional for Type 0: A 2 * n array of Doubles which provides
- * a linear mapping of sample values to the range. Defaults to Range.
- */
- protected List decode = null;
-
- /**
- * Optional For Type 0: A stream of sample values
- */
-
- /**
- * Required For Type 4: Postscript Calculator function
- * composed of arithmetic, boolean, and stack operators + boolean constants
- */
- protected StringBuffer functionDataStream = null;
-
- /**
- * Required (possibly) For Type 0: A vector of Strings for the
- * various filters to be used to decode the stream.
- * These are how the string is compressed. Flate, LZW, etc.
- */
- protected List filter = null;
- /* *************************TYPE 2************************** */
-
- /**
- * Required For Type 2: An Array of n Doubles defining
- * the function result when x=0. Default is [0].
- */
- protected List cZero = null;
-
- /**
- * Required For Type 2: An Array of n Doubles defining
- * the function result when x=1. Default is [1].
- */
- protected List cOne = null;
+public class PDFFunction extends PDFObject implements Function {
- /**
- * Required for Type 2: The interpolation exponent.
- * Each value x will return n results.
- * Must be greater than 0.
- */
- protected double interpolationExponentN = 1;
-
- /* *************************TYPE 3************************** */
-
- /**
- * Required for Type 3: An vector of PDFFunctions which
- * form an array of k single input functions making up
- * the stitching function.
- */
- protected List functions = null;
-
- /**
- * Optional for Type 3: An array of (k-1) Doubles that,
- * in combination with Domain, define the intervals to which
- * each function from the Functions array apply. Bounds
- * elements must be in order of increasing magnitude,
- * and each value must be within the value of Domain.
- * k is the number of functions.
- * If you pass null, it will output (1/k) in an array of k-1 elements.
- * This makes each function responsible for an equal amount of the stitching function.
- * It makes the gradient even.
- */
- protected List bounds = null;
- // See encode above, as it's also part of Type 3 Functions.
-
- /* *************************TYPE 4************************** */
- // See 'data' above.
+ private FunctionDelegate delegate;
/**
* create an complete Function object of Type 0, A Sampled function.
@@ -211,26 +98,13 @@ public class PDFFunction extends PDFObject {
* @param theFunctionType This is the type of function (0,2,3, or 4).
* It should be 0 as this is the constructor for sampled functions.
*/
- public PDFFunction(int theFunctionType, List theDomain,
- List theRange, List theSize, int theBitsPerSample,
- int theOrder, List theEncode, List theDecode,
- StringBuffer theFunctionDataStream, List theFilter) {
- super();
-
- this.functionType = 0; // dang well better be 0;
- this.size = theSize;
- this.bitsPerSample = theBitsPerSample;
- this.order = theOrder; // int
- this.encode = theEncode; // vector of int
- this.decode = theDecode; // vector of int
- this.functionDataStream = theFunctionDataStream;
- this.filter = theFilter; // vector of Strings
-
- // the domain and range are actually two dimensional arrays.
- // so if there's not an even number of items, bad stuff
- // happens.
- this.domain = theDomain;
- this.range = theRange;
+ public PDFFunction(int theFunctionType, List<Double> theDomain,
+ List<Double> theRange, List<Double> theSize, int theBitsPerSample,
+ int theOrder, List<Double> theEncode, List<Double> theDecode,
+ StringBuffer theFunctionDataStream, List<String> theFilter) {
+ delegate = new FunctionDelegate(this, theFunctionType, theDomain, theRange,
+ theSize, theBitsPerSample, theOrder, theEncode, theDecode,
+ theFunctionDataStream, theFilter);
}
/**
@@ -260,20 +134,11 @@ public class PDFFunction extends PDFObject {
* PDF Spec page 268
* @param theFunctionType The type of the function, which should be 2.
*/
- public PDFFunction(int theFunctionType, List theDomain,
- List theRange, List theCZero, List theCOne,
+ public PDFFunction(int theFunctionType, List<Double> theDomain,
+ List<Double> theRange, List<Double> theCZero, List<Double> theCOne,
double theInterpolationExponentN) {
- super();
-
- this.functionType = 2; // dang well better be 2;
-
- this.cZero = theCZero;
- this.cOne = theCOne;
- this.interpolationExponentN = theInterpolationExponentN;
-
-
- this.domain = theDomain;
- this.range = theRange;
+ delegate = new FunctionDelegate(this, theFunctionType, theDomain, theRange,
+ theCZero, theCOne, theInterpolationExponentN);
}
@@ -312,18 +177,11 @@ public class PDFFunction extends PDFObject {
* @param theFunctionType This is the function type. It should be 3,
* for a stitching function.
*/
- public PDFFunction(int theFunctionType, List theDomain,
- List theRange, List theFunctions,
- List theBounds, List theEncode) {
- super();
-
- this.functionType = 3; // dang well better be 3;
-
- this.functions = theFunctions;
- this.bounds = theBounds;
- this.encode = theEncode;
- this.domain = theDomain;
- this.range = theRange;
+ public PDFFunction(int theFunctionType, List<Double> theDomain,
+ List<Double> theRange, List<Function> theFunctions,
+ List<Double> theBounds, List<Double> theEncode) {
+ delegate = new FunctionDelegate(this, theFunctionType, theDomain, theRange,
+ theFunctions, theBounds, theEncode);
}
@@ -349,20 +207,12 @@ public class PDFFunction extends PDFObject {
* @param theFunctionType The type of function which should be 4, as this is
* a Postscript calculator function
*/
- public PDFFunction(int theFunctionType, List theDomain,
- List theRange, StringBuffer theFunctionDataStream) {
- super();
-
- this.functionType = 4; // dang well better be 4;
- this.functionDataStream = theFunctionDataStream;
-
- this.domain = theDomain;
-
- this.range = theRange;
-
+ public PDFFunction(int theFunctionType, List<Double> theDomain,
+ List<Double> theRange, StringBuffer theFunctionDataStream) {
+ delegate = new FunctionDelegate(this, theFunctionType, theDomain, theRange,
+ theFunctionDataStream);
}
-
/**
* represent as PDF. Whatever the FunctionType is, the correct
* representation spits out. The sets of required and optional
@@ -375,319 +225,13 @@ public class PDFFunction extends PDFObject {
* @return the PDF string.
*/
public byte[] toPDF() {
- int vectorSize = 0;
- int numberOfFunctions = 0;
- int tempInt = 0;
- StringBuffer p = new StringBuffer(256);
- p.append("<< \n/FunctionType " + this.functionType + " \n");
-
- // FunctionType 0
- if (this.functionType == 0) {
- if (this.domain != null) {
- // DOMAIN
- p.append("/Domain [ ");
- vectorSize = this.domain.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(PDFNumber.doubleOut((Double)this.domain.get(tempInt))
- + " ");
- }
-
- p.append("] \n");
- } else {
- p.append("/Domain [ 0 1 ] \n");
- }
-
- // SIZE
- if (this.size != null) {
- p.append("/Size [ ");
- vectorSize = this.size.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(PDFNumber.doubleOut((Double)this.size.get(tempInt))
- + " ");
- }
- p.append("] \n");
- }
- // ENCODE
- if (this.encode != null) {
- p.append("/Encode [ ");
- vectorSize = this.encode.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(PDFNumber.doubleOut((Double)this.encode.get(tempInt))
- + " ");
- }
- p.append("] \n");
- } else {
- p.append("/Encode [ ");
- vectorSize = this.functions.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append("0 1 ");
- }
- p.append("] \n");
-
- }
-
- // BITSPERSAMPLE
- p.append("/BitsPerSample " + this.bitsPerSample);
-
- // ORDER (optional)
- if (this.order == 1 || this.order == 3) {
- p.append(" \n/Order " + this.order + " \n");
- }
-
- // RANGE
- if (this.range != null) {
- p.append("/Range [ ");
- vectorSize = this.range.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(PDFNumber.doubleOut((Double)this.range.get(tempInt))
- + " ");
- }
-
- p.append("] \n");
- }
-
- // DECODE
- if (this.decode != null) {
- p.append("/Decode [ ");
- vectorSize = this.decode.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(PDFNumber.doubleOut((Double)this.decode.get(tempInt))
- + " ");
- }
-
- p.append("] \n");
- }
-
- // LENGTH
- if (this.functionDataStream != null) {
- p.append("/Length " + (this.functionDataStream.length() + 1)
- + " \n");
- }
-
- // FILTER?
- if (this.filter != null) { // if there's a filter
- vectorSize = this.filter.size();
- p.append("/Filter ");
- if (vectorSize == 1) {
- p.append("/" + ((String)this.filter.get(0))
- + " \n");
- } else {
- p.append("[ ");
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append("/" + ((String)this.filter.get(0))
- + " ");
- }
- p.append("] \n");
- }
- }
- p.append(">>");
-
- // stream representing the function
- if (this.functionDataStream != null) {
- p.append("\nstream\n" + this.functionDataStream
- + "\nendstream");
- }
-
- // end of if FunctionType 0
-
- } else if (this.functionType == 2) {
- // DOMAIN
- if (this.domain != null) {
- p.append("/Domain [ ");
- vectorSize = this.domain.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(PDFNumber.doubleOut((Double)this.domain.get(tempInt))
- + " ");
- }
-
- p.append("] \n");
- } else {
- p.append("/Domain [ 0 1 ] \n");
- }
-
-
- // RANGE
- if (this.range != null) {
- p.append("/Range [ ");
- vectorSize = this.range.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(PDFNumber.doubleOut((Double)this.range.get(tempInt))
- + " ");
- }
-
- p.append("] \n");
- }
-
- // FunctionType, C0, C1, N are required in PDF
-
- // C0
- if (this.cZero != null) {
- p.append("/C0 [ ");
- vectorSize = this.cZero.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(PDFNumber.doubleOut((Double)this.cZero.get(tempInt))
- + " ");
- }
- p.append("] \n");
- }
-
- // C1
- if (this.cOne != null) {
- p.append("/C1 [ ");
- vectorSize = this.cOne.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(PDFNumber.doubleOut((Double)this.cOne.get(tempInt))
- + " ");
- }
- p.append("] \n");
- }
-
- // N: The interpolation Exponent
- p.append("/N "
- + PDFNumber.doubleOut(new Double(this.interpolationExponentN))
- + " \n");
-
- p.append(">>");
-
- } else if (this.functionType
- == 3) { // fix this up when my eyes uncross
- // DOMAIN
- if (this.domain != null) {
- p.append("/Domain [ ");
- vectorSize = this.domain.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(PDFNumber.doubleOut((Double)this.domain.get(tempInt))
- + " ");
- }
- p.append("] \n");
- } else {
- p.append("/Domain [ 0 1 ] \n");
- }
-
- // RANGE
- if (this.range != null) {
- p.append("/Range [ ");
- vectorSize = this.range.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(PDFNumber.doubleOut((Double)this.range.get(tempInt))
- + " ");
- }
-
- p.append("] \n");
- }
-
- // FUNCTIONS
- if (this.functions != null) {
- p.append("/Functions [ ");
- numberOfFunctions = this.functions.size();
- for (tempInt = 0; tempInt < numberOfFunctions; tempInt++) {
- p.append(((PDFFunction)this.functions.get(tempInt)).referencePDF()
- + " ");
-
- }
- p.append("] \n");
- }
-
-
- // ENCODE
- if (this.encode != null) {
- p.append("/Encode [ ");
- vectorSize = this.encode.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(PDFNumber.doubleOut((Double)this.encode.get(tempInt))
- + " ");
- }
-
- p.append("] \n");
- } else {
- p.append("/Encode [ ");
- vectorSize = this.functions.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append("0 1 ");
- }
- p.append("] \n");
-
- }
-
-
- // BOUNDS, required, but can be empty
- p.append("/Bounds [ ");
- if (this.bounds != null) {
-
- vectorSize = this.bounds.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(PDFNumber.doubleOut((Double)this.bounds.get(tempInt))
- + " ");
- }
-
- } else {
- if (this.functions != null) {
- // if there are n functions,
- // there must be n-1 bounds.
- // so let each function handle an equal portion
- // of the whole. e.g. if there are 4, then [ 0.25 0.25 0.25 ]
-
- String functionsFraction = PDFNumber.doubleOut(new Double(1.0
- / ((double)numberOfFunctions)));
-
- for (tempInt = 0; tempInt + 1 < numberOfFunctions;
- tempInt++) {
-
- p.append(functionsFraction + " ");
- }
- functionsFraction = null; // clean reference.
-
- }
-
- }
- p.append("]\n>>");
- } else if (this.functionType
- == 4) { // fix this up when my eyes uncross
- // DOMAIN
- if (this.domain != null) {
- p.append("/Domain [ ");
- vectorSize = this.domain.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(PDFNumber.doubleOut((Double)this.domain.get(tempInt))
- + " ");
- }
-
- p.append("] \n");
- } else {
- p.append("/Domain [ 0 1 ] \n");
- }
-
- // RANGE
- if (this.range != null) {
- p.append("/Range [ ");
- vectorSize = this.range.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(PDFNumber.doubleOut((Double)this.range.get(tempInt))
- + " ");
- }
-
- p.append("] \n");
- }
-
- // LENGTH
- if (this.functionDataStream != null) {
- p.append("/Length " + (this.functionDataStream.length() + 1)
- + " \n");
- }
-
- p.append(">>");
-
- // stream representing the function
- if (this.functionDataStream != null) {
- p.append("\nstream\n{ " + this.functionDataStream
- + " }\nendstream");
- }
-
-
- }
+ return toByteString();
+ }
- return encode(p.toString());
+ public byte[] toByteString() {
+ FunctionPattern pattern = new FunctionPattern(this);
+ return encode(pattern.toWriteableString());
}
/** {@inheritDoc} */
@@ -702,96 +246,155 @@ public class PDFFunction extends PDFObject {
return false;
}
PDFFunction func = (PDFFunction)obj;
- if (functionType != func.functionType) {
+ if (delegate.getFunctionType() != func.getFunctionType()) {
return false;
}
- if (bitsPerSample != func.bitsPerSample) {
+ if (delegate.getBitsPerSample() != func.getBitsPerSample()) {
return false;
}
- if (order != func.order) {
+ if (delegate.getOrder() != func.getOrder()) {
return false;
}
- if (interpolationExponentN != func.interpolationExponentN) {
+ if (delegate.getInterpolationExponentN() != func.getInterpolationExponentN()) {
return false;
}
- if (domain != null) {
- if (!domain.equals(func.domain)) {
+ if (delegate.getDomain() != null) {
+ if (!delegate.getDomain().equals(func.getDomain())) {
return false;
}
- } else if (func.domain != null) {
+ } else if (func.getDomain() != null) {
return false;
}
- if (range != null) {
- if (!range.equals(func.range)) {
+ if (delegate.getRange() != null) {
+ if (!delegate.getRange().equals(func.getRange())) {
return false;
}
- } else if (func.range != null) {
+ } else if (func.getRange() != null) {
return false;
}
- if (size != null) {
- if (!size.equals(func.size)) {
+ if (delegate.getSize() != null) {
+ if (!delegate.getSize().equals(func.getSize())) {
return false;
}
- } else if (func.size != null) {
+ } else if (func.getSize() != null) {
return false;
}
- if (encode != null) {
- if (!encode.equals(func.encode)) {
+ if (delegate.getEncode() != null) {
+ if (!delegate.getEncode().equals(func.getEncode())) {
return false;
}
- } else if (func.encode != null) {
+ } else if (func.getEncode() != null) {
return false;
}
- if (decode != null) {
- if (!decode.equals(func.decode)) {
+ if (delegate.getDecode() != null) {
+ if (!delegate.getDecode().equals(func.getDecode())) {
return false;
}
- } else if (func.decode != null) {
+ } else if (func.getDecode() != null) {
return false;
}
- if (functionDataStream != null) {
- if (!functionDataStream.equals(func.functionDataStream)) {
+ if (delegate.getDataStream() != null) {
+ if (!delegate.getDataStream().equals(func.getDataStream())) {
return false;
}
- } else if (func.functionDataStream != null) {
+ } else if (func.getDataStream() != null) {
return false;
}
- if (filter != null) {
- if (!filter.equals(func.filter)) {
+ if (delegate.getFilter() != null) {
+ if (!delegate.getFilter().equals(func.getFilter())) {
return false;
}
- } else if (func.filter != null) {
+ } else if (func.getFilter() != null) {
return false;
}
- if (cZero != null) {
- if (!cZero.equals(func.cZero)) {
+ if (delegate.getCZero() != null) {
+ if (!delegate.getCZero().equals(func.getCZero())) {
return false;
}
- } else if (func.cZero != null) {
+ } else if (func.getCZero() != null) {
return false;
}
- if (cOne != null) {
- if (!cOne.equals(func.cOne)) {
+ if (delegate.getCOne() != null) {
+ if (!delegate.getCOne().equals(func.getCOne())) {
return false;
}
- } else if (func.cOne != null) {
+ } else if (func.getCOne() != null) {
return false;
}
- if (functions != null) {
- if (!functions.equals(func.functions)) {
+ if (delegate.getFunctions() != null) {
+ if (!delegate.getFunctions().equals(func.getFunctions())) {
return false;
}
- } else if (func.functions != null) {
+ } else if (func.getFunctions() != null) {
return false;
}
- if (bounds != null) {
- if (!bounds.equals(func.bounds)) {
+ if (delegate.getBounds() != null) {
+ if (!delegate.getBounds().equals(func.getBounds())) {
return false;
}
- } else if (func.bounds != null) {
+ } else if (func.getBounds() != null) {
return false;
}
return true;
}
+ public int getFunctionType() {
+ return delegate.getFunctionType();
+ }
+
+ public List<Double> getBounds() {
+ return delegate.getBounds();
+ }
+
+ public List<Double> getDomain() {
+ return delegate.getDomain();
+ }
+
+ public List<Double> getSize() {
+ return delegate.getSize();
+ }
+
+ public List<String> getFilter() {
+ return delegate.getFilter();
+ }
+
+ public List<Double> getEncode() {
+ return delegate.getEncode();
+ }
+
+ public List<Function> getFunctions() {
+ return delegate.getFunctions();
+ }
+
+ public int getBitsPerSample() {
+ return delegate.getBitsPerSample();
+ }
+
+ public double getInterpolationExponentN() {
+ return delegate.getInterpolationExponentN();
+ }
+
+ public int getOrder() {
+ return delegate.getOrder();
+ }
+
+ public List<Double> getRange() {
+ return delegate.getRange();
+ }
+
+ public List<Double> getDecode() {
+ return delegate.getDecode();
+ }
+
+ public StringBuffer getDataStream() {
+ return delegate.getDataStream();
+ }
+
+ public List<Double> getCZero() {
+ return delegate.getCZero();
+ }
+
+ public List<Double> getCOne() {
+ return delegate.getCOne();
+ }
}
diff --git a/src/java/org/apache/fop/pdf/PDFIdentifiedDictionary.java b/src/java/org/apache/fop/pdf/PDFIdentifiedDictionary.java
new file mode 100644
index 000000000..c2d033aec
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFIdentifiedDictionary.java
@@ -0,0 +1,42 @@
+/*
+ * 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;
+
+/**
+ * Identified Dictionary.
+ */
+public class PDFIdentifiedDictionary extends PDFDictionary {
+
+ private final String id;
+
+ public PDFIdentifiedDictionary(String id) {
+ this.id = id;
+ }
+
+ public String getId() {
+ return this.id;
+ }
+
+ public boolean hasId(String id) {
+ return (this.id != null) && (id != null) && this.id.equals(id);
+ }
+
+}
+
diff --git a/src/java/org/apache/fop/pdf/PDFLayer.java b/src/java/org/apache/fop/pdf/PDFLayer.java
new file mode 100644
index 000000000..f8f434e87
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFLayer.java
@@ -0,0 +1,86 @@
+/*
+ * 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;
+
+/**
+ * Optional Content Group Dictionary, which we will call a 'layer'.
+ */
+public class PDFLayer extends PDFIdentifiedDictionary {
+
+ public abstract static class Resolver {
+ private boolean resolved;
+ private PDFLayer layer;
+ private Object extension;
+ public Resolver(PDFLayer layer, Object extension) {
+ this.layer = layer;
+ this.extension = extension;
+ }
+ public PDFLayer getLayer() {
+ return layer;
+ }
+ public Object getExtension() {
+ return extension;
+ }
+ public void resolve() {
+ if (!resolved) {
+ performResolution();
+ resolved = true;
+ }
+ }
+ protected void performResolution() {
+ }
+ }
+
+ private Resolver resolver;
+
+ public PDFLayer(String id) {
+ super(id);
+ put("Type", new PDFName("OCG"));
+ }
+
+ @Override
+ public int output(OutputStream stream) throws IOException {
+ if (resolver != null) {
+ resolver.resolve();
+ }
+ return super.output(stream);
+ }
+
+ public void setResolver(Resolver resolver) {
+ this.resolver = resolver;
+ }
+
+ public void populate(Object name, Object intent, Object usage) {
+ if (name != null) {
+ put("Name", name);
+ }
+ if (intent != null) {
+ put("Intent", intent);
+ }
+ if (usage != null) {
+ put("Usage", usage);
+ }
+ }
+
+}
+
diff --git a/src/java/org/apache/fop/pdf/PDFNavigator.java b/src/java/org/apache/fop/pdf/PDFNavigator.java
new file mode 100644
index 000000000..fdb97469b
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFNavigator.java
@@ -0,0 +1,93 @@
+/*
+ * 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;
+
+/**
+ * Navigation Node Dictionary, which we call a 'navigator'.
+ * This class is used to for sub-page navigation.
+ */
+public class PDFNavigator extends PDFIdentifiedDictionary {
+
+ public abstract static class Resolver {
+ private boolean resolved;
+ private PDFNavigator navigator;
+ private Object extension;
+ public Resolver(PDFNavigator navigator, Object extension) {
+ this.navigator = navigator;
+ this.extension = extension;
+ }
+ public PDFNavigator getNavigator() {
+ return navigator;
+ }
+ public Object getExtension() {
+ return extension;
+ }
+ public void resolve() {
+ if (!resolved) {
+ performResolution();
+ resolved = true;
+ }
+ }
+ protected void performResolution() {
+ }
+ }
+
+ private Resolver resolver;
+
+ public PDFNavigator(String id) {
+ super(id);
+ put("Type", new PDFName("NavNode"));
+ }
+
+ @Override
+ public int output(OutputStream stream) throws IOException {
+ if (resolver != null) {
+ resolver.resolve();
+ }
+ return super.output(stream);
+ }
+
+ public void setResolver(Resolver resolver) {
+ this.resolver = resolver;
+ }
+
+ public void populate(Object nextAction, Object nextNode, Object prevAction, Object prevNode, Object duration) {
+ if (nextAction != null) {
+ put("NA", nextAction);
+ }
+ if (nextNode != null) {
+ put("Next", nextNode);
+ }
+ if (prevAction != null) {
+ put("PA", prevAction);
+ }
+ if (prevNode != null) {
+ put("Prev", prevNode);
+ }
+ if (duration != null) {
+ put("Dur", duration);
+ }
+ }
+
+}
+
diff --git a/src/java/org/apache/fop/pdf/PDFNavigatorAction.java b/src/java/org/apache/fop/pdf/PDFNavigatorAction.java
new file mode 100644
index 000000000..ba32269b5
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFNavigatorAction.java
@@ -0,0 +1,28 @@
+/*
+ * 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;
+
+public abstract class PDFNavigatorAction extends PDFIdentifiedDictionary {
+
+ protected PDFNavigatorAction(String id) {
+ super(id);
+ }
+
+}
diff --git a/src/java/org/apache/fop/pdf/PDFNumber.java b/src/java/org/apache/fop/pdf/PDFNumber.java
index 1c31f8e9d..754194886 100644
--- a/src/java/org/apache/fop/pdf/PDFNumber.java
+++ b/src/java/org/apache/fop/pdf/PDFNumber.java
@@ -29,6 +29,14 @@ public class PDFNumber extends PDFObject {
private Number number;
+ public PDFNumber() {
+ this.number = Integer.valueOf(0);
+ }
+
+ public PDFNumber(Number number) {
+ this.number = number;
+ }
+
/**
* Returns the number.
* @return the number
diff --git a/src/java/org/apache/fop/pdf/PDFPaintingState.java b/src/java/org/apache/fop/pdf/PDFPaintingState.java
index 29d022f61..f6528a30c 100644
--- a/src/java/org/apache/fop/pdf/PDFPaintingState.java
+++ b/src/java/org/apache/fop/pdf/PDFPaintingState.java
@@ -44,8 +44,6 @@ import org.apache.fop.util.AbstractPaintingState;
* previous state then the necessary values can be overridden.
* The current transform behaves differently to other values as the
* matrix is combined with the current resolved value.
- * It is impossible to optimise the result without analysing the all
- * the possible combinations after completing.
*/
public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState {
@@ -187,6 +185,36 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState
return newState;
}
+ public void setLayer(String layer) {
+ getPDFData().setLayer(layer);
+ }
+
+ public String getLayer() {
+ return getPDFData().getLayer();
+ }
+
+ public boolean getLayerChanged() {
+ String layerCurrent = getLayer();
+ if (layerCurrent == null) {
+ return false;
+ } else if (getStateStack().isEmpty()) {
+ return true;
+ } else {
+ for (int i = getStackLevel(); i > 0; --i) {
+ String layerPrev = ((PDFData) getStateStack().get(i - 1)).getLayer();
+ if (layerPrev == null) {
+ continue;
+ } else {
+ // Both current and prior are set, so, if same, then we know layer
+ // didn't change (and can stop search), otherwise it did change.
+ return !layerCurrent.equals(layerPrev);
+ }
+ }
+ // Current layer set, but no prior saved layer set, so must have changed.
+ return true;
+ }
+ }
+
/** {@inheritDoc} */
@Override
protected AbstractData instantiateData() {
@@ -209,7 +237,7 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState
AbstractData data = getData();
AbstractData copy = (AbstractData)data.clone();
data.clearTransform();
- getStateStack().add(copy);
+ getStateStack().push(copy);
}
private PDFData getPDFData() {
diff --git a/src/java/org/apache/fop/pdf/PDFPattern.java b/src/java/org/apache/fop/pdf/PDFPattern.java
index 46a6a7378..df4b0233d 100644
--- a/src/java/org/apache/fop/pdf/PDFPattern.java
+++ b/src/java/org/apache/fop/pdf/PDFPattern.java
@@ -23,6 +23,9 @@ import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
+import org.apache.fop.render.shading.Pattern;
+import org.apache.fop.render.shading.Shading;
+
/**
* class representing a PDF Function.
*
@@ -33,7 +36,7 @@ import java.util.List;
*
* All PDF Functions have a FunctionType (0,2,3, or 4), a Domain, and a Range.
*/
-public class PDFPattern extends PDFPathPaint {
+public class PDFPattern extends PDFPathPaint implements Pattern {
/**
* The resources associated with this pattern
@@ -146,13 +149,14 @@ public class PDFPattern extends PDFPathPaint {
* @param theExtGState optional: the extended graphics state, if used.
* @param theMatrix Optional:List of Doubles that specify the matrix.
*/
- public PDFPattern(int thePatternType, PDFShading theShading,
+ public PDFPattern(int thePatternType, Shading theShading,
List theXUID, StringBuffer theExtGState,
List theMatrix) {
super();
this.patternType = 2; // thePatternType;
- this.shading = theShading;
+ assert theShading instanceof PDFShading;
+ this.shading = (PDFShading)theShading;
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.
@@ -259,7 +263,7 @@ public class PDFPattern extends PDFPathPaint {
vectorSize = this.xUID.size();
p.append("/XUID [ ");
for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(((Integer)this.xUID.get(tempInt)) + " ");
+ p.append((this.xUID.get(tempInt)) + " ");
}
p.append("] \n");
}
@@ -269,13 +273,14 @@ public class PDFPattern extends PDFPathPaint {
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() + 1)
- + " \n");
+ p.append("/Length " + encodedStream.getSize() + " \n");
}
} else {
@@ -289,7 +294,7 @@ public class PDFPattern extends PDFPathPaint {
vectorSize = this.xUID.size();
p.append("/XUID [ ");
for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(((Integer)this.xUID.get(tempInt)) + " ");
+ p.append((this.xUID.get(tempInt)) + " ");
}
p.append("] \n");
}
diff --git a/src/java/org/apache/fop/pdf/PDFResources.java b/src/java/org/apache/fop/pdf/PDFResources.java
index cded7c00a..6d09d5738 100644
--- a/src/java/org/apache/fop/pdf/PDFResources.java
+++ b/src/java/org/apache/fop/pdf/PDFResources.java
@@ -37,8 +37,8 @@ import org.apache.fop.fonts.base14.ZapfDingbats;
/**
* Class representing a /Resources object.
*
- * /Resources object contain a list of references to the fonts for the
- * document
+ * /Resources object contain a list of references to the fonts, patterns,
+ * shadings, etc., for the document.
*/
public class PDFResources extends PDFDictionary {
@@ -73,6 +73,9 @@ public class PDFResources extends PDFDictionary {
/** Map of ICC color spaces (key: ICC profile description) */
protected Map<String, PDFICCBasedColorSpace> iccColorSpaces = new LinkedHashMap<String, PDFICCBasedColorSpace>();
+ /** Named properties */
+ protected Map<String, PDFReference> properties = new LinkedHashMap<String, PDFReference>();
+
/**
* create a /Resources object.
*
@@ -191,6 +194,25 @@ public class PDFResources extends PDFDictionary {
return cs;
}
+ /**
+ * Add a named property.
+ *
+ * @param name name of property
+ * @param property reference to property value
+ */
+ public void addProperty(String name, PDFReference property) {
+ this.properties.put(name, property);
+ }
+
+ /**
+ * Get a named property.
+ *
+ * @param name name of property
+ */
+ public PDFReference getProperty(String name) {
+ return this.properties.get(name);
+ }
+
@Override
public int output(OutputStream stream) throws IOException {
populateDictionary();
@@ -253,6 +275,14 @@ public class PDFResources extends PDFDictionary {
}
put("ColorSpace", dict);
}
+
+ if (!properties.isEmpty()) {
+ PDFDictionary dict = new PDFDictionary(this);
+ for (String name : properties.keySet()) {
+ dict.put(name, properties.get(name));
+ }
+ put("Properties", dict);
+ }
}
}
diff --git a/src/java/org/apache/fop/pdf/PDFSetOCGStateAction.java b/src/java/org/apache/fop/pdf/PDFSetOCGStateAction.java
new file mode 100644
index 000000000..a47c5cd59
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFSetOCGStateAction.java
@@ -0,0 +1,82 @@
+/*
+ * 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;
+
+public class PDFSetOCGStateAction extends PDFNavigatorAction {
+
+ public abstract static class Resolver {
+ private boolean resolved;
+ private PDFSetOCGStateAction action;
+ private Object extension;
+ public Resolver(PDFSetOCGStateAction action, Object extension) {
+ this.action = action;
+ this.extension = extension;
+ }
+ public PDFSetOCGStateAction getAction() {
+ return action;
+ }
+ public Object getExtension() {
+ return extension;
+ }
+ public void resolve() {
+ if (!resolved) {
+ performResolution();
+ resolved = true;
+ }
+ }
+ protected void performResolution() {
+ }
+ }
+
+ private Resolver resolver;
+
+ public PDFSetOCGStateAction(String id) {
+ super(id);
+ put("Type", new PDFName("Action"));
+ put("S", new PDFName("SetOCGState"));
+ }
+
+ @Override
+ public int output(OutputStream stream) throws IOException {
+ if (resolver != null) {
+ resolver.resolve();
+ }
+ return super.output(stream);
+ }
+
+ public void setResolver(Resolver resolver) {
+ this.resolver = resolver;
+ }
+
+ public void populate(Object state, Object preserveRB, Object nextAction) {
+ if (state != null) {
+ put("State", state);
+ }
+ if (preserveRB != null) {
+ put("PreserveRB", preserveRB);
+ }
+ if (nextAction != null) {
+ put("Next", nextAction);
+ }
+ }
+}
diff --git a/src/java/org/apache/fop/pdf/PDFShading.java b/src/java/org/apache/fop/pdf/PDFShading.java
index 62012b9b2..3f7b2b4b0 100644
--- a/src/java/org/apache/fop/pdf/PDFShading.java
+++ b/src/java/org/apache/fop/pdf/PDFShading.java
@@ -22,6 +22,10 @@ package org.apache.fop.pdf;
// Java...
import java.util.List;
+import org.apache.fop.render.shading.Function;
+import org.apache.fop.render.shading.Shading;
+import org.apache.fop.render.shading.ShadingPattern;
+
/**
* class representing a PDF Smooth Shading object.
*
@@ -32,7 +36,7 @@ import java.util.List;
*
* All PDF Functions have a shadingType (0,2,3, or 4), a Domain, and a Range.
*/
-public class PDFShading extends PDFObject {
+public class PDFShading extends PDFObject implements Shading {
// Guts common to all function types
/**
@@ -205,7 +209,7 @@ public class PDFShading extends PDFObject {
public PDFShading(int theShadingType, PDFDeviceColorSpace theColorSpace,
List theBackground, List theBBox,
boolean theAntiAlias, List theCoords,
- List theDomain, PDFFunction theFunction,
+ List theDomain, Function theFunction,
List theExtend) {
super();
this.shadingType = theShadingType; // 2 or 3
@@ -216,7 +220,8 @@ public class PDFShading extends PDFObject {
this.coords = theCoords;
this.domain = theDomain;
- this.function = theFunction;
+ assert theFunction instanceof PDFFunction;
+ this.function = (PDFFunction)theFunction;
this.extend = theExtend;
}
@@ -335,197 +340,8 @@ public class PDFShading extends PDFObject {
* @return the PDF string.
*/
public String toPDFString() {
- int vectorSize;
- int tempInt;
- StringBuffer p = new StringBuffer(128);
- p.append("<<\n/ShadingType " + this.shadingType + " \n");
- if (this.colorSpace != null) {
- p.append("/ColorSpace /"
- + this.colorSpace.getName() + " \n");
- }
-
- if (this.background != null) {
- p.append("/Background [ ");
- vectorSize = this.background.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(PDFNumber.doubleOut((Double)this.background.get(tempInt))
- + " ");
- }
- p.append("] \n");
- }
-
- if (this.bBox
- != null) { // I've never seen an example, so I guess this is right.
- p.append("/BBox [ ");
- vectorSize = this.bBox.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(PDFNumber.doubleOut((Double)this.bBox.get(tempInt))
- + " ");
- }
- p.append("] \n");
- }
-
- if (this.antiAlias) {
- p.append("/AntiAlias " + this.antiAlias + " \n");
- }
-
- // Here's where we differentiate based on what type it is.
- if (this.shadingType == 1) { // function based shading
- if (this.domain != null) {
- p.append("/Domain [ ");
- vectorSize = this.domain.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(PDFNumber.doubleOut((Double)this.domain.get(tempInt))
- + " ");
- }
- p.append("] \n");
- } else {
- p.append("/Domain [ 0 1 ] \n");
- }
-
- if (this.matrix != null) {
- p.append("/Matrix [ ");
- vectorSize = this.matrix.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(PDFNumber.doubleOut((Double)this.matrix.get(tempInt))
- + " ");
- }
- p.append("] \n");
- }
-
- if (this.function != null) {
- p.append("/Function ");
- p.append(this.function.referencePDF() + " \n");
- }
- } else if ((this.shadingType == 2)
- || (this.shadingType
- == 3)) { // 2 is axial shading (linear gradient)
- // 3 is radial shading (circular gradient)
- if (this.coords != null) {
- p.append("/Coords [ ");
- vectorSize = this.coords.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(PDFNumber.doubleOut((Double)this.coords.get(tempInt))
- + " ");
- }
- p.append("] \n");
- }
-
- // DOMAIN
- if (this.domain != null) {
- p.append("/Domain [ ");
- vectorSize = this.domain.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(PDFNumber.doubleOut((Double)this.domain.get(tempInt))
- + " ");
- }
- p.append("] \n");
- } else {
- p.append("/Domain [ 0 1 ] \n");
- }
-
- if (this.extend != null) {
- p.append("/Extend [ ");
- vectorSize = this.extend.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(((Boolean)this.extend.get(tempInt)) + " ");
- }
-
- p.append("] \n");
- } else {
- p.append("/Extend [ true true ] \n");
- }
-
-
- if (this.function != null) {
- p.append("/Function ");
- p.append(this.function.referencePDF() + " \n");
- }
-
-
- } else if ((this.shadingType == 4) || (this.shadingType == 6)
- || (this.shadingType
- == 7)) { // 4:Free-form Gouraud-shaded triangle meshes
- // 6:coons patch meshes
- // 7://tensor product patch meshes (which no one ever uses)
- if (this.bitsPerCoordinate > 0) {
- p.append("/BitsPerCoordinate " + this.bitsPerCoordinate
- + " \n");
- } else {
- p.append("/BitsPerCoordinate 1 \n");
- }
-
- if (this.bitsPerComponent > 0) {
- p.append("/BitsPerComponent " + this.bitsPerComponent
- + " \n");
- } else {
- p.append("/BitsPerComponent 1 \n");
- }
-
- if (this.bitsPerFlag > 0) {
- p.append("/BitsPerFlag " + this.bitsPerFlag + " \n");
- } else {
- p.append("/BitsPerFlag 2 \n");
- }
-
- if (this.decode != null) {
- p.append("/Decode [ ");
- vectorSize = this.decode.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(((Boolean)this.decode.get(tempInt)) + " ");
- }
-
- p.append("] \n");
- }
-
- if (this.function != null) {
- p.append("/Function ");
- p.append(this.function.referencePDF() + " \n");
- }
-
- } else if (this.shadingType
- == 5) { // Lattice Free form gouraud-shaded triangle mesh
-
- if (this.bitsPerCoordinate > 0) {
- p.append("/BitsPerCoordinate " + this.bitsPerCoordinate
- + " \n");
- } else {
- p.append("/BitsPerCoordinate 1 \n");
- }
-
- if (this.bitsPerComponent > 0) {
- p.append("/BitsPerComponent " + this.bitsPerComponent
- + " \n");
- } else {
- p.append("/BitsPerComponent 1 \n");
- }
-
- if (this.decode != null) {
- p.append("/Decode [ ");
- vectorSize = this.decode.size();
- for (tempInt = 0; tempInt < vectorSize; tempInt++) {
- p.append(((Boolean)this.decode.get(tempInt)) + " ");
- }
-
- p.append("] \n");
- }
-
- if (this.function != null) {
- p.append("/Function ");
- p.append(this.function.referencePDF() + " \n");
- }
-
- if (this.verticesPerRow > 0) {
- p.append("/VerticesPerRow " + this.verticesPerRow + " \n");
- } else {
- p.append("/VerticesPerRow 2 \n");
- }
-
- }
-
- p.append(">>");
-
- return (p.toString());
+ ShadingPattern pattern = new ShadingPattern(this);
+ return pattern.toString(colorSpace, shadingType, background, bBox, antiAlias);
}
/** {@inheritDoc} */
@@ -623,4 +439,173 @@ public class PDFShading extends PDFObject {
}
return true;
}
+
+ /**
+ * A method to write a type 1 shading object
+ * @param p The StringBuffer to write the shading object
+ * @return Returns the StringBuffer to which the shading object was written
+ */
+ public StringBuffer handleShadingType1(StringBuffer p) {
+ if (this.domain != null) {
+ p.append("/Domain [ ");
+ for (int domainIndex = 0; domainIndex < domain.size(); domainIndex++) {
+ p.append(PDFNumber.doubleOut((Double)this.domain.get(domainIndex))
+ + " ");
+ }
+ p.append("] \n");
+ } else {
+ p.append("/Domain [ 0 1 ] \n");
+ }
+
+ if (this.matrix != null) {
+ p.append("/Matrix [ ");
+ for (int matrixIndex = 0; matrixIndex < matrix.size(); matrixIndex++) {
+ p.append(PDFNumber.doubleOut((Double)this.matrix.get(matrixIndex))
+ + " ");
+ }
+ p.append("] \n");
+ }
+
+ if (this.function != null) {
+ p.append("/Function ");
+ p.append(this.function.referencePDF() + " \n");
+ }
+ return p;
+ }
+
+ /**
+ * A method to write a type 2 or 3 shading object
+ * @param p The StringBuffer to write the shading object
+ * @return Returns the StringBuffer to which the shading object was written
+ */
+ public StringBuffer handleShadingType2or3(StringBuffer p) {
+ // 3 is radial shading (circular gradient)
+ if (this.coords != null) {
+ p.append("/Coords [ ");
+ for (int coordIndex = 0; coordIndex < coords.size(); coordIndex++) {
+ p.append(PDFNumber.doubleOut((Double)this.coords.get(coordIndex))
+ + " ");
+ }
+ p.append("] \n");
+ }
+
+ // DOMAIN
+ if (this.domain != null) {
+ p.append("/Domain [ ");
+ for (int domainIndex = 0; domainIndex < domain.size(); domainIndex++) {
+ p.append(PDFNumber.doubleOut((Double)this.domain.get(domainIndex))
+ + " ");
+ }
+ p.append("] \n");
+ } else {
+ p.append("/Domain [ 0 1 ] \n");
+ }
+
+ if (this.extend != null) {
+ p.append("/Extend [ ");
+ for (int extendIndex = 0; extendIndex < extend.size(); extendIndex++) {
+ p.append((this.extend.get(extendIndex)) + " ");
+ }
+
+ p.append("] \n");
+ } else {
+ p.append("/Extend [ true true ] \n");
+ }
+
+
+ if (this.function != null) {
+ p.append("/Function ");
+ p.append(this.function.referencePDF() + " \n");
+ }
+
+ return p;
+ }
+
+ /**
+ * A method to write a type 4, 6 or 7 shading object
+ * @param p The StringBuffer to write the shading object
+ * @return Returns the StringBuffer to which the shading object was written
+ */
+ public StringBuffer handleShadingType4or6or7(StringBuffer p) {
+ // 6:coons patch meshes
+ // 7://tensor product patch meshes (which no one ever uses)
+ if (this.bitsPerCoordinate > 0) {
+ p.append("/BitsPerCoordinate " + this.bitsPerCoordinate
+ + " \n");
+ } else {
+ p.append("/BitsPerCoordinate 1 \n");
+ }
+
+ if (this.bitsPerComponent > 0) {
+ p.append("/BitsPerComponent " + this.bitsPerComponent
+ + " \n");
+ } else {
+ p.append("/BitsPerComponent 1 \n");
+ }
+
+ if (this.bitsPerFlag > 0) {
+ p.append("/BitsPerFlag " + this.bitsPerFlag + " \n");
+ } else {
+ p.append("/BitsPerFlag 2 \n");
+ }
+
+ if (this.decode != null) {
+ p.append("/Decode [ ");
+ for (int decodeIndex = 0; decodeIndex < decode.size(); decodeIndex++) {
+ p.append((this.decode.get(decodeIndex)) + " ");
+ }
+
+ p.append("] \n");
+ }
+
+ if (this.function != null) {
+ p.append("/Function ");
+ p.append(this.function.referencePDF() + " \n");
+ }
+
+ return p;
+ }
+
+ /**
+ * A method to write a type 5 shading object
+ * @param p The StringBuffer to write the shading object
+ * @return Returns the StringBuffer to which the shading object was written
+ */
+ public StringBuffer handleShadingType5(StringBuffer p) {
+ if (this.bitsPerCoordinate > 0) {
+ p.append("/BitsPerCoordinate " + this.bitsPerCoordinate
+ + " \n");
+ } else {
+ p.append("/BitsPerCoordinate 1 \n");
+ }
+
+ if (this.bitsPerComponent > 0) {
+ p.append("/BitsPerComponent " + this.bitsPerComponent
+ + " \n");
+ } else {
+ p.append("/BitsPerComponent 1 \n");
+ }
+
+ if (this.decode != null) {
+ p.append("/Decode [ ");
+ for (int decodeIndex = 0; decodeIndex < decode.size(); decodeIndex++) {
+ p.append((this.decode.get(decodeIndex)) + " ");
+ }
+
+ p.append("] \n");
+ }
+
+ if (this.function != null) {
+ p.append("/Function ");
+ p.append(this.function.referencePDF() + " \n");
+ }
+
+ if (this.verticesPerRow > 0) {
+ p.append("/VerticesPerRow " + this.verticesPerRow + " \n");
+ } else {
+ p.append("/VerticesPerRow 2 \n");
+ }
+
+ return p;
+ }
}
diff --git a/src/java/org/apache/fop/pdf/PDFTransitionAction.java b/src/java/org/apache/fop/pdf/PDFTransitionAction.java
new file mode 100644
index 000000000..01f8fcf21
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFTransitionAction.java
@@ -0,0 +1,79 @@
+/*
+ * 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;
+
+public class PDFTransitionAction extends PDFNavigatorAction {
+
+ public abstract static class Resolver {
+ private boolean resolved;
+ private PDFTransitionAction action;
+ private Object extension;
+ public Resolver(PDFTransitionAction action, Object extension) {
+ this.action = action;
+ this.extension = extension;
+ }
+ public PDFTransitionAction getAction() {
+ return action;
+ }
+ public Object getExtension() {
+ return extension;
+ }
+ public void resolve() {
+ if (!resolved) {
+ performResolution();
+ resolved = true;
+ }
+ }
+ protected void performResolution() {
+ }
+ }
+
+ private Resolver resolver;
+
+ public PDFTransitionAction(String id) {
+ super(id);
+ put("Type", new PDFName("Action"));
+ put("S", new PDFName("Trans"));
+ }
+
+ @Override
+ public int output(OutputStream stream) throws IOException {
+ if (resolver != null) {
+ resolver.resolve();
+ }
+ return super.output(stream);
+ }
+
+ public void setResolver(Resolver resolver) {
+ this.resolver = resolver;
+ }
+
+ public void populate(Object transition, Object nextAction) {
+ if (transition != null) {
+ put("Trans", transition);
+ }
+ if (nextAction != null) {
+ put("Next", nextAction);
+ }
+ }
+}