From 0c68e84d467c056958d0bdc8a1220a3d789699cd Mon Sep 17 00:00:00 2001 From: Jordan Naftolin Date: Wed, 21 Jun 2000 01:40:56 +0000 Subject: [PATCH] Added internal-link functionality git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@193417 13f79535-47bb-0310-9956-ffa450edef68 --- src/org/apache/fop/layout/LinkSet.java | 19 +- src/org/apache/fop/layout/Page.java | 10 + src/org/apache/fop/pdf/PDFDocument.java | 1777 ++++++++++++----------- 3 files changed, 931 insertions(+), 875 deletions(-) diff --git a/src/org/apache/fop/layout/LinkSet.java b/src/org/apache/fop/layout/LinkSet.java index 32172bc7d..67155d0f0 100644 --- a/src/org/apache/fop/layout/LinkSet.java +++ b/src/org/apache/fop/layout/LinkSet.java @@ -75,7 +75,7 @@ import org.apache.fop.fo.properties.TextAlignLast; // for enumerated public class LinkSet { /** the destination of the links */ - String externalDestination; + String destination; /** the set of rectangles */ Vector rects = new Vector(); @@ -89,14 +89,21 @@ public class LinkSet { protected int startIndent; protected int endIndent; + private int linkType; + private Area area; + public final static int + INTERNAL = 0, // represents internal link + EXTERNAL = 1; // represents external link + // property required for alignment adjustments int contentRectangleWidth = 0; - public LinkSet(String externalDest, Area area) { - this.externalDestination = externalDest; + public LinkSet(String destination, Area area, int linkType) { + this.destination = destination; this.area = area; + this.linkType = linkType; } public void addRect(Rectangle r, LineArea lineArea) { @@ -170,7 +177,7 @@ public class LinkSet { } public String getDest() { - return this.externalDestination; + return this.destination; } public Vector getRects() { @@ -188,4 +195,8 @@ public class LinkSet { public Area getArea() { return area; } + + public int getLinkType(){ + return linkType; + } } diff --git a/src/org/apache/fop/layout/Page.java b/src/org/apache/fop/layout/Page.java index 18db9fa64..304a1b409 100644 --- a/src/org/apache/fop/layout/Page.java +++ b/src/org/apache/fop/layout/Page.java @@ -75,6 +75,8 @@ public class Page { protected Vector linkSets = new Vector(); + private Vector idList = new Vector(); + Page(AreaTree areaTree, int height, int width) { this.areaTree = areaTree; this.height = height; @@ -153,4 +155,12 @@ public class Page { public boolean hasLinks() { return (!this.linkSets.isEmpty()); } + + public void addToIDList(String id){ + idList.addElement(id); + } + + public Vector getIDList(){ + return idList; + } } diff --git a/src/org/apache/fop/pdf/PDFDocument.java b/src/org/apache/fop/pdf/PDFDocument.java index 72710eeb2..bf577d966 100644 --- a/src/org/apache/fop/pdf/PDFDocument.java +++ b/src/org/apache/fop/pdf/PDFDocument.java @@ -1,35 +1,35 @@ /*-- $Id$ -- ============================================================================ - The Apache Software License, Version 1.1 + The Apache Software License, Version 1.1 ============================================================================ - Copyright (C) 1999 The Apache Software Foundation. All rights reserved. + Copyright (C) 1999 The Apache Software Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modifica- tion, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. + this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. 3. The end-user documentation included with the redistribution, if any, must - include the following acknowledgment: "This product includes software - developed by the Apache Software Foundation (http://www.apache.org/)." - Alternately, this acknowledgment may appear in the software itself, if - and wherever such third-party acknowledgments normally appear. + include the following acknowledgment: "This product includes software + developed by the Apache Software Foundation (http://www.apache.org/)." + Alternately, this acknowledgment may appear in the software itself, if + and wherever such third-party acknowledgments normally appear. 4. The names "FOP" and "Apache Software Foundation" must not be used to - endorse or promote products derived from this software without prior - written permission. For written permission, please contact - apache@apache.org. + endorse or promote products derived from this software without prior + written permission. For written permission, please contact + apache@apache.org. 5. Products derived from this software may not be called "Apache", nor may - "Apache" appear in their name, without prior written permission of the - Apache Software Foundation. + "Apache" appear in their name, without prior written permission of the + Apache Software Foundation. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND @@ -57,15 +57,19 @@ package org.apache.fop.pdf; // referenced and I'd rather not do it import org.apache.fop.image.FopImage; +import org.apache.fop.layout.LinkSet; import org.apache.fop.datatypes.ColorSpace; +import org.apache.fop.datatypes.IDReferences; +import org.apache.fop.layout.Page; // Java import java.io.IOException; import java.io.PrintWriter; import java.util.Vector; import java.util.Hashtable; +import java.util.Enumeration; import java.awt.Rectangle; - + /** * class representing a PDF document. * @@ -81,870 +85,901 @@ import java.awt.Rectangle; */ public class PDFDocument { - /** the version of PDF supported */ - protected static final String pdfVersion = "1.3"; - - /** the current character position */ - protected int position = 0; - - /** the character position of each object */ - protected Vector location = new Vector(); - - /** the counter for object numbering */ - protected int objectcount = 0; - - /** the objects themselves */ - protected Vector objects = new Vector(); - - /** character position of xref table */ - protected int xref; - - /** the /Root object */ - protected PDFRoot root; - - /** the /Info object */ - protected PDFInfo info; - - /** the /Resources object */ - protected PDFResources resources; - - /** the colorspace (0=RGB, 1=CMYK) **/ - //protected int colorspace = 0; - protected ColorSpace colorspace = new ColorSpace(ColorSpace.DEVICE_RGB); - - /** the counter for Pattern name numbering (e.g. 'Pattern1')*/ - protected int patternCount = 0; - - /** the counter for Shading name numbering */ - protected int shadingCount = 0; - - /** the counter for XObject numbering */ - protected int xObjectCount = 0; - - /** the XObjects */ - protected Vector xObjects = new Vector(); - - /** the XObjects Map. - Should be modified (works only for image subtype) */ - protected Hashtable xObjectsMap = new Hashtable(); - - /** - * creates an empty PDF document - */ - public PDFDocument() { - - /* create the /Root, /Info and /Resources objects */ - this.root = makeRoot(); - this.info = makeInfo(); - this.resources = makeResources(); - } - - /** - * set the producer of the document - * - * @param producer string indicating application producing the PDF - */ - public void setProducer(String producer) { - this.info.setProducer(producer); - } - - /** - * make /Root object as next object - * - * @return the created /Root object - */ - protected PDFRoot makeRoot() { - - /* create a PDFRoot with the next object number and add to - list of objects */ - PDFRoot pdfRoot = new PDFRoot(++this.objectcount); - this.objects.addElement(pdfRoot); - - /* create a new /Pages object to be root of Pages hierarchy - and add to list of objects */ - PDFPages rootPages = new PDFPages(++this.objectcount); - this.objects.addElement(rootPages); - - /* inform the /Root object of the /Pages root */ - pdfRoot.setRootPages(rootPages); - return pdfRoot; - } - - /** - * make an /Info object - * - * @param producer string indicating application producing the PDF - * @return the created /Info object - */ - protected PDFInfo makeInfo() { - - /* create a PDFInfo with the next object number and add to - list of objects */ - PDFInfo pdfInfo = new PDFInfo(++this.objectcount); - this.objects.addElement(pdfInfo); - return pdfInfo; - } - - /** - * make a /Resources object - * - * @return the created /Resources object - */ - private PDFResources makeResources() { - - /* create a PDFResources with the next object number and add - to list of objects */ - PDFResources pdfResources = new PDFResources(++this.objectcount); - this.objects.addElement(pdfResources); - return pdfResources; - } - - /** - * Make a Type 0 sampled function - * - * @param theDomain Vector objects of Double objects. - * This is the domain of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theRange Vector objects of Double objects. - * This is the Range of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theSize A Vector object of Integer objects. - * This is the number of samples in each input dimension. - * I can't imagine there being more or less than two input dimensions, - * so maybe this should be an array of length 2. - * - * See page 265 of the PDF 1.3 Spec. - * @param theBitsPerSample An int specifying the number of bits user to represent each sample value. - * Limited to 1,2,4,8,12,16,24 or 32. - * See page 265 of the 1.3 PDF Spec. - * @param theOrder The order of interpolation between samples. Default is 1 (one). Limited - * to 1 (one) or 3, which means linear or cubic-spline interpolation. - * - * This attribute is optional. - * - * See page 265 in the PDF 1.3 spec. - * @param theEncode Vector objects of Double objects. - * This is the linear mapping of input values intop the domain - * of the function's sample table. Default is hard to represent in - * ascii, but basically [0 (Size0 1) 0 (Size1 1)...]. - * This attribute is optional. - * - * See page 265 in the PDF 1.3 spec. - * @param theDecode Vector objects of Double objects. - * This is a linear mapping of sample values into the range. - * The default is just the range. - * - * This attribute is optional. - * Read about it on page 265 of the PDF 1.3 spec. - * @param theFunctionDataStream The sample values that specify the function are provided in a stream. - * - * This is optional, but is almost always used. - * - * Page 265 of the PDF 1.3 spec has more. - * @param theFilter This is a vector of String objects which are the various filters that - * have are to be applied to the stream to make sense of it. Order matters, - * so watch out. - * - * This is not documented in the Function section of the PDF 1.3 spec, - * it was deduced from samples that this is sometimes used, even if we may never - * use it in FOP. It is added for completeness sake. - * @param theNumber The object number of this PDF object. - * @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 makeFunction(int theFunctionType, - Vector theDomain, Vector theRange, - Vector theSize,int theBitsPerSample, - int theOrder,Vector theEncode,Vector theDecode, - StringBuffer theFunctionDataStream, Vector theFilter) - {//Type 0 function - PDFFunction function = new PDFFunction( - ++this.objectcount, theFunctionType, - theDomain, theRange, theSize, - theBitsPerSample, theOrder, - theEncode, theDecode, - theFunctionDataStream, theFilter); - - this.objects.addElement(function); - return(function); - } - - /** - * make a type Exponential interpolation function - * (for shading usually) - * - * @param theDomain Vector objects of Double objects. - * This is the domain of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theRange Vector of Doubles that is the Range of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theCZero This is a vector of Double objects which defines the function result - * when x=0. - * - * This attribute is optional. - * It's described on page 268 of the PDF 1.3 spec. - * @param theCOne This is a vector of Double objects which defines the function result - * when x=1. - * - * This attribute is optional. - * It's described on page 268 of the PDF 1.3 spec. - * @param theInterpolationExponentN This is the inerpolation exponent. - * - * This attribute is required. - * PDF Spec page 268 - * @param theFunctionType The type of the function, which should be 2. - */ - public PDFFunction makeFunction(int theFunctionType, - Vector theDomain, Vector theRange, - Vector theCZero, Vector theCOne, - double theInterpolationExponentN) - - {//type 2 - PDFFunction function = new PDFFunction( - ++this.objectcount, - theFunctionType, - theDomain, theRange, - theCZero, theCOne, - theInterpolationExponentN); - - this.objects.addElement(function); - return(function); - } - - /** - * Make a Type 3 Stitching function - * - * @param theDomain Vector objects of Double objects. - * This is the domain of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theRange Vector objects of Double objects. - * This is the Range of the function. - * See page 264 of the PDF 1.3 Spec. - * @param theFunctions A Vector of the PDFFunction objects that the stitching function stitches. - * - * This attributed is required. - * It is described on page 269 of the PDF spec. - * @param theBounds This is a vector of Doubles representing the numbers that, - * in conjunction with Domain define the intervals to which each function from - * the 'functions' object applies. It must be in order of increasing magnitude, - * and each must be within Domain. - * - * It basically sets how much of the gradient each function handles. - * - * This attributed is required. - * It's described on page 269 of the PDF 1.3 spec. - * @param theEncode Vector objects of Double objects. - * This is the linear mapping of input values intop the domain - * of the function's sample table. Default is hard to represent in - * ascii, but basically [0 (Size0 1) 0 (Size1 1)...]. - * This attribute is required. - * - * See page 270 in the PDF 1.3 spec. - * @param theFunctionType This is the function type. It should be 3, - * for a stitching function. - */ - public PDFFunction makeFunction(int theFunctionType, - Vector theDomain, Vector theRange, - Vector theFunctions, Vector theBounds, - Vector theEncode) - {//Type 3 - - PDFFunction function = new PDFFunction( - ++this.objectcount, - theFunctionType, - theDomain, theRange, - theFunctions, theBounds, - theEncode); - - this.objects.addElement(function); - return(function); - } - - /** - * make a postscript calculator function - * - * @param theNumber - * @param theFunctionType - * @param theDomain - * @param theRange - * @param theFunctionDataStream - */ - public PDFFunction makeFunction(int theNumber, int theFunctionType, - Vector theDomain, Vector theRange, - StringBuffer theFunctionDataStream) - { //Type 4 - PDFFunction function = new PDFFunction( - ++this.objectcount, - theFunctionType, - theDomain, theRange, - theFunctionDataStream); - - this.objects.addElement(function); - return(function); - - } - - /** - * make a function based shading object - * - * @param theShadingType The type of shading object, which should be 1 for function - * based shading. - * @param theColorSpace The colorspace is 'DeviceRGB' or something similar. - * @param theBackground An array of color components appropriate to the - * colorspace key specifying a single color value. - * This key is used by the f operator buy ignored by the sh operator. - * @param theBBox Vector of double's representing a rectangle - * in the coordinate space that is current at the - * time of shading is imaged. Temporary clipping - * boundary. - * @param theAntiAlias Whether or not to anti-alias. - * @param theDomain Optional vector of Doubles specifying the domain. - * @param theMatrix Vector of Doubles specifying the matrix. - * If it's a pattern, then the matrix maps it to pattern space. - * If it's a shading, then it maps it to current user space. - * It's optional, the default is the identity matrix - * @param theFunction The PDF Function that maps an (x,y) location to a color - */ - public PDFShading makeShading(int theShadingType, ColorSpace theColorSpace, - Vector theBackground, Vector theBBox, boolean theAntiAlias, - Vector theDomain, Vector theMatrix, PDFFunction theFunction) - { //make Shading of Type 1 - String theShadingName = new String("Sh"+(++this.shadingCount)); - - PDFShading shading = new PDFShading(++this.objectcount, theShadingName, - theShadingType, theColorSpace, theBackground, theBBox, - theAntiAlias, theDomain, theMatrix, theFunction); - this.objects.addElement(shading); - - //add this shading to resources - this.resources.addShading(shading); - - return(shading); - } - - /** - * Make an axial or radial shading object. - * - * @param theShadingType 2 or 3 for axial or radial shading - * @param theColorSpace "DeviceRGB" or similar. - * @param theBackground theBackground An array of color components appropriate to the - * colorspace key specifying a single color value. - * This key is used by the f operator buy ignored by the sh operator. - * @param theBBox Vector of double's representing a rectangle - * in the coordinate space that is current at the - * time of shading is imaged. Temporary clipping - * boundary. - * @param theAntiAlias Default is false - * @param theCoords Vector of four (type 2) or 6 (type 3) Double - * @param theDomain Vector of Doubles specifying the domain - * @param theFunction the Stitching (PDFfunction type 3) function, even if it's stitching a single function - * @param theExtend Vector of Booleans of whether to extend teh start and end colors past the start and end points - * The default is [false, false] - */ - public PDFShading makeShading(int theShadingType, - ColorSpace theColorSpace, Vector theBackground, - Vector theBBox, boolean theAntiAlias, - Vector theCoords, Vector theDomain, - PDFFunction theFunction, Vector theExtend) - { //make Shading of Type 2 or 3 - String theShadingName = new String("Sh"+(++this.shadingCount)); - - PDFShading shading = new PDFShading(++this.objectcount, theShadingName, - theShadingType, theColorSpace, - theBackground, theBBox, theAntiAlias, - theCoords, theDomain,theFunction,theExtend); - - this.resources.addShading(shading); - - this.objects.addElement(shading); - return(shading); - } - - /** - * Make a free-form gouraud shaded triangle mesh, coons patch mesh, or tensor patch mesh - * shading object - * - * @param theShadingType 4, 6, or 7 depending on whether it's - * Free-form gouraud-shaded triangle meshes, coons patch meshes, - * or tensor product patch meshes, respectively. - * @param theColorSpace "DeviceRGB" or similar. - * @param theBackground theBackground An array of color components appropriate to the - * colorspace key specifying a single color value. - * This key is used by the f operator buy ignored by the sh operator. - * @param theBBox Vector of double's representing a rectangle - * in the coordinate space that is current at the - * time of shading is imaged. Temporary clipping - * boundary. - * @param theAntiAlias Default is false - * @param theBitsPerCoordinate 1,2,4,8,12,16,24 or 32. - * @param theBitsPerComponent 1,2,4,8,12, and 16 - * @param theBitsPerFlag 2,4,8. - * @param theDecode Vector of Doubles see PDF 1.3 spec pages 303 to 312. - * @param theFunction the PDFFunction - */ - public PDFShading makeShading(int theShadingType, ColorSpace theColorSpace, - Vector theBackground, Vector theBBox, boolean theAntiAlias, - int theBitsPerCoordinate, int theBitsPerComponent, - int theBitsPerFlag, Vector theDecode, PDFFunction theFunction) - { //make Shading of type 4,6 or 7 - String theShadingName = new String("Sh"+(++this.shadingCount)); - - PDFShading shading = new PDFShading(++this.objectcount, theShadingName, - theShadingType, theColorSpace, - theBackground, theBBox, theAntiAlias, - theBitsPerCoordinate,theBitsPerComponent, - theBitsPerFlag, theDecode, theFunction); - - this.resources.addShading(shading); - - this.objects.addElement(shading); - return(shading); - } - - /** - * make a Lattice-Form Gouraud mesh shading object - * - * @param theShadingType 5 for lattice-Form Gouraud shaded-triangle mesh - * without spaces. "Shading1" or "Sh1" are good examples. - * @param theColorSpace "DeviceRGB" or similar. - * @param theBackground theBackground An array of color components appropriate to the - * colorspace key specifying a single color value. - * This key is used by the f operator buy ignored by the sh operator. - * @param theBBox Vector of double's representing a rectangle - * in the coordinate space that is current at the - * time of shading is imaged. Temporary clipping - * boundary. - * @param theAntiAlias Default is false - * @param theBitsPerCoordinate 1,2,4,8,12,16, 24, or 32 - * @param theBitsPerComponent 1,2,4,8,12,24,32 - * @param theDecode Vector of Doubles. See page 305 in PDF 1.3 spec. - * @param theVerticesPerRow number of vertices in each "row" of the lattice. - * @param theFunction The PDFFunction that's mapped on to this shape - */ - public PDFShading makeShading(int theShadingType, ColorSpace theColorSpace, - Vector theBackground, Vector theBBox, boolean theAntiAlias, - int theBitsPerCoordinate, int theBitsPerComponent, - Vector theDecode, int theVerticesPerRow, PDFFunction theFunction) - { //make shading of Type 5 - String theShadingName = new String("Sh"+(++this.shadingCount)); - - PDFShading shading= new PDFShading(++this.objectcount, - theShadingName, theShadingType, theColorSpace, - theBackground, theBBox, theAntiAlias, - theBitsPerCoordinate, theBitsPerComponent, - theDecode, theVerticesPerRow, theFunction); - - this.resources.addShading(shading); - - this.objects.addElement(shading); - - return(shading); - } - - /** - * Make a tiling pattern - * - * @param thePatternType the type of pattern, which is 1 for tiling. - * @param theResources the resources associated with this pattern - * @param thePaintType 1 or 2, colored or uncolored. - * @param theTilingType 1, 2, or 3, constant spacing, no distortion, or faster tiling - * @param theBBox Vector of Doubles: The pattern cell bounding box - * @param theXStep horizontal spacing - * @param theYStep vertical spacing - * @param theMatrix Optional Vector 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 makePattern( - int thePatternType, //1 - PDFResources theResources, - int thePaintType, int theTilingType, - Vector theBBox, double theXStep, double theYStep, - Vector theMatrix, Vector theXUID, StringBuffer thePatternDataStream) - { - String thePatternName = new String("Pa"+(++this.patternCount)); - //int theNumber, String thePatternName, - //PDFResources theResources - PDFPattern pattern = new PDFPattern(++this.objectcount, - thePatternName, - theResources, 1, - thePaintType, theTilingType, - theBBox, theXStep, theYStep, - theMatrix, theXUID, thePatternDataStream); - - this.resources.addPattern(pattern); - this.objects.addElement(pattern); - - return(pattern); - } - - /** - * Make a smooth shading pattern - * - * @param thePatternType the type of the pattern, which is 2, smooth shading - * @param theShading the PDF 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:Vector of Doubles that specify the matrix. - */ - public PDFPattern makePattern(int thePatternType, - PDFShading theShading, Vector theXUID, - StringBuffer theExtGState,Vector theMatrix) - { - String thePatternName = new String("Pa"+(++this.patternCount)); - - PDFPattern pattern = new PDFPattern(++this.objectcount, - thePatternName, 2, theShading, theXUID, - theExtGState, theMatrix); - - this.resources.addPattern(pattern); - this.objects.addElement(pattern); - - return(pattern); - } - - public int getColorSpace() - { - return(this.colorspace.getColorSpace()); - } - - public void setColorSpace(int theColorspace) - { - this.colorspace.setColorSpace(theColorspace); - return; - } - - public PDFPattern createGradient(boolean radial, - ColorSpace theColorspace, - Vector theColors, - Vector theBounds, - Vector theCoords) - { - PDFShading myShad; - PDFFunction myfunky; - PDFFunction myfunc; - Vector theCzero; - Vector theCone; - PDFPattern myPattern; - ColorSpace theColorSpace; - double interpolation = (double) 1.000; - Vector theFunctions = new Vector(); - - int currentPosition; - int lastPosition = theColors.size()-2; - - - //if 5 elements, the penultimate element is 3. - //do not go beyond that, because you always need - //to have a next color when creating the function. - - for(currentPosition=0; - currentPosition < lastPosition; - currentPosition++) - {//for every consecutive color pair - PDFColor currentColor = - (PDFColor)theColors.elementAt(currentPosition); - PDFColor nextColor = - (PDFColor)theColors.elementAt(currentPosition+1); - //colorspace must be consistant - if (this.colorspace.getColorSpace() != currentColor.getColorSpace()) - currentColor.setColorSpace(this.colorspace.getColorSpace()); - - if (this.colorspace.getColorSpace() != nextColor.getColorSpace()) - nextColor.setColorSpace(this.colorspace.getColorSpace()); - - theCzero = currentColor.getVector(); - theCone = nextColor.getVector(); - - myfunc = this.makeFunction( - 2, null, null, - theCzero, theCone, - interpolation); - - theFunctions.addElement(myfunc); - - }//end of for every consecutive color pair - - myfunky = this.makeFunction(3, - null, null, - theFunctions, theBounds, - null); - - if(radial) - { - if(theCoords.size() ==6) - { - myShad = this.makeShading( - 3, this.colorspace, - null, null, false, - theCoords, null, myfunky, null); - } - else - { //if the center x, center y, and radius specifiy - //the gradient, then assume the same center x, center y, - //and radius of zero for the other necessary component - Vector newCoords = new Vector(); - newCoords.addElement(theCoords.elementAt(0)); - newCoords.addElement(theCoords.elementAt(1)); - newCoords.addElement(theCoords.elementAt(2)); - newCoords.addElement(theCoords.elementAt(0)); - newCoords.addElement(theCoords.elementAt(1)); - newCoords.addElement(new Double(0.0)); - - myShad = this.makeShading( - 3, this.colorspace, - null, null, false, - newCoords, null, myfunky, null); - - } - } - else - { - myShad = this.makeShading( - 2, this.colorspace, - null, null, false, - theCoords, null, myfunky, null); - - } - - myPattern = this.makePattern( - 2, myShad, null, null, null); - - return(myPattern); - } - - - /** - * make a Type1 /Font object - * - * @param fontname internal name to use for this font (eg "F1") - * @param basefont name of the base font (eg "Helvetica") - * @param encoding character encoding scheme used by the font - * @return the created /Font object - */ - public PDFFont makeFont(String fontname, String basefont, - String encoding) { - - /* create a PDFFont with the next object number and add to the - list of objects */ - PDFFont font = new PDFFont(++this.objectcount, fontname, - basefont, encoding); - this.objects.addElement(font); - return font; - } - - public int addImage(FopImage img) { - // check if already created - String url = img.getURL(); - PDFXObject xObject = (PDFXObject) this.xObjectsMap.get(url); - if (xObject != null) return xObject.getXNumber(); - // else, create a new one - xObject = new PDFXObject(++this.objectcount, - ++this.xObjectCount, img); - this.objects.addElement(xObject); - this.xObjects.addElement(xObject); - this.xObjectsMap.put(url, xObject); - return xObjectCount; - } - - /** - * make a /Page object - * - * @param resources resources object to use - * @param contents stream object with content - * @param pagewidth width of the page in points - * @param pageheight height of the page in points - * - * @return the created /Page object - */ - public PDFPage makePage(PDFResources resources, - PDFStream contents, - int pagewidth, - int pageheight) { - - /* create a PDFPage with the next object number, the given - resources, contents and dimensions */ - PDFPage page = new PDFPage(++this.objectcount, resources, - contents, - pagewidth, pageheight); - - /* add it to the list of objects */ - this.objects.addElement(page); - - /* add the page to the Root */ - this.root.addPage(page); - - return page; - } - - /** - * make a link object - * - * @param rect the clickable rectangle - * @param destination the destination file - * - * @return the PDFLink object created - */ - public PDFLink makeLink(Rectangle rect, String destination) { + /** the version of PDF supported */ + protected static final String pdfVersion = "1.3"; + + /** the current character position */ + protected int position = 0; + + /** the character position of each object */ + protected Vector location = new Vector(); + + /** the counter for object numbering */ + protected int objectcount = 0; + + /** the objects themselves */ + protected Vector objects = new Vector(); + + /** character position of xref table */ + protected int xref; + + /** the /Root object */ + protected PDFRoot root; + + /** the /Info object */ + protected PDFInfo info; + + /** the /Resources object */ + protected PDFResources resources; + + /** the documents idReferences */ + protected IDReferences idReferences; + + /** the colorspace (0=RGB, 1=CMYK) **/ + //protected int colorspace = 0; + protected ColorSpace colorspace = new ColorSpace(ColorSpace.DEVICE_RGB); + + /** the counter for Pattern name numbering (e.g. 'Pattern1')*/ + protected int patternCount = 0; + + /** the counter for Shading name numbering */ + protected int shadingCount = 0; + + /** the counter for XObject numbering */ + protected int xObjectCount = 0; + + /** the XObjects */ + protected Vector xObjects = new Vector(); + + /** the XObjects Map. + Should be modified (works only for image subtype) */ + protected Hashtable xObjectsMap = new Hashtable(); + + /** + * creates an empty PDF document + */ + public PDFDocument() { + + /* create the /Root, /Info and /Resources objects */ + this.root = makeRoot(); + this.info = makeInfo(); + this.resources = makeResources(); + } + + /** + * set the producer of the document + * + * @param producer string indicating application producing the PDF + */ + public void setProducer(String producer) { + this.info.setProducer(producer); + } + + /** + * make /Root object as next object + * + * @return the created /Root object + */ + protected PDFRoot makeRoot() { + + /* create a PDFRoot with the next object number and add to + list of objects */ + PDFRoot pdfRoot = new PDFRoot(++this.objectcount); + this.objects.addElement(pdfRoot); + + /* create a new /Pages object to be root of Pages hierarchy + and add to list of objects */ + PDFPages rootPages = new PDFPages(++this.objectcount); + this.objects.addElement(rootPages); + + /* inform the /Root object of the /Pages root */ + pdfRoot.setRootPages(rootPages); + return pdfRoot; + } + + /** + * make an /Info object + * + * @param producer string indicating application producing the PDF + * @return the created /Info object + */ + protected PDFInfo makeInfo() { + + /* create a PDFInfo with the next object number and add to + list of objects */ + PDFInfo pdfInfo = new PDFInfo(++this.objectcount); + this.objects.addElement(pdfInfo); + return pdfInfo; + } + + /** + * make a /Resources object + * + * @return the created /Resources object + */ + private PDFResources makeResources() { + + /* create a PDFResources with the next object number and add + to list of objects */ + PDFResources pdfResources = new PDFResources(++this.objectcount); + this.objects.addElement(pdfResources); + return pdfResources; + } + + /** + * Make a Type 0 sampled function + * + * @param theDomain Vector objects of Double objects. + * This is the domain of the function. + * See page 264 of the PDF 1.3 Spec. + * @param theRange Vector objects of Double objects. + * This is the Range of the function. + * See page 264 of the PDF 1.3 Spec. + * @param theSize A Vector object of Integer objects. + * This is the number of samples in each input dimension. + * I can't imagine there being more or less than two input dimensions, + * so maybe this should be an array of length 2. + * + * See page 265 of the PDF 1.3 Spec. + * @param theBitsPerSample An int specifying the number of bits user to represent each sample value. + * Limited to 1,2,4,8,12,16,24 or 32. + * See page 265 of the 1.3 PDF Spec. + * @param theOrder The order of interpolation between samples. Default is 1 (one). Limited + * to 1 (one) or 3, which means linear or cubic-spline interpolation. + * + * This attribute is optional. + * + * See page 265 in the PDF 1.3 spec. + * @param theEncode Vector objects of Double objects. + * This is the linear mapping of input values intop the domain + * of the function's sample table. Default is hard to represent in + * ascii, but basically [0 (Size0 1) 0 (Size1 1)...]. + * This attribute is optional. + * + * See page 265 in the PDF 1.3 spec. + * @param theDecode Vector objects of Double objects. + * This is a linear mapping of sample values into the range. + * The default is just the range. + * + * This attribute is optional. + * Read about it on page 265 of the PDF 1.3 spec. + * @param theFunctionDataStream The sample values that specify the function are provided in a stream. + * + * This is optional, but is almost always used. + * + * Page 265 of the PDF 1.3 spec has more. + * @param theFilter This is a vector of String objects which are the various filters that + * have are to be applied to the stream to make sense of it. Order matters, + * so watch out. + * + * This is not documented in the Function section of the PDF 1.3 spec, + * it was deduced from samples that this is sometimes used, even if we may never + * use it in FOP. It is added for completeness sake. + * @param theNumber The object number of this PDF object. + * @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 makeFunction(int theFunctionType, + Vector theDomain, Vector theRange, + Vector theSize,int theBitsPerSample, + int theOrder,Vector theEncode,Vector theDecode, + StringBuffer theFunctionDataStream, Vector theFilter) + {//Type 0 function + PDFFunction function = new PDFFunction( + ++this.objectcount, theFunctionType, + theDomain, theRange, theSize, + theBitsPerSample, theOrder, + theEncode, theDecode, + theFunctionDataStream, theFilter); + + this.objects.addElement(function); + return(function); + } + + /** + * make a type Exponential interpolation function + * (for shading usually) + * + * @param theDomain Vector objects of Double objects. + * This is the domain of the function. + * See page 264 of the PDF 1.3 Spec. + * @param theRange Vector of Doubles that is the Range of the function. + * See page 264 of the PDF 1.3 Spec. + * @param theCZero This is a vector of Double objects which defines the function result + * when x=0. + * + * This attribute is optional. + * It's described on page 268 of the PDF 1.3 spec. + * @param theCOne This is a vector of Double objects which defines the function result + * when x=1. + * + * This attribute is optional. + * It's described on page 268 of the PDF 1.3 spec. + * @param theInterpolationExponentN This is the inerpolation exponent. + * + * This attribute is required. + * PDF Spec page 268 + * @param theFunctionType The type of the function, which should be 2. + */ + public PDFFunction makeFunction(int theFunctionType, + Vector theDomain, Vector theRange, + Vector theCZero, Vector theCOne, + double theInterpolationExponentN) + + {//type 2 + PDFFunction function = new PDFFunction( + ++this.objectcount, + theFunctionType, + theDomain, theRange, + theCZero, theCOne, + theInterpolationExponentN); + + this.objects.addElement(function); + return(function); + } + + /** + * Make a Type 3 Stitching function + * + * @param theDomain Vector objects of Double objects. + * This is the domain of the function. + * See page 264 of the PDF 1.3 Spec. + * @param theRange Vector objects of Double objects. + * This is the Range of the function. + * See page 264 of the PDF 1.3 Spec. + * @param theFunctions A Vector of the PDFFunction objects that the stitching function stitches. + * + * This attributed is required. + * It is described on page 269 of the PDF spec. + * @param theBounds This is a vector of Doubles representing the numbers that, + * in conjunction with Domain define the intervals to which each function from + * the 'functions' object applies. It must be in order of increasing magnitude, + * and each must be within Domain. + * + * It basically sets how much of the gradient each function handles. + * + * This attributed is required. + * It's described on page 269 of the PDF 1.3 spec. + * @param theEncode Vector objects of Double objects. + * This is the linear mapping of input values intop the domain + * of the function's sample table. Default is hard to represent in + * ascii, but basically [0 (Size0 1) 0 (Size1 1)...]. + * This attribute is required. + * + * See page 270 in the PDF 1.3 spec. + * @param theFunctionType This is the function type. It should be 3, + * for a stitching function. + */ + public PDFFunction makeFunction(int theFunctionType, + Vector theDomain, Vector theRange, + Vector theFunctions, Vector theBounds, + Vector theEncode) + {//Type 3 + + PDFFunction function = new PDFFunction( + ++this.objectcount, + theFunctionType, + theDomain, theRange, + theFunctions, theBounds, + theEncode); + + this.objects.addElement(function); + return(function); + } + + /** + * make a postscript calculator function + * + * @param theNumber + * @param theFunctionType + * @param theDomain + * @param theRange + * @param theFunctionDataStream + */ + public PDFFunction makeFunction(int theNumber, int theFunctionType, + Vector theDomain, Vector theRange, + StringBuffer theFunctionDataStream) + { //Type 4 + PDFFunction function = new PDFFunction( + ++this.objectcount, + theFunctionType, + theDomain, theRange, + theFunctionDataStream); + + this.objects.addElement(function); + return(function); + + } + + /** + * make a function based shading object + * + * @param theShadingType The type of shading object, which should be 1 for function + * based shading. + * @param theColorSpace The colorspace is 'DeviceRGB' or something similar. + * @param theBackground An array of color components appropriate to the + * colorspace key specifying a single color value. + * This key is used by the f operator buy ignored by the sh operator. + * @param theBBox Vector of double's representing a rectangle + * in the coordinate space that is current at the + * time of shading is imaged. Temporary clipping + * boundary. + * @param theAntiAlias Whether or not to anti-alias. + * @param theDomain Optional vector of Doubles specifying the domain. + * @param theMatrix Vector of Doubles specifying the matrix. + * If it's a pattern, then the matrix maps it to pattern space. + * If it's a shading, then it maps it to current user space. + * It's optional, the default is the identity matrix + * @param theFunction The PDF Function that maps an (x,y) location to a color + */ + public PDFShading makeShading(int theShadingType, ColorSpace theColorSpace, + Vector theBackground, Vector theBBox, boolean theAntiAlias, + Vector theDomain, Vector theMatrix, PDFFunction theFunction) + { //make Shading of Type 1 + String theShadingName = new String("Sh"+(++this.shadingCount)); + + PDFShading shading = new PDFShading(++this.objectcount, theShadingName, + theShadingType, theColorSpace, theBackground, theBBox, + theAntiAlias, theDomain, theMatrix, theFunction); + this.objects.addElement(shading); + + //add this shading to resources + this.resources.addShading(shading); + + return(shading); + } + + /** + * Make an axial or radial shading object. + * + * @param theShadingType 2 or 3 for axial or radial shading + * @param theColorSpace "DeviceRGB" or similar. + * @param theBackground theBackground An array of color components appropriate to the + * colorspace key specifying a single color value. + * This key is used by the f operator buy ignored by the sh operator. + * @param theBBox Vector of double's representing a rectangle + * in the coordinate space that is current at the + * time of shading is imaged. Temporary clipping + * boundary. + * @param theAntiAlias Default is false + * @param theCoords Vector of four (type 2) or 6 (type 3) Double + * @param theDomain Vector of Doubles specifying the domain + * @param theFunction the Stitching (PDFfunction type 3) function, even if it's stitching a single function + * @param theExtend Vector of Booleans of whether to extend teh start and end colors past the start and end points + * The default is [false, false] + */ + public PDFShading makeShading(int theShadingType, + ColorSpace theColorSpace, Vector theBackground, + Vector theBBox, boolean theAntiAlias, + Vector theCoords, Vector theDomain, + PDFFunction theFunction, Vector theExtend) + { //make Shading of Type 2 or 3 + String theShadingName = new String("Sh"+(++this.shadingCount)); + + PDFShading shading = new PDFShading(++this.objectcount, theShadingName, + theShadingType, theColorSpace, + theBackground, theBBox, theAntiAlias, + theCoords, theDomain,theFunction,theExtend); + + this.resources.addShading(shading); + + this.objects.addElement(shading); + return(shading); + } + + /** + * Make a free-form gouraud shaded triangle mesh, coons patch mesh, or tensor patch mesh + * shading object + * + * @param theShadingType 4, 6, or 7 depending on whether it's + * Free-form gouraud-shaded triangle meshes, coons patch meshes, + * or tensor product patch meshes, respectively. + * @param theColorSpace "DeviceRGB" or similar. + * @param theBackground theBackground An array of color components appropriate to the + * colorspace key specifying a single color value. + * This key is used by the f operator buy ignored by the sh operator. + * @param theBBox Vector of double's representing a rectangle + * in the coordinate space that is current at the + * time of shading is imaged. Temporary clipping + * boundary. + * @param theAntiAlias Default is false + * @param theBitsPerCoordinate 1,2,4,8,12,16,24 or 32. + * @param theBitsPerComponent 1,2,4,8,12, and 16 + * @param theBitsPerFlag 2,4,8. + * @param theDecode Vector of Doubles see PDF 1.3 spec pages 303 to 312. + * @param theFunction the PDFFunction + */ + public PDFShading makeShading(int theShadingType, ColorSpace theColorSpace, + Vector theBackground, Vector theBBox, boolean theAntiAlias, + int theBitsPerCoordinate, int theBitsPerComponent, + int theBitsPerFlag, Vector theDecode, PDFFunction theFunction) + { //make Shading of type 4,6 or 7 + String theShadingName = new String("Sh"+(++this.shadingCount)); + + PDFShading shading = new PDFShading(++this.objectcount, theShadingName, + theShadingType, theColorSpace, + theBackground, theBBox, theAntiAlias, + theBitsPerCoordinate,theBitsPerComponent, + theBitsPerFlag, theDecode, theFunction); + + this.resources.addShading(shading); + + this.objects.addElement(shading); + return(shading); + } + + /** + * make a Lattice-Form Gouraud mesh shading object + * + * @param theShadingType 5 for lattice-Form Gouraud shaded-triangle mesh + * without spaces. "Shading1" or "Sh1" are good examples. + * @param theColorSpace "DeviceRGB" or similar. + * @param theBackground theBackground An array of color components appropriate to the + * colorspace key specifying a single color value. + * This key is used by the f operator buy ignored by the sh operator. + * @param theBBox Vector of double's representing a rectangle + * in the coordinate space that is current at the + * time of shading is imaged. Temporary clipping + * boundary. + * @param theAntiAlias Default is false + * @param theBitsPerCoordinate 1,2,4,8,12,16, 24, or 32 + * @param theBitsPerComponent 1,2,4,8,12,24,32 + * @param theDecode Vector of Doubles. See page 305 in PDF 1.3 spec. + * @param theVerticesPerRow number of vertices in each "row" of the lattice. + * @param theFunction The PDFFunction that's mapped on to this shape + */ + public PDFShading makeShading(int theShadingType, ColorSpace theColorSpace, + Vector theBackground, Vector theBBox, boolean theAntiAlias, + int theBitsPerCoordinate, int theBitsPerComponent, + Vector theDecode, int theVerticesPerRow, PDFFunction theFunction) + { //make shading of Type 5 + String theShadingName = new String("Sh"+(++this.shadingCount)); + + PDFShading shading= new PDFShading(++this.objectcount, + theShadingName, theShadingType, theColorSpace, + theBackground, theBBox, theAntiAlias, + theBitsPerCoordinate, theBitsPerComponent, + theDecode, theVerticesPerRow, theFunction); + + this.resources.addShading(shading); + + this.objects.addElement(shading); + + return(shading); + } + + /** + * Make a tiling pattern + * + * @param thePatternType the type of pattern, which is 1 for tiling. + * @param theResources the resources associated with this pattern + * @param thePaintType 1 or 2, colored or uncolored. + * @param theTilingType 1, 2, or 3, constant spacing, no distortion, or faster tiling + * @param theBBox Vector of Doubles: The pattern cell bounding box + * @param theXStep horizontal spacing + * @param theYStep vertical spacing + * @param theMatrix Optional Vector 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 makePattern( + int thePatternType, //1 + PDFResources theResources, + int thePaintType, int theTilingType, + Vector theBBox, double theXStep, double theYStep, + Vector theMatrix, Vector theXUID, StringBuffer thePatternDataStream) + { + String thePatternName = new String("Pa"+(++this.patternCount)); + //int theNumber, String thePatternName, + //PDFResources theResources + PDFPattern pattern = new PDFPattern(++this.objectcount, + thePatternName, + theResources, 1, + thePaintType, theTilingType, + theBBox, theXStep, theYStep, + theMatrix, theXUID, thePatternDataStream); + + this.resources.addPattern(pattern); + this.objects.addElement(pattern); + + return(pattern); + } + + /** + * Make a smooth shading pattern + * + * @param thePatternType the type of the pattern, which is 2, smooth shading + * @param theShading the PDF 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:Vector of Doubles that specify the matrix. + */ + public PDFPattern makePattern(int thePatternType, + PDFShading theShading, Vector theXUID, + StringBuffer theExtGState,Vector theMatrix) + { + String thePatternName = new String("Pa"+(++this.patternCount)); + + PDFPattern pattern = new PDFPattern(++this.objectcount, + thePatternName, 2, theShading, theXUID, + theExtGState, theMatrix); + + this.resources.addPattern(pattern); + this.objects.addElement(pattern); + + return(pattern); + } + + public int getColorSpace() + { + return(this.colorspace.getColorSpace()); + } + + public void setColorSpace(int theColorspace) + { + this.colorspace.setColorSpace(theColorspace); + return; + } + + public PDFPattern createGradient(boolean radial, + ColorSpace theColorspace, + Vector theColors, + Vector theBounds, + Vector theCoords) + { + PDFShading myShad; + PDFFunction myfunky; + PDFFunction myfunc; + Vector theCzero; + Vector theCone; + PDFPattern myPattern; + ColorSpace theColorSpace; + double interpolation = (double) 1.000; + Vector theFunctions = new Vector(); + + int currentPosition; + int lastPosition = theColors.size()-2; + + + //if 5 elements, the penultimate element is 3. + //do not go beyond that, because you always need + //to have a next color when creating the function. + + for ( currentPosition=0; + currentPosition < lastPosition; + currentPosition++ ) {//for every consecutive color pair + PDFColor currentColor = + (PDFColor)theColors.elementAt(currentPosition); + PDFColor nextColor = + (PDFColor)theColors.elementAt(currentPosition+1); + //colorspace must be consistant + if ( this.colorspace.getColorSpace() != currentColor.getColorSpace() ) + currentColor.setColorSpace(this.colorspace.getColorSpace()); + + if ( this.colorspace.getColorSpace() != nextColor.getColorSpace() ) + nextColor.setColorSpace(this.colorspace.getColorSpace()); + + theCzero = currentColor.getVector(); + theCone = nextColor.getVector(); + + myfunc = this.makeFunction( + 2, null, null, + theCzero, theCone, + interpolation); + + theFunctions.addElement(myfunc); + + }//end of for every consecutive color pair + + myfunky = this.makeFunction(3, + null, null, + theFunctions, theBounds, + null); + + if ( radial ) { + if ( theCoords.size() ==6 ) { + myShad = this.makeShading( + 3, this.colorspace, + null, null, false, + theCoords, null, myfunky, null); + } + else { //if the center x, center y, and radius specifiy + //the gradient, then assume the same center x, center y, + //and radius of zero for the other necessary component + Vector newCoords = new Vector(); + newCoords.addElement(theCoords.elementAt(0)); + newCoords.addElement(theCoords.elementAt(1)); + newCoords.addElement(theCoords.elementAt(2)); + newCoords.addElement(theCoords.elementAt(0)); + newCoords.addElement(theCoords.elementAt(1)); + newCoords.addElement(new Double(0.0)); + + myShad = this.makeShading( + 3, this.colorspace, + null, null, false, + newCoords, null, myfunky, null); + + } + } + else { + myShad = this.makeShading( + 2, this.colorspace, + null, null, false, + theCoords, null, myfunky, null); + + } + + myPattern = this.makePattern( + 2, myShad, null, null, null); + + return(myPattern); + } + + + /** + * make a Type1 /Font object + * + * @param fontname internal name to use for this font (eg "F1") + * @param basefont name of the base font (eg "Helvetica") + * @param encoding character encoding scheme used by the font + * @return the created /Font object + */ + public PDFFont makeFont(String fontname, String basefont, + String encoding) { + + /* create a PDFFont with the next object number and add to the + list of objects */ + PDFFont font = new PDFFont(++this.objectcount, fontname, + basefont, encoding); + this.objects.addElement(font); + return font; + } + + public int addImage(FopImage img) { + // check if already created + String url = img.getURL(); + PDFXObject xObject = (PDFXObject) this.xObjectsMap.get(url); + if ( xObject != null ) return xObject.getXNumber(); + // else, create a new one + xObject = new PDFXObject(++this.objectcount, + ++this.xObjectCount, img); + this.objects.addElement(xObject); + this.xObjects.addElement(xObject); + this.xObjectsMap.put(url, xObject); + return xObjectCount; + } + + /** + * make a /Page object + * + * @param resources resources object to use + * @param contents stream object with content + * @param pagewidth width of the page in points + * @param pageheight height of the page in points + * + * @return the created /Page object + */ + public PDFPage makePage(PDFResources resources, + PDFStream contents, + int pagewidth, + int pageheight, + Page currentPage) { + + /* create a PDFPage with the next object number, the given + resources, contents and dimensions */ + PDFPage page = new PDFPage(++this.objectcount, resources, + contents, + pagewidth, pageheight); + + Enumeration enum=currentPage.getIDList().elements(); + while ( enum.hasMoreElements() ) { + String id=enum.nextElement().toString(); + idReferences.setInternalGoToPageReference(id,page.referencePDF()); + } + + /* add it to the list of objects */ + this.objects.addElement(page); + + /* add the page to the Root */ + this.root.addPage(page); + + return page; + } + + /** + * make a link object + * + * @param rect the clickable rectangle + * @param destination the destination file + * @param linkType the link type + * @return the PDFLink object created + */ + public PDFLink makeLink(Rectangle rect, String destination, int linkType) { PDFLink linkObject; PDFAction action; PDFLink link = new PDFLink(++this.objectcount, rect); this.objects.addElement(link); - - //check destination - if ( destination.endsWith(".pdf") ) //FileSpec - { - PDFFileSpec fileSpec = new PDFFileSpec(++this.objectcount,destination); - this.objects.addElement(fileSpec); - action = new PDFGoToRemote(++this.objectcount,fileSpec); - this.objects.addElement(action); - link.setAction(action); + + if ( linkType == LinkSet.EXTERNAL ) { + //check destination + if ( destination.endsWith(".pdf") ) { //FileSpec + PDFFileSpec fileSpec = new PDFFileSpec(++this.objectcount,destination); + this.objects.addElement(fileSpec); + action = new PDFGoToRemote(++this.objectcount,fileSpec); + this.objects.addElement(action); + link.setAction(action); + } + else { //URI + PDFUri uri = new PDFUri(destination); + link.setAction(uri); + } } - else //URI - { - PDFUri uri = new PDFUri(destination); - link.setAction(uri); + else { // linkType is internal + String goToReference; + PDFInternalLink internalLink; + + if ( idReferences.doesIDExist(destination) ) { + if ( idReferences.doesGoToReferenceExist(destination) ) { + goToReference = idReferences.getInternalLinkGotToReference(destination); + } + else { //assign Internal Link GoTo object + goToReference = idReferences.createInternalLinkGoTo(destination,++this.objectcount); + this.objects.addElement(idReferences.getPDFGoTo(destination)); + } + } + else { //id was not found, so create it + idReferences.createNewId(destination); + idReferences.addToIdValidationList(destination); + goToReference = idReferences.createInternalLinkGoTo(destination,++this.objectcount); + this.objects.addElement(idReferences.getPDFGoTo(destination)); + } + internalLink = new PDFInternalLink(goToReference); + link.setAction(internalLink); } - return link; } - /** - * make a stream object - * - * @return the stream object created - */ - public PDFStream makeStream() { - - /* create a PDFStream with the next object number and add it - - to the list of objects */ - PDFStream obj = new PDFStream(++this.objectcount); - this.objects.addElement(obj); - return obj; - } - - /** - * make an annotation list object - * - * @return the annotation list object created - */ - public PDFAnnotList makeAnnotList() { - - /* create a PDFAnnotList with the next object number and add it - to the list of objects */ - PDFAnnotList obj = new PDFAnnotList(++this.objectcount); - this.objects.addElement(obj); - return obj; - } - - /** - * get the /Resources object for the document - * - * @return the /Resources object - */ - public PDFResources getResources() { - return this.resources; - } - - /** - * write the entire document out - * - * @param writer the PrinterWriter to output the document to - */ - public void output(PrintWriter writer) throws IOException { - - /* output the header and increment the character position by - the header's length */ - this.position += outputHeader(writer); - - this.resources.setXObjects(xObjects); - - /* loop through the object numbers */ - for (int i=1; i <= this.objectcount; i++) { - - /* add the position of this object to the list of object - locations */ - this.location.addElement(new Integer(this.position)); - - /* retrieve the object with the current number */ - PDFObject object = (PDFObject)this.objects.elementAt(i-1); - - /* output the object and increment the character position - by the object's length */ - this.position += object.output(writer); - } - - /* output the xref table and increment the character position - by the table's length */ - this.position += outputXref(writer); - - /* output the trailer and flush the Writer */ - outputTrailer(writer); - writer.flush(); - } - - /** - * write the PDF header - * - * @param writer the PrintWriter to write the header to - * @return the number of characters written - */ - protected int outputHeader(PrintWriter writer) throws IOException { - String pdf = "%PDF-" + this.pdfVersion + "\n"; - writer.write(pdf); - return pdf.length(); - } - - /** - * write the trailer - * - * @param writer the PrintWriter to write the trailer to - */ - protected void outputTrailer(PrintWriter writer) throws IOException { - - /* construct the trailer */ - String pdf = "trailer\n<<\n/Size " + (this.objectcount+1) - + "\n/Root " + this.root.number + " " + this.root.generation - + " R\n/Info " + this.info.number + " " - + this.info.generation + " R\n>>\nstartxref\n" + this.xref - + "\n%%EOF\n"; - - /* write the trailer */ - writer.write(pdf); - } - - /** - * write the xref table - * - * @param writer the PrintWriter to write the xref table to - * @return the number of characters written - */ - private int outputXref(PrintWriter writer) throws IOException { - - /* remember position of xref table */ - this.xref = this.position; - - /* construct initial part of xref */ - StringBuffer pdf = new StringBuffer("xref\n0 " + (this.objectcount+1) - + "\n0000000000 65535 f \n"); - - /* loop through object numbers */ - for (int i=1; i < this.objectcount+1; i++) { - - /* contruct xref entry for object */ - String padding = "0000000000"; - String x = this.location.elementAt(i-1).toString(); - String loc = padding.substring(x.length()) + x; - - /* append to xref table */ - pdf = pdf.append(loc + " 00000 n \n"); - } - - /* write the xref table and return the character length */ - writer.write(pdf.toString()); - return pdf.length(); - } -} + + /** + * make a stream object + * + * @return the stream object created + */ + public PDFStream makeStream() { + + /* create a PDFStream with the next object number and add it + + to the list of objects */ + PDFStream obj = new PDFStream(++this.objectcount); + this.objects.addElement(obj); + return obj; + } + + /** + * make an annotation list object + * + * @return the annotation list object created + */ + public PDFAnnotList makeAnnotList() { + + /* create a PDFAnnotList with the next object number and add it + to the list of objects */ + PDFAnnotList obj = new PDFAnnotList(++this.objectcount); + this.objects.addElement(obj); + return obj; + } + + /** + * get the /Resources object for the document + * + * @return the /Resources object + */ + public PDFResources getResources() { + return this.resources; + } + + /** + * write the entire document out + * + * @param writer the PrinterWriter to output the document to + */ + public void output(PrintWriter writer) throws IOException { + + /* output the header and increment the character position by + the header's length */ + this.position += outputHeader(writer); + + this.resources.setXObjects(xObjects); + + /* loop through the object numbers */ + for ( int i=1; i <= this.objectcount; i++ ) { + + /* add the position of this object to the list of object + locations */ + this.location.addElement(new Integer(this.position)); + + /* retrieve the object with the current number */ + PDFObject object = (PDFObject)this.objects.elementAt(i-1); + + /* output the object and increment the character position + by the object's length */ + this.position += object.output(writer); + } + + /* output the xref table and increment the character position + by the table's length */ + this.position += outputXref(writer); + + /* output the trailer and flush the Writer */ + outputTrailer(writer); + writer.flush(); + } + + /** + * write the PDF header + * + * @param writer the PrintWriter to write the header to + * @return the number of characters written + */ + protected int outputHeader(PrintWriter writer) throws IOException { + String pdf = "%PDF-" + this.pdfVersion + "\n"; + writer.write(pdf); + return pdf.length(); + } + + /** + * write the trailer + * + * @param writer the PrintWriter to write the trailer to + */ + protected void outputTrailer(PrintWriter writer) throws IOException { + + /* construct the trailer */ + String pdf = "trailer\n<<\n/Size " + (this.objectcount+1) + + "\n/Root " + this.root.number + " " + this.root.generation + + " R\n/Info " + this.info.number + " " + + this.info.generation + " R\n>>\nstartxref\n" + this.xref + + "\n%%EOF\n"; + + /* write the trailer */ + writer.write(pdf); + } + + /** + * write the xref table + * + * @param writer the PrintWriter to write the xref table to + * @return the number of characters written + */ + private int outputXref(PrintWriter writer) throws IOException { + + /* remember position of xref table */ + this.xref = this.position; + + /* construct initial part of xref */ + StringBuffer pdf = new StringBuffer("xref\n0 " + (this.objectcount+1) + + "\n0000000000 65535 f \n"); + + /* loop through object numbers */ + for ( int i=1; i < this.objectcount+1; i++ ) { + + /* contruct xref entry for object */ + String padding = "0000000000"; + String x = this.location.elementAt(i-1).toString(); + String loc = padding.substring(x.length()) + x; + + /* append to xref table */ + pdf = pdf.append(loc + " 00000 n \n"); + } + + /* write the xref table and return the character length */ + writer.write(pdf.toString()); + return pdf.length(); + } + + public void setIDReferences(IDReferences idReferences){ + this.idReferences= idReferences; + } +} \ No newline at end of file -- 2.39.5