Browse Source

Preparations for supporting "PDF in PDF" (PDF file as "src" attribute for fo:external-graphic).

Changes in the PDF library:
- Support all basic PDF objects as generic classes.
- Reworked some of the PDF classes to use the new generic classes instead of writing to StringBuffers everywhere (less code, less error-prone in the long run).
- Finished Form XObject support.
- Manage Image XObjects together with Form XObjects in PDFDocument
- Tweaked the filters so externally applied filters can more easily be handled.

Changes to image package:
- Added a very simple and temporary dynamic registration for image implementations (in order to plug in external image implementations)
("temporary" since the image package redesign is still on the task list for this year)

Changes to the PDF Renderer:
- Added a PDFImageHandler interface which can be used to create arbitrary XObjects (in the case of PDF-in-PDF: Form XObjects).


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_PDF_in_PDF@563142 13f79535-47bb-0310-9956-ffa450edef68
Temp_PDF_in_PDF
Jeremias Maerki 17 years ago
parent
commit
fca2799f68
38 changed files with 1126 additions and 487 deletions
  1. 10
    2
      src/java/org/apache/fop/image/ImageFactory.java
  2. 49
    0
      src/java/org/apache/fop/image/RegisterableImageProvider.java
  3. 15
    8
      src/java/org/apache/fop/image/analyser/ImageReaderFactory.java
  4. 6
    2
      src/java/org/apache/fop/pdf/ASCII85Filter.java
  5. 6
    2
      src/java/org/apache/fop/pdf/ASCIIHexFilter.java
  6. 28
    17
      src/java/org/apache/fop/pdf/AbstractPDFStream.java
  7. 8
    4
      src/java/org/apache/fop/pdf/BitmapImage.java
  8. 3
    3
      src/java/org/apache/fop/pdf/CCFFilter.java
  9. 1
    1
      src/java/org/apache/fop/pdf/DCTFilter.java
  10. 13
    13
      src/java/org/apache/fop/pdf/FlateFilter.java
  11. 1
    1
      src/java/org/apache/fop/pdf/NullFilter.java
  12. 17
    0
      src/java/org/apache/fop/pdf/PDFArray.java
  13. 30
    10
      src/java/org/apache/fop/pdf/PDFDictionary.java
  14. 31
    10
      src/java/org/apache/fop/pdf/PDFDocument.java
  15. 1
    1
      src/java/org/apache/fop/pdf/PDFEncryptionJCE.java
  16. 1
    1
      src/java/org/apache/fop/pdf/PDFFactory.java
  17. 1
    1
      src/java/org/apache/fop/pdf/PDFFilter.java
  18. 98
    16
      src/java/org/apache/fop/pdf/PDFFilterList.java
  19. 125
    53
      src/java/org/apache/fop/pdf/PDFFormXObject.java
  20. 5
    16
      src/java/org/apache/fop/pdf/PDFICCStream.java
  21. 2
    0
      src/java/org/apache/fop/pdf/PDFImage.java
  22. 168
    0
      src/java/org/apache/fop/pdf/PDFImageXObject.java
  23. 5
    11
      src/java/org/apache/fop/pdf/PDFMetadata.java
  24. 79
    0
      src/java/org/apache/fop/pdf/PDFName.java
  25. 47
    0
      src/java/org/apache/fop/pdf/PDFNull.java
  26. 6
    2
      src/java/org/apache/fop/pdf/PDFNumber.java
  27. 5
    1
      src/java/org/apache/fop/pdf/PDFObject.java
  28. 13
    0
      src/java/org/apache/fop/pdf/PDFReference.java
  29. 1
    1
      src/java/org/apache/fop/pdf/PDFResources.java
  30. 11
    1
      src/java/org/apache/fop/pdf/PDFStream.java
  31. 6
    12
      src/java/org/apache/fop/pdf/PDFT1Stream.java
  32. 5
    11
      src/java/org/apache/fop/pdf/PDFTTFStream.java
  33. 13
    155
      src/java/org/apache/fop/pdf/PDFXObject.java
  34. 34
    30
      src/java/org/apache/fop/render/pdf/FopPDFImage.java
  35. 50
    0
      src/java/org/apache/fop/render/pdf/PDFImageHandler.java
  36. 119
    0
      src/java/org/apache/fop/render/pdf/PDFImageHandlerRegistry.java
  37. 50
    36
      src/java/org/apache/fop/render/pdf/PDFRenderer.java
  38. 63
    66
      src/java/org/apache/fop/svg/PDFGraphics2D.java

+ 10
- 2
src/java/org/apache/fop/image/ImageFactory.java View File

@@ -44,6 +44,7 @@ import org.apache.commons.logging.LogFactory;
import org.apache.fop.image.analyser.ImageReaderFactory;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.datatypes.URISpecification;
import org.apache.xmlgraphics.util.Service;

/**
* Create FopImage objects (with a configuration file - not yet implemented).
@@ -131,6 +132,14 @@ public final class ImageFactory {
imt = new ImageMimeType("image/emf");
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(emfImage);

Iterator iter = Service.providers(RegisterableImageProvider.class, true);
while (iter.hasNext()) {
RegisterableImageProvider impl = (RegisterableImageProvider)iter.next();
imt = new ImageMimeType(impl.getSupportedMimeType());
imageMimeTypes.put(imt.getMimeType(), imt);
imt.addProvider(new ImageProvider(impl.getName(), impl.getClassName()));
}
}

/**
@@ -698,5 +707,4 @@ class ImageMimeType {
providers.add(provider);
}
}
}

}

+ 49
- 0
src/java/org/apache/fop/image/RegisterableImageProvider.java View File

@@ -0,0 +1,49 @@
/*
* 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.image;

/**
* This interface is used to dynamically register FopImage implementations.
* <p>
* NOTE: Please don't rely on this interface too much. It is a temporary measure
* until the whole image package can be redesigned. The redesign will likely
* provide a different mechanism to dynamically register new implementations.
*/
public interface RegisterableImageProvider {

/**
* Returns the MIME type the implementation supports.
* @return the MIME type
*/
String getSupportedMimeType();
/**
* Returns the name of the implementation.
* @return the name
*/
String getName();
/**
* Returns the fully qualified class name for the implementing class.
* @return the class name
*/
String getClassName();

}

+ 15
- 8
src/java/org/apache/fop/image/analyser/ImageReaderFactory.java View File

@@ -20,17 +20,16 @@
package org.apache.fop.image.analyser;

// Java
import java.io.InputStream;
import java.io.IOException;
import java.util.ArrayList;

// FOP
import org.apache.fop.image.FopImage;
import org.apache.fop.apps.FOUserAgent;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.image.FopImage;
import org.apache.xmlgraphics.util.Service;

/**
* Factory for ImageReader objects.
@@ -40,8 +39,9 @@ import org.apache.commons.logging.LogFactory;
*/
public class ImageReaderFactory {

private static ArrayList formats = new ArrayList();
private static List formats = new java.util.ArrayList();

/** logger */
protected static Log log = LogFactory.getLog(ImageReaderFactory.class);

static {
@@ -52,6 +52,13 @@ public class ImageReaderFactory {
registerFormat(new TIFFReader());
registerFormat(new EPSReader());
registerFormat(new EMFReader());

//Dynamic registration of ImageReaders
Iterator iter = Service.providers(ImageReader.class, true);
while (iter.hasNext()) {
registerFormat((ImageReader)iter.next());
}
// the xml parser through batik closes the stream when finished
// so there is a workaround in the SVGReader
registerFormat(new SVGReader());

+ 6
- 2
src/java/org/apache/fop/pdf/ASCII85Filter.java View File

@@ -52,7 +52,7 @@ public class ASCII85Filter extends PDFFilter {
*
* @return always null
*/
public String getDecodeParms() {
public PDFObject getDecodeParms() {
return null;
}

@@ -60,7 +60,11 @@ public class ASCII85Filter extends PDFFilter {
* {@inheritDoc}
*/
public OutputStream applyFilter(OutputStream out) throws IOException {
return new ASCII85OutputStream(out);
if (isApplied()) {
return out;
} else {
return new ASCII85OutputStream(out);
}
}

}

+ 6
- 2
src/java/org/apache/fop/pdf/ASCIIHexFilter.java View File

@@ -51,7 +51,7 @@ public class ASCIIHexFilter extends PDFFilter {
*
* @return always null
*/
public String getDecodeParms() {
public PDFObject getDecodeParms() {
return null;
}

@@ -59,7 +59,11 @@ public class ASCIIHexFilter extends PDFFilter {
* {@inheritDoc}
*/
public OutputStream applyFilter(OutputStream out) throws IOException {
return new ASCIIHexOutputStream(out);
if (isApplied()) {
return out;
} else {
return new ASCIIHexOutputStream(out);
}
}

}

+ 28
- 17
src/java/org/apache/fop/pdf/AbstractPDFStream.java View File

@@ -28,7 +28,7 @@ import org.apache.fop.util.CloseBlockerOutputStream;
/**
* This is an abstract base class for PDF streams.
*/
public abstract class AbstractPDFStream extends PDFObject {
public abstract class AbstractPDFStream extends PDFDictionary {

/** The filters that should be applied */
private PDFFilterList filters;
@@ -64,7 +64,10 @@ public abstract class AbstractPDFStream extends PDFObject {
this.filters = new PDFFilterList();
} else {
this.filters = new PDFFilterList(getDocument().isEncryptionActive());
//this.filters = new PDFFilterList(false);
}
boolean hasFilterEntries = (get("Filter") != null);
if (hasFilterEntries) {
this.filters.setDisableAllFilters(true);
}
}
return this.filters;
@@ -118,8 +121,8 @@ public abstract class AbstractPDFStream extends PDFObject {
//Allocate a temporary buffer to find out the size of the encoded stream
final StreamCache encodedStream = StreamCacheFactory.getInstance().
createStreamCache(getSizeHint());
OutputStream filteredOutput =
getFilterList().applyFilters(encodedStream.getOutputStream());
OutputStream filteredOutput
= getFilterList().applyFilters(encodedStream.getOutputStream());
outputRawStreamData(filteredOutput);
filteredOutput.flush();
filteredOutput.close();
@@ -146,8 +149,7 @@ public abstract class AbstractPDFStream extends PDFObject {
//Stream contents
CloseBlockerOutputStream cbout = new CloseBlockerOutputStream(out);
CountingOutputStream cout = new CountingOutputStream(cbout);
OutputStream filteredOutput =
getFilterList().applyFilters(cout);
OutputStream filteredOutput = getFilterList().applyFilters(cout);
outputRawStreamData(filteredOutput);
filteredOutput.close();
refLength.setNumber(new Integer(cout.getCount()));
@@ -172,19 +174,17 @@ public abstract class AbstractPDFStream extends PDFObject {
StreamCache encodedStream = null;
PDFNumber refLength = null;
final String lengthEntry;
final Object lengthEntry;
if (getDocument().isEncodingOnTheFly()) {
refLength = new PDFNumber();
getDocumentSafely().registerObject(refLength);
lengthEntry = refLength.referencePDF();
lengthEntry = refLength;
} else {
encodedStream = encodeStream();
lengthEntry = Integer.toString(encodedStream.getSize() + 1);
lengthEntry = new Integer(encodedStream.getSize() + 1);
}
String filterEntry = getFilterList().buildFilterDictEntries();
byte[] p = encode(buildStreamDict(lengthEntry));

stream.write(p);
length += p.length;
@@ -209,12 +209,23 @@ public abstract class AbstractPDFStream extends PDFObject {
* @param lengthEntry value for the /Length entry
* @return the newly constructed dictionary
*/
protected String buildStreamDict(String lengthEntry) {
final String filterEntry = getFilterList().buildFilterDictEntries();
return (getObjectID()
+ "<< /Length " + lengthEntry + "\n"
+ filterEntry
+ "\n>>\n");
protected String buildStreamDict(Object lengthEntry) {
StringBuffer sb = new StringBuffer();
sb.append(getObjectID());
populateStreamDict(lengthEntry);
writeDictionary(sb);
return sb.toString();
}

/**
* Populates the dictionary with all necessary entries for the stream.
* Override this method if you need additional entries.
* @param lengthEntry value for the /Length entry
*/
protected void populateStreamDict(Object lengthEntry) {
put("Length", lengthEntry);
getFilterList().putFilterDictEntries(this);
}

/**

+ 8
- 4
src/java/org/apache/fop/pdf/BitmapImage.java View File

@@ -21,7 +21,6 @@ package org.apache.fop.pdf;

import java.io.IOException;
import java.io.OutputStream;
//import java.util.Map;

/**
* Bitmap image.
@@ -34,7 +33,7 @@ public class BitmapImage implements PDFImage {
private int bitsPerPixel;
private PDFDeviceColorSpace colorSpace;
private byte[] bitmaps;
private String maskRef;
private PDFReference maskRef;
private PDFColor transparent = null;
private String key;
private PDFDocument pdfDoc;
@@ -47,7 +46,7 @@ public class BitmapImage implements PDFImage {
* @param width the width of the image
* @param height the height of the image
* @param data the bitmap data
* @param mask the transparancy mask reference if any
* @param mask the transparency mask reference if any
*/
public BitmapImage(String k, int width, int height, byte[] data,
String mask) {
@@ -57,7 +56,7 @@ public class BitmapImage implements PDFImage {
this.bitsPerPixel = 8;
this.colorSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_RGB);
this.bitmaps = data;
maskRef = mask;
maskRef = new PDFReference(mask);
}

/**
@@ -170,6 +169,11 @@ public class BitmapImage implements PDFImage {
* @return the soft mask reference if any
*/
public String getSoftMask() {
return maskRef.toInlinePDFString();
}
/** {@inheritDoc} */
public PDFReference getSoftMaskReference() {
return maskRef;
}


+ 3
- 3
src/java/org/apache/fop/pdf/CCFFilter.java View File

@@ -28,7 +28,7 @@ package org.apache.fop.pdf;
*/
public class CCFFilter extends NullFilter {

private String decodeParms;
private PDFObject decodeParms;

/**
* {@inheritDoc}
@@ -40,7 +40,7 @@ public class CCFFilter extends NullFilter {
/**
* {@inheritDoc}
*/
public String getDecodeParms() {
public PDFObject getDecodeParms() {
return this.decodeParms;
}

@@ -48,7 +48,7 @@ public class CCFFilter extends NullFilter {
* Sets the CCF decoding parameters
* @param decodeParms The decoding parameters
*/
public void setDecodeParms(String decodeParms) {
public void setDecodeParms(PDFObject decodeParms) {
this.decodeParms = decodeParms;
}


+ 1
- 1
src/java/org/apache/fop/pdf/DCTFilter.java View File

@@ -41,7 +41,7 @@ public class DCTFilter extends NullFilter {
* Get the decode params for this filter.
* @return the DCT filter has no decode params
*/
public String getDecodeParms() {
public PDFObject getDecodeParms() {
return null;
}


+ 13
- 13
src/java/org/apache/fop/pdf/FlateFilter.java View File

@@ -94,22 +94,20 @@ public class FlateFilter extends PDFFilter {
*
* @return a string containing the decode params for this filter
*/
public String getDecodeParms() {
public PDFObject getDecodeParms() {
if (predictor > PREDICTION_NONE) {
StringBuffer sb = new StringBuffer();
sb.append("<< /Predictor ");
sb.append(predictor);
PDFDictionary dict = new PDFDictionary();
dict.put("Predictor", predictor);
if (colors > 0) {
sb.append(" /Colors " + colors);
dict.put("Colors", colors);
}
if (bitsPerComponent > 0) {
sb.append(" /BitsPerComponent " + bitsPerComponent);
dict.put("BitsPerComponent", bitsPerComponent);
}
if (columns > 0) {
sb.append(" /Columns " + columns);
dict.put("Columns", columns);
}
sb.append(" >> ");
return sb.toString();
return dict;
}
return null;
}
@@ -210,11 +208,13 @@ public class FlateFilter extends PDFFilter {
}


/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
public OutputStream applyFilter(OutputStream out) throws IOException {
return new FlateEncodeOutputStream(out);
if (isApplied()) {
return out;
} else {
return new FlateEncodeOutputStream(out);
}
}

}

+ 1
- 1
src/java/org/apache/fop/pdf/NullFilter.java View File

@@ -38,7 +38,7 @@ public class NullFilter extends PDFFilter {
/**
* {@inheritDoc}
*/
public String getDecodeParms() {
public PDFObject getDecodeParms() {
return null;
}


+ 17
- 0
src/java/org/apache/fop/pdf/PDFArray.java View File

@@ -96,6 +96,15 @@ public class PDFArray extends PDFObject {
this.values.set(index, obj);
}
/**
* Sets an entry at a given location.
* @param index the index of the value to set
* @param value the new value
*/
public void set(int index, double value) {
this.values.set(index, new Double(value));
}
/**
* Gets an entry at a given location.
* @param index the index of the value to set
@@ -113,6 +122,14 @@ public class PDFArray extends PDFObject {
this.values.add(obj);
}
/**
* Adds a new value to the array.
* @param value the value
*/
public void add(double value) {
this.values.add(new Double(value));
}
/**
* {@inheritDoc}
*/

+ 30
- 10
src/java/org/apache/fop/pdf/PDFDictionary.java View File

@@ -59,6 +59,18 @@ public class PDFDictionary extends PDFObject {
this.entries.put(name, value);
}
/**
* Puts a new name/value pair.
* @param name the name
* @param value the value
*/
public void put(String name, int value) {
if (!entries.containsKey(name)) {
this.order.add(name);
}
this.entries.put(name, new Integer(value));
}
/**
* Returns the value given a name.
* @param name the name of the value
@@ -76,21 +88,29 @@ public class PDFDictionary extends PDFObject {
if (hasObjectNumber()) {
p.append(getObjectID());
}
p.append("<<");
writeDictionary(p);
if (hasObjectNumber()) {
p.append("endobj\n");
}
return p.toString();
}

/**
* Writes the contents of the dictionary to a StringBuffer.
* @param sb the target StringBuffer
*/
protected void writeDictionary(StringBuffer sb) {
sb.append("<<");
Iterator iter = this.order.iterator();
while (iter.hasNext()) {
String key = (String)iter.next();
p.append("\n /");
p.append(key);
p.append(" ");
sb.append("\n /");
sb.append(key);
sb.append(" ");
Object obj = this.entries.get(key);
formatObject(obj, p);
formatObject(obj, sb);
}
p.append("\n>>\n");
if (hasObjectNumber()) {
p.append("endobj\n");
}
return p.toString();
sb.append("\n>>\n");
}

}

+ 31
- 10
src/java/org/apache/fop/pdf/PDFDocument.java View File

@@ -721,8 +721,20 @@ public class PDFDocument {
*
* @param key the image key to look for
* @return the image or PDFXObject for the key if found
* @deprecated Use getXObject instead (so forms are treated in the same way)
*/
public PDFXObject getImage(String key) {
public PDFImageXObject getImage(String key) {
PDFImageXObject xObject = (PDFImageXObject)xObjectsMap.get(key);
return xObject;
}

/**
* Get an XObject from the image map.
*
* @param key the XObject key to look for
* @return the PDFXObject for the key if found
*/
public PDFXObject getXObject(String key) {
PDFXObject xObject = (PDFXObject)xObjectsMap.get(key);
return xObject;
}
@@ -779,10 +791,10 @@ public class PDFDocument {
* @param img the PDF image to add
* @return the PDF XObject that references the PDF image data
*/
public PDFXObject addImage(PDFResourceContext res, PDFImage img) {
public PDFImageXObject addImage(PDFResourceContext res, PDFImage img) {
// check if already created
String key = img.getKey();
PDFXObject xObject = (PDFXObject)xObjectsMap.get(key);
PDFImageXObject xObject = (PDFImageXObject)xObjectsMap.get(key);
if (xObject != null) {
if (res != null) {
res.getPDFResources().addXObject(xObject);
@@ -793,7 +805,7 @@ public class PDFDocument {
// setup image
img.setup(this);
// create a new XObject
xObject = new PDFXObject(++this.xObjectCount, img);
xObject = new PDFImageXObject(++this.xObjectCount, img);
registerObject(xObject);
this.resources.addXObject(xObject);
if (res != null) {
@@ -811,26 +823,35 @@ public class PDFDocument {
*
* @param res the PDF resource context to add to, may be null
* @param cont the PDF Stream contents of the Form XObject
* @param formres the PDF Resources for the Form XObject data
* @param formres a reference to the PDF Resources for the Form XObject data
* @param key the key for the object
* @return the PDF Form XObject that references the PDF data
*/
public PDFFormXObject addFormXObject(
PDFResourceContext res,
PDFStream cont,
PDFResources formres,
PDFReference formres,
String key) {
PDFFormXObject xObject;
xObject =
new PDFFormXObject(
// check if already created
PDFFormXObject xObject = (PDFFormXObject)xObjectsMap.get(key);
if (xObject != null) {
if (res != null) {
res.getPDFResources().addXObject(xObject);
}
return xObject;
}
xObject = new PDFFormXObject(
++this.xObjectCount,
cont,
formres.referencePDF());
formres);
registerObject(xObject);
this.resources.addXObject(xObject);
if (res != null) {
res.getPDFResources().addXObject(xObject);
}
this.xObjectsMap.put(key, xObject);
return xObject;
}


+ 1
- 1
src/java/org/apache/fop/pdf/PDFEncryptionJCE.java View File

@@ -75,7 +75,7 @@ public class PDFEncryptionJCE extends PDFObject implements PDFEncryption {
* Return a parameter dictionary for this filter, or null
* @return The parameter dictionary. In this case, null.
*/
public String getDecodeParms() {
public PDFObject getDecodeParms() {
return null;
}


+ 1
- 1
src/java/org/apache/fop/pdf/PDFFactory.java View File

@@ -1471,7 +1471,7 @@ public class PDFFactory {

/**
* Create a PDFICCStream
* @see PDFXObject
* @see PDFImageXObject
* @see org.apache.fop.image.JpegImage
* @see org.apache.fop.pdf.PDFDeviceColorSpace
* @return the new PDF ICC stream object

+ 1
- 1
src/java/org/apache/fop/pdf/PDFFilter.java View File

@@ -92,7 +92,7 @@ public abstract class PDFFilter {
*
* @return the decode params for the filter
*/
public abstract String getDecodeParms();
public abstract PDFObject getDecodeParms();

/**
* Applies a filter to an OutputStream.

+ 98
- 16
src/java/org/apache/fop/pdf/PDFFilterList.java View File

@@ -48,6 +48,8 @@ public class PDFFilterList {
private List filters = new java.util.ArrayList();

private boolean ignoreASCIIFilters = false;
private boolean disableAllFilters = false;
/**
* Default constructor.
@@ -67,6 +69,22 @@ public class PDFFilterList {
this.ignoreASCIIFilters = ignoreASCIIFilters;
}

/**
* Used to disable all filters.
* @param value true if all filters shall be disabled
*/
public void setDisableAllFilters(boolean value) {
this.disableAllFilters = value;
}
/**
* Returns true if all filters are disabled.
* @return true if all filters are disabled
*/
public boolean isDisableAllFilters() {
return this.disableAllFilters;
}
/**
* Indicates whether the filter list is already initialized.
* @return true if more there are filters present
@@ -185,21 +203,7 @@ public class PDFFilterList {
List names = new java.util.ArrayList();
List parms = new java.util.ArrayList();

// run the filters
int nonNullParams = 0;
for (int count = 0; count < filters.size(); count++) {
PDFFilter filter = (PDFFilter)filters.get(count);
// place the names in our local vector in reverse order
if (filter.getName().length() > 0) {
names.add(0, filter.getName());
if (filter.getDecodeParms() != null) {
parms.add(0, filter.getDecodeParms());
nonNullParams++;
} else {
parms.add(0, null);
}
}
}
int nonNullParams = populateNamesAndParms(names, parms);

// now build up the filter entries for the dictionary
return buildFilterEntries(names)
@@ -209,6 +213,47 @@ public class PDFFilterList {

}

/**
* Apply the filters to the data
* in the order given and add the /Filter and /DecodeParms
* entries to the stream dictionary. If the filters have already
* been applied to the data (either externally, or internally)
* then the dictionary entries added.
* @param dict the PDFDictionary to set the entries on
*/
protected void putFilterDictEntries(PDFDictionary dict) {
if (filters != null && filters.size() > 0) {
List names = new java.util.ArrayList();
List parms = new java.util.ArrayList();

populateNamesAndParms(names, parms);

// now build up the filter entries for the dictionary
putFilterEntries(dict, names);
putDecodeParams(dict, parms);
}
}
private int populateNamesAndParms(List names, List parms) {
// run the filters
int nonNullParams = 0;
for (int count = 0; count < filters.size(); count++) {
PDFFilter filter = (PDFFilter)filters.get(count);
// place the names in our local vector in reverse order
if (filter.getName().length() > 0) {
names.add(0, filter.getName());
PDFObject param = filter.getDecodeParms();
if (param != null) {
parms.add(0, param);
nonNullParams++;
} else {
parms.add(0, null);
}
}
}
return nonNullParams;
}

private String buildFilterEntries(List names) {
int filterCount = 0;
StringBuffer sb = new StringBuffer(64);
@@ -231,6 +276,23 @@ public class PDFFilterList {
}
}

private void putFilterEntries(PDFDictionary dict, List names) {
PDFArray array = new PDFArray();
for (int i = 0, c = names.size(); i < c; i++) {
final String name = (String)names.get(i);
if (name.length() > 0) {
array.add(new PDFName(name));
}
}
if (array.length() > 0) {
if (array.length() > 1) {
dict.put("Filter", array);
} else {
dict.put("Filter", array.get(0));
}
}
}
private String buildDecodeParms(List parms) {
StringBuffer sb = new StringBuffer();
boolean needParmsEntry = false;
@@ -259,6 +321,26 @@ public class PDFFilterList {
}
}

private void putDecodeParams(PDFDictionary dict, List parms) {
boolean needParmsEntry = false;
PDFArray array = new PDFArray();
for (int i = 0, c = parms.size(); i < c; i++) {
Object obj = parms.get(i);
if (obj != null) {
array.add(obj);
needParmsEntry = true;
} else {
array.add(null);
}
}
if (array.length() > 0 & needParmsEntry) {
if (array.length() > 1) {
dict.put("DecodeParams", array);
} else {
dict.put("DecodeParams", array.get(0));
}
}
}
/**
* Applies all registered filters as necessary. The method returns an
@@ -269,7 +351,7 @@ public class PDFFilterList {
*/
public OutputStream applyFilters(OutputStream stream) throws IOException {
OutputStream out = stream;
if (filters != null) {
if (filters != null && !isDisableAllFilters()) {
for (int count = filters.size() - 1; count >= 0; count--) {
PDFFilter filter = (PDFFilter)filters.get(count);
out = filter.applyFilter(out);

+ 125
- 53
src/java/org/apache/fop/pdf/PDFFormXObject.java View File

@@ -20,6 +20,8 @@
package org.apache.fop.pdf;

// Java
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.io.OutputStream;

@@ -30,79 +32,149 @@ import java.io.OutputStream;
* dictionary but a stream of image data.
*/
public class PDFFormXObject extends PDFXObject {
private PDFStream contents;
private String resRef;
private PDFReference resRef;

/**
* create a FormXObject with the given number and name and load the
* image in the object
*
* @param xnumber the pdf object X number
* @param cont the pdf stream contents
* @param ref the resource PDF reference
* @param contents the form's contents
* @param resources the resource PDF reference
*/
public PDFFormXObject(int xnumber, PDFStream cont, String ref) {
super(xnumber, null);
contents = cont;
resRef = ref;
public PDFFormXObject(int xnumber, PDFStream contents, PDFReference resources) {
super();
put("Name", new PDFName("Form" + xnumber));
this.resRef = resources;
this.contents = contents;
put("Type", new PDFName("XObject"));
put("Subtype", new PDFName("Form"));
put("FormType", new Integer(1));
setMatrix(new AffineTransform());
}

/**
* Output the form stream as PDF.
* This sets up the form XObject dictionary and adds the content
* data stream.
*
* @param stream the output stream to write the data
* @throws IOException if there is an error writing the data
* @return the length of the data written
* Sets the bounding box of the Form XObject.
* @param bbox the bounding box
*/
protected int output(OutputStream stream) throws IOException {
int length = 0;

String dictEntries = getFilterList().buildFilterDictEntries();

final StreamCache encodedStream = encodeStream();

StringBuffer sb = new StringBuffer(128);
sb.append(getObjectID());
sb.append("<</Type /XObject\n");
sb.append("/Subtype /Form\n");
sb.append("/FormType 1\n");
sb.append("/BBox [0 0 1000 1000]\n");
sb.append("/Matrix [1 0 0 1 0 0]\n");
sb.append("/Resources " + resRef + "\n");
sb.append("/Length " + (encodedStream.getSize() + 1) + "\n");

sb.append(dictEntries);
sb.append(">>\n");

// push the pdf dictionary on the writer
byte[] pdfBytes = encode(sb.toString());
stream.write(pdfBytes);
length += pdfBytes.length;

//Send encoded stream to target OutputStream
length += outputStreamData(encodedStream, stream);
encodedStream.clear(); //Encoded stream can now be discarded

pdfBytes = encode("endobj\n");
stream.write(pdfBytes);
length += pdfBytes.length;
// let it gc
// this object is retained as a reference to inserting
// the same image but the image data is no longer needed
contents = null;
return length;
public void setBBox(Rectangle2D bbox) {
PDFArray array = (PDFArray)get("BBox");
if (array == null) {
array = new PDFArray();
array.add(bbox.getX());
array.add(bbox.getY());
array.add(bbox.getWidth());
array.add(bbox.getHeight());
put("BBox", array);
} else {
array.set(0, bbox.getX());
array.set(1, bbox.getY());
array.set(2, bbox.getWidth());
array.set(3, bbox.getHeight());
}
}
/**
* Returns the bounding box.
* @return the BBox value
*/
public Rectangle2D getBBox() {
PDFArray array = (PDFArray)get("BBox");
if (array != null) {
Rectangle2D rect = new Rectangle2D.Double();
double x = ((Number)array.get(0)).doubleValue();
double y = ((Number)array.get(1)).doubleValue();
double w = ((Number)array.get(2)).doubleValue();
double h = ((Number)array.get(3)).doubleValue();
rect.setFrame(x, y, w, h);
return rect;
} else {
return null;
}
}
/**
* {@inheritDoc}
* Sets the Matrix value
* @param at the AffineTransform defining the transformation matrix
*/
public void setMatrix(AffineTransform at) {
PDFArray array = (PDFArray)get("Matrix");
double[] m = new double[6];
at.getMatrix(m);
if (array == null) {
array = new PDFArray();
array.add(m[0]);
array.add(m[1]);
array.add(m[2]);
array.add(m[3]);
array.add(m[4]);
array.add(m[5]);
put("Matrix", array);
} else {
array.set(0, m[0]);
array.set(1, m[1]);
array.set(2, m[2]);
array.set(3, m[3]);
array.set(4, m[4]);
array.set(5, m[5]);
}
}
/**
* Returns the Matrix value.
* @return the Matrix
*/
public AffineTransform getMatrix() {
PDFArray array = (PDFArray)get("Matrix");
if (array != null) {
AffineTransform at = new AffineTransform();
double m00 = ((Number)array.get(0)).doubleValue();
double m10 = ((Number)array.get(1)).doubleValue();
double m01 = ((Number)array.get(2)).doubleValue();
double m11 = ((Number)array.get(3)).doubleValue();
double m02 = ((Number)array.get(4)).doubleValue();
double m12 = ((Number)array.get(5)).doubleValue();
at.setTransform(m00, m10, m01, m11, m02, m12);
return at;
} else {
return null;
}
}
/**
* Used to set the contents of the PDF stream.
* @param data the contents as a byte array
* @throws IOException in case of an I/O problem
*/
public void setData(byte[] data) throws IOException {
this.contents.setData(data);
}

/** {@inheritDoc} */
protected void outputRawStreamData(OutputStream out) throws IOException {
contents.outputRawStreamData(out);
}

/** {@inheritDoc} */
protected int output(OutputStream stream) throws IOException {
final int len = super.output(stream);
//Now that the data has been written, it can be discarded.
this.contents = null;
return len;
}

/** {@inheritDoc} */
protected void populateStreamDict(Object lengthEntry) {
if (get("Matrix") == null) {
put("Matrix", new PDFArray(new int[] {1, 0, 0, 1, 0, 0}));
}
put("Resources", resRef);
super.populateStreamDict(lengthEntry);
}
}


+ 5
- 16
src/java/org/apache/fop/pdf/PDFICCStream.java View File

@@ -73,24 +73,13 @@ public class PDFICCStream extends PDFStream {
cp.write(out);
}
/**
* {@inheritDoc}
*/
protected String buildStreamDict(String lengthEntry) {
final String filterEntry = getFilterList().buildFilterDictEntries();
final StringBuffer sb = new StringBuffer(128);
sb.append(getObjectID());
sb.append("<< ");
sb.append("/N " + cp.getNumComponents());

/** {@inheritDoc} */
protected void populateStreamDict(Object lengthEntry) {
put("N", cp.getNumComponents());
if (pdfColorSpace != null) {
sb.append("\n/Alternate /" + pdfColorSpace.getName() + " ");
put("Alternate", new PDFName(pdfColorSpace.getName()));
}

sb.append("\n/Length " + lengthEntry);
sb.append("\n" + filterEntry);
sb.append("\n>>\n");
return sb.toString();
super.populateStreamDict(lengthEntry);
}

}

+ 2
- 0
src/java/org/apache/fop/pdf/PDFImage.java View File

@@ -109,6 +109,8 @@ public interface PDFImage {
* @return the PDF reference for a soft mask image
*/
String getSoftMask();
PDFReference getSoftMaskReference();

/** @return true for CMYK images generated by Adobe Photoshop */
boolean isInverted();

+ 168
- 0
src/java/org/apache/fop/pdf/PDFImageXObject.java View File

@@ -0,0 +1,168 @@
/*
* 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;

// Java
import java.io.IOException;
import java.io.OutputStream;

/* modified by JKT to integrate with 0.12.0 */
/* modified by Eric SCHAEFFER to integrate with 0.13.0 */

/**
* PDF XObject
*
* A derivative of the PDF Object, is a PDF Stream that has not only a
* dictionary but a stream of image data.
* The dictionary just provides information like the stream length.
* This outputs the image dictionary and the image data.
* This is used as a reference for inserting the same image in the
* document in another place.
*/
public class PDFImageXObject extends PDFXObject {
private PDFImage pdfimage;

/**
* create an XObject with the given number and name and load the
* image in the object
*
* @param xnumber the pdf object X number
* @param img the pdf image that contains the image data
*/
public PDFImageXObject(int xnumber, PDFImage img) {
super();
put("Name", new PDFName("Im" + xnumber));
pdfimage = img;
}

/**
* Output the image as PDF.
* This sets up the image dictionary and adds the image data stream.
*
* @param stream the output stream to write the data
* @throws IOException if there is an error writing the data
* @return the length of the data written
*/
protected int output(OutputStream stream) throws IOException {
int length = super.output(stream);
// let it gc
// this object is retained as a reference to inserting
// the same image but the image data is no longer needed
pdfimage = null;
return length;
}

/** {@inheritDoc} */
protected void populateStreamDict(Object lengthEntry) {
super.populateStreamDict(lengthEntry);
if (pdfimage.isPS()) {
populateDictionaryFromPS();
} else {
populateDictionaryFromImage();
}
}
private void populateDictionaryFromPS() {
getDocumentSafely().getProfile().verifyPSXObjectsAllowed();
put("Subtype", new PDFName("PS"));
}

private void populateDictionaryFromImage() {
put("Subtype", new PDFName("Image"));
put("Width", new Integer(pdfimage.getWidth()));
put("Height", new Integer(pdfimage.getHeight()));
put("BitsPerComponent", new Integer(pdfimage.getBitsPerPixel()));

PDFICCStream pdfICCStream = pdfimage.getICCStream();
if (pdfICCStream != null) {
put("ColorSpace", new PDFArray(new Object[] {new PDFName("ICCBased"), pdfICCStream}));
} else {
PDFDeviceColorSpace cs = pdfimage.getColorSpace();
put("ColorSpace", new PDFArray(new Object[] {new PDFName("ICCBased"), cs.getName()}));
}

if (pdfimage.isInverted()) {
/* PhotoShop generates CMYK values that's inverse,
* this will invert the values - too bad if it's not
* a PhotoShop image...
*/
final Float zero = new Float(0.0f);
final Float one = new Float(1.0f);
PDFArray decode = new PDFArray();
for (int i = 0, c = pdfimage.getColorSpace().getNumComponents(); i < c; i++) {
decode.add(one);
decode.add(zero);
}
put("Decode", decode);
}

if (pdfimage.isTransparent()) {
PDFColor transp = pdfimage.getTransparentColor();
PDFArray mask = new PDFArray();
mask.add(new Integer(transp.red255()));
mask.add(new Integer(transp.red255()));
mask.add(new Integer(transp.green255()));
mask.add(new Integer(transp.green255()));
mask.add(new Integer(transp.blue255()));
mask.add(new Integer(transp.blue255()));
put("Mask", mask);
}
PDFReference ref = pdfimage.getSoftMaskReference();
if (ref != null) {
put("SMask", ref);
}
}
/** {@inheritDoc} */
protected void outputRawStreamData(OutputStream out) throws IOException {
pdfimage.outputContents(out);
}

/** {@inheritDoc} */
protected int getSizeHint() throws IOException {
return 0;
}

/** {@inheritDoc} */
protected void prepareImplicitFilters() {
PDFFilter pdfFilter = pdfimage.getPDFFilter();
if (pdfFilter != null) {
getFilterList().ensureFilterInPlace(pdfFilter);
}
}
/**
* This sets up the default filters for XObjects. It uses the PDFImage
* instance to determine what default filters to apply.
* {@inheritDoc}
*/
protected void setupFilterList() {
if (!getFilterList().isInitialized()) {
getFilterList().addDefaultFilters(
getDocumentSafely().getFilterMap(),
pdfimage.getFilterHint());
}
super.setupFilterList();
}

}

+ 5
- 11
src/java/org/apache/fop/pdf/PDFMetadata.java View File

@@ -101,24 +101,18 @@ public class PDFMetadata extends PDFStream {
}
/** {@inheritDoc} */
protected String buildStreamDict(String lengthEntry) {
protected void populateStreamDict(Object lengthEntry) {
final String filterEntry = getFilterList().buildFilterDictEntries();
if (getDocumentSafely().getProfile().getPDFAMode().isPDFA1LevelB()
&& filterEntry != null && filterEntry.length() > 0) {
throw new PDFConformanceException(
"The Filter key is prohibited when PDF/A-1 is active");
}
final StringBuffer sb = new StringBuffer(128);
sb.append(getObjectID());
sb.append("<< ");
sb.append("/Type /Metadata");
sb.append("\n/Subtype /XML");
sb.append("\n/Length " + lengthEntry);
sb.append("\n" + filterEntry);
sb.append("\n>>\n");
return sb.toString();
put("Type", new PDFName("Metadata"));
put("Subtype", new PDFName("XML"));
super.populateStreamDict(lengthEntry);
}
/**
* Creates an XMP document based on the settings on the PDF Document.
* @param pdfDoc the PDF Document

+ 79
- 0
src/java/org/apache/fop/pdf/PDFName.java View File

@@ -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;

/**
* Class representing a PDF name object.
*/
public class PDFName implements PDFWritable {
private String name;
/**
* Creates a new PDF name object.
* @param name the name value
*/
public PDFName(String name) {
this.name = escapeName(name);
}


private static String escapeName(String name) {
StringBuffer sb = new StringBuffer(Math.min(16, name.length() + 4));
if (!name.startsWith("/")) {
sb.append('/');
}
for (int i = 0, c = name.length(); i < c; i++) {
char ch = name.charAt(i);
if (ch >= 33 && ch <= 126) {
sb.append(ch);
} else {
sb.append('#');
toHex(ch, sb);
}
}
return sb.toString();
}
private static final char[] DIGITS
= {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

private static void toHex(char ch, StringBuffer sb) {
if (ch >= 256) {
throw new IllegalArgumentException(
"Only 8-bit characters allowed by this implementation");
}
sb.append(DIGITS[ch >>> 4 & 0x0F]);
sb.append(DIGITS[ch & 0x0F]);
}
/** {@inheritDoc} */
public String toInlinePDFString() {
return this.name;
}
/** {@inheritDoc} */
public String toString() {
return toInlinePDFString();
}
}

+ 47
- 0
src/java/org/apache/fop/pdf/PDFNull.java View File

@@ -0,0 +1,47 @@
/*
* 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;

/**
* Class representing a PDF name object.
*/
public final class PDFNull implements PDFWritable {
/** Instance for the "null" object. */
public static final PDFNull INSTANCE = new PDFNull();
/**
* Creates a new PDF name object.
* @param name the name value
*/
private PDFNull() {
}

/** {@inheritDoc} */
public String toInlinePDFString() {
return "null";
}
/** {@inheritDoc} */
public String toString() {
return toInlinePDFString();
}
}

+ 6
- 2
src/java/org/apache/fop/pdf/PDFNumber.java View File

@@ -111,9 +111,13 @@ public class PDFNumber extends PDFObject {
"The number of this PDFNumber must not be empty");
}
StringBuffer sb = new StringBuffer(64);
sb.append(getObjectID());
if (hasObjectNumber()) {
sb.append(getObjectID());
}
sb.append(getNumber().toString());
sb.append("\nendobj\n");
if (hasObjectNumber()) {
sb.append("\nendobj\n");
}
return sb.toString();
}


+ 5
- 1
src/java/org/apache/fop/pdf/PDFObject.java View File

@@ -251,10 +251,14 @@ public abstract class PDFObject implements PDFWritable {
* @param sb the StringBuffer to write to
*/
protected void formatObject(Object obj, StringBuffer sb) {
if (obj instanceof PDFWritable) {
if (obj == null) {
sb.append("null");
} else if (obj instanceof PDFWritable) {
sb.append(((PDFWritable)obj).toInlinePDFString());
} else if (obj instanceof Number) {
sb.append(obj);
} else if (obj instanceof Boolean) {
sb.append(obj);
} else {
sb.append("(").append(obj).append(")");
}

+ 13
- 0
src/java/org/apache/fop/pdf/PDFReference.java View File

@@ -42,6 +42,14 @@ public class PDFReference implements PDFWritable {
this.indirectReference = obj.referencePDF();
this.objReference = new SoftReference(obj);
}
/**
* Creates a new PDF reference, but without a reference to the original object.
* @param ref an object reference
*/
public PDFReference(String ref) {
this.indirectReference = ref;
}

/**
* Returns the PDF object
@@ -64,4 +72,9 @@ public class PDFReference implements PDFWritable {
return this.indirectReference;
}
/** {@inheritDoc} */
public String toString() {
return toInlinePDFString();
}
}

+ 1
- 1
src/java/org/apache/fop/pdf/PDFResources.java View File

@@ -240,7 +240,7 @@ public class PDFResources extends PDFObject {
p = p.append("/XObject <<\n");
for (Iterator iter = xObjects.iterator(); iter.hasNext();) {
PDFXObject xobj = (PDFXObject)iter.next();
p = p.append(" /Im" + xobj.getXNumber() + " "
p = p.append(" " + xobj.getName() + " "
+ xobj.referencePDF()
+ "\n");
}

+ 11
- 1
src/java/org/apache/fop/pdf/PDFStream.java View File

@@ -64,7 +64,17 @@ public class PDFStream extends AbstractPDFStream {
}

}

/**
* Returns an OutputStream that can be used to write to the buffer which is used
* to build up the PDF stream.
* @return the OutputStream
* @throws IOException In case of an I/O problem
*/
public OutputStream getBufferOutputStream() throws IOException {
return this.data.getOutputStream();
}
/**
* Used to set the contents of the PDF stream.
* @param data the contents as a byte array

+ 6
- 12
src/java/org/apache/fop/pdf/PDFT1Stream.java View File

@@ -61,18 +61,12 @@ public class PDFT1Stream extends AbstractPDFStream {
return length;
}

/**
* {@inheritDoc}
*/
protected String buildStreamDict(String lengthEntry) {
final String filterEntry = getFilterList().buildFilterDictEntries();
return (getObjectID()
+ "<< /Length " + lengthEntry
+ " /Length1 " + pfb.getLength1()
+ " /Length2 " + pfb.getLength2()
+ " /Length3 " + pfb.getLength3()
+ "\n" + filterEntry
+ "\n>>\n");
/** {@inheritDoc} */
protected void populateStreamDict(Object lengthEntry) {
super.populateStreamDict(lengthEntry);
put("Length1", new Integer(pfb.getLength1()));
put("Length2", new Integer(pfb.getLength2()));
put("Length3", new Integer(pfb.getLength3()));
}

/**

+ 5
- 11
src/java/org/apache/fop/pdf/PDFTTFStream.java View File

@@ -51,18 +51,12 @@ public class PDFTTFStream extends PDFStream {
return length;
}

/**
* {@inheritDoc}
*/
protected String buildStreamDict(String lengthEntry) {
final String filterEntry = getFilterList().buildFilterDictEntries();
return (getObjectID()
+ "<< /Length " + lengthEntry
+ " /Length1 " + origLength
+ "\n" + filterEntry
+ "\n>>\n");
/** {@inheritDoc} */
protected void populateStreamDict(Object lengthEntry) {
put("Length1", origLength);
super.populateStreamDict(lengthEntry);
}
/**
* Sets the TrueType font data.
* @param data the font payload

+ 13
- 155
src/java/org/apache/fop/pdf/PDFXObject.java View File

@@ -21,13 +21,9 @@ package org.apache.fop.pdf;

// Java
import java.io.IOException;
import java.io.OutputStream;

/* modified by JKT to integrate with 0.12.0 */
/* modified by Eric SCHAEFFER to integrate with 0.13.0 */

/**
* PDF XObject
* Abstract base class of PDF XObjects.
*
* A derivative of the PDF Object, is a PDF Stream that has not only a
* dictionary but a stream of image data.
@@ -36,170 +32,32 @@ import java.io.OutputStream;
* This is used as a reference for inserting the same image in the
* document in another place.
*/
public class PDFXObject extends AbstractPDFStream {
public abstract class PDFXObject extends AbstractPDFStream {
private PDFImage pdfimage;
private int xnum;

/**
* create an XObject with the given number and name and load the
* image in the object
*
* @param xnumber the pdf object X number
* @param img the pdf image that contains the image data
* Create an XObject with the given number.
*/
public PDFXObject(int xnumber, PDFImage img) {
public PDFXObject() {
super();
this.xnum = xnumber;
pdfimage = img;
}

/**
* Get the xnumber for this pdf object.
*
* @return the PDF XObject number
*/
public int getXNumber() {
return this.xnum;
}

/**
* Output the image as PDF.
* This sets up the image dictionary and adds the image data stream.
*
* @param stream the output stream to write the data
* @throws IOException if there is an error writing the data
* @return the length of the data written
*/
protected int output(OutputStream stream) throws IOException {
int length = super.output(stream);
// let it gc
// this object is retained as a reference to inserting
// the same image but the image data is no longer needed
pdfimage = null;
return length;
}

/**
* {@inheritDoc}
* Returns the XObject's name.
* @return the name of the XObject
*/
protected String buildStreamDict(String lengthEntry) {
String dictEntries = getFilterList().buildFilterDictEntries();
if (pdfimage.isPS()) {
return buildDictionaryFromPS(lengthEntry, dictEntries);
} else {
return buildDictionaryFromImage(lengthEntry, dictEntries);
}
public PDFName getName() {
return (PDFName)get("Name");
}
private String buildDictionaryFromPS(String lengthEntry,
String dictEntries) {
getDocumentSafely().getProfile().verifyPSXObjectsAllowed();
StringBuffer sb = new StringBuffer(128);
sb.append(getObjectID());
sb.append("<</Type /XObject\n");
sb.append("/Subtype /PS\n");
sb.append("/Length " + lengthEntry);

sb.append(dictEntries);
sb.append("\n>>\n");
return sb.toString();
}

private String buildDictionaryFromImage(String lengthEntry,
String dictEntries) {
StringBuffer sb = new StringBuffer(128);
sb.append(getObjectID());
sb.append("<</Type /XObject\n");
sb.append("/Subtype /Image\n");
sb.append("/Name /Im" + xnum + "\n");
sb.append("/Length " + lengthEntry + "\n");
sb.append("/Width " + pdfimage.getWidth() + "\n");
sb.append("/Height " + pdfimage.getHeight() + "\n");
sb.append("/BitsPerComponent " + pdfimage.getBitsPerPixel() + "\n");

PDFICCStream pdfICCStream = pdfimage.getICCStream();
if (pdfICCStream != null) {
sb.append("/ColorSpace [/ICCBased "
+ pdfICCStream.referencePDF() + "]\n");
} else {
PDFDeviceColorSpace cs = pdfimage.getColorSpace();
sb.append("/ColorSpace /" + cs.getName()
+ "\n");
}

if (pdfimage.isInverted()) {
/* PhotoShop generates CMYK values that's inverse,
* this will invert the values - too bad if it's not
* a PhotoShop image...
*/
if (pdfimage.getColorSpace().getColorSpace() == PDFDeviceColorSpace.DEVICE_CMYK) {
sb.append("/Decode [ 1.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 ]\n");
} else if (pdfimage.getColorSpace().getColorSpace() == PDFDeviceColorSpace.DEVICE_RGB) {
sb.append("/Decode [ 1.0 0.0 1.0 0.0 1.0 0.0 ]\n");
} else if (pdfimage.getColorSpace().getColorSpace() == PDFDeviceColorSpace.DEVICE_GRAY) {
sb.append("/Decode [ 1.0 0.0 ]\n");
}
}

if (pdfimage.isTransparent()) {
PDFColor transp = pdfimage.getTransparentColor();
sb.append("/Mask ["
+ transp.red255() + " "
+ transp.red255() + " "
+ transp.green255() + " "
+ transp.green255() + " "
+ transp.blue255() + " "
+ transp.blue255() + "]\n");
}
String ref = pdfimage.getSoftMask();
if (ref != null) {
sb.append("/SMask " + ref + "\n");
}

sb.append(dictEntries);
sb.append("\n>>\n");
return sb.toString();
/** {@inheritDoc} */
protected void populateStreamDict(Object lengthEntry) {
put("Type", new PDFName("XObject"));
super.populateStreamDict(lengthEntry);
}
/**
* {@inheritDoc}
*/
protected void outputRawStreamData(OutputStream out) throws IOException {
pdfimage.outputContents(out);
}

/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
protected int getSizeHint() throws IOException {
return 0;
}

/**
* {@inheritDoc}
*/
protected void prepareImplicitFilters() {
PDFFilter pdfFilter = pdfimage.getPDFFilter();
if (pdfFilter != null) {
getFilterList().ensureFilterInPlace(pdfFilter);
}
}
/**
* This sets up the default filters for XObjects. It uses the PDFImage
* instance to determine what default filters to apply.
* {@inheritDoc}
*/
protected void setupFilterList() {
if (!getFilterList().isInitialized()) {
getFilterList().addDefaultFilters(
getDocumentSafely().getFilterMap(),
pdfimage.getFilterHint());
}
super.setupFilterList();
}

}

+ 34
- 30
src/java/org/apache/fop/render/pdf/FopPDFImage.java View File

@@ -18,32 +18,32 @@
/* $Id$ */

package org.apache.fop.render.pdf;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
import java.io.IOException;
import java.io.OutputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.image.EPSImage;
import org.apache.fop.image.FopImage;
import org.apache.fop.image.TIFFImage;
import org.apache.fop.pdf.BitmapImage;
import org.apache.fop.pdf.CCFFilter;
import org.apache.fop.pdf.DCTFilter;
import org.apache.fop.pdf.PDFColor;
import org.apache.fop.pdf.PDFConformanceException;
import org.apache.fop.pdf.PDFDeviceColorSpace;
import org.apache.fop.pdf.PDFDictionary;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFFilter;
import org.apache.fop.pdf.PDFFilterList;
import org.apache.fop.pdf.PDFICCBasedColorSpace;
import org.apache.fop.pdf.PDFImage;
import org.apache.fop.pdf.PDFFilter;
import org.apache.fop.pdf.PDFICCStream;
import org.apache.fop.pdf.PDFColor;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.DCTFilter;
import org.apache.fop.pdf.CCFFilter;
import org.apache.fop.pdf.PDFDeviceColorSpace;
import org.apache.fop.pdf.PDFXObject;
import org.apache.fop.pdf.BitmapImage;
import org.apache.fop.pdf.PDFImage;
import org.apache.fop.pdf.PDFReference;
import org.apache.fop.util.ColorProfileUtil;

import org.apache.fop.image.FopImage;
import org.apache.fop.image.EPSImage;
import org.apache.fop.image.TIFFImage;

import java.io.IOException;
import java.io.OutputStream;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;

/**
* PDFImage implementation for the PDF renderer.
*/
@@ -56,7 +56,7 @@ public class FopPDFImage implements PDFImage {
private PDFICCStream pdfICCStream = null;
private PDFFilter pdfFilter = null;
private String maskRef;
private String softMaskRef;
private PDFReference softMask;
private boolean isPS = false;
private boolean isCCF = false;
private boolean isDCT = false;
@@ -104,8 +104,10 @@ public class FopPDFImage implements PDFImage {
} else if (comp == 4) {
pdfFilter = new CCFFilter();
pdfFilter.setApplied(true);
((CCFFilter)pdfFilter).setDecodeParms("<< /K -1 /Columns "
+ tiffImage.getWidth() + " >>");
PDFDictionary dict = new PDFDictionary();
dict.put("K", -1);
dict.put("Columns", tiffImage.getWidth());
((CCFFilter)pdfFilter).setDecodeParms(dict);
isCCF = true;
} else if (comp == 6) {
pdfFilter = new DCTFilter();
@@ -149,16 +151,15 @@ public class FopPDFImage implements PDFImage {
doc.getProfile().verifyTransparencyAllowed(fopImage.getOriginalURI());
//TODO Implement code to combine image with background color if transparency is not
//allowed (need BufferedImage support for that)
byte [] softMask = fopImage.getSoftMask();
if (softMask == null) {
byte [] softMaskBitmap = fopImage.getSoftMask();
if (softMaskBitmap == null) {
return;
}
BitmapImage fopimg = new BitmapImage
("Mask:" + key, fopImage.getWidth(), fopImage.getHeight(),
softMask, null);
softMaskBitmap, null);
fopimg.setColorSpace(new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_GRAY));
PDFXObject xobj = doc.addImage(null, fopimg);
softMaskRef = xobj.referencePDF();
softMask = doc.addImage(null, fopimg).makeReference();
}
if (doc.getProfile().getPDFAMode().isPDFA1LevelB()) {
if (pdfCS != null
@@ -236,13 +237,16 @@ public class FopPDFImage implements PDFImage {
return maskRef;
}

/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
public String getSoftMask() {
return softMaskRef;
return softMask.toInlinePDFString();
}

/** {@inheritDoc} */
public PDFReference getSoftMaskReference() {
return softMask;
}
/** @return true for CMYK images generated by Adobe Photoshop */
public boolean isInverted() {
return fopImage.isInverted();

+ 50
- 0
src/java/org/apache/fop/render/pdf/PDFImageHandler.java View File

@@ -0,0 +1,50 @@
/*
* 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.render.pdf;

import java.io.IOException;

import org.apache.fop.image.FopImage;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFXObject;

/**
* This interface is used for handling all sorts of image type for PDF output.
*/
public interface PDFImageHandler {

/**
* Returns the MIME type supported by this instance.
* @return the MIME type
*/
String getSupportedMimeType();
/**
* Generates the PDF objects for the given FopImage instance and returns
* the resulting XObject.
* @param image the image to be handled
* @param uri the URI of the image
* @param pdfDoc the target PDF document
* @return the generated XObject
* @throws IOException if an I/O error occurs
*/
PDFXObject generateImage(FopImage image, String uri, PDFDocument pdfDoc) throws IOException;
}

+ 119
- 0
src/java/org/apache/fop/render/pdf/PDFImageHandlerRegistry.java View File

@@ -0,0 +1,119 @@
/*
* 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.render.pdf;

import java.util.Iterator;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xmlgraphics.util.Service;

/**
* This class holds references to various image handlers used by the PDF renderer. It also
* supports automatic discovery of additional handlers available through
* the class path.
*/
public class PDFImageHandlerRegistry {

/** the logger */
private static Log log = LogFactory.getLog(PDFImageHandlerRegistry.class);
/** Map containing PDF image handlers for various MIME types */
private Map handlers = new java.util.HashMap();
/**
* Default constructor.
*/
public PDFImageHandlerRegistry() {
discoverHandlers();
}
/**
* Add an PDFImageHandler. The handler itself is inspected to find out what it supports.
* @param classname the fully qualified class name
*/
public void addHandler(String classname) {
try {
PDFImageHandler handlerInstance
= (PDFImageHandler)Class.forName(classname).newInstance();
addHandler(handlerInstance);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Could not find "
+ classname);
} catch (InstantiationException e) {
throw new IllegalArgumentException("Could not instantiate "
+ classname);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("Could not access "
+ classname);
} catch (ClassCastException e) {
throw new IllegalArgumentException(classname
+ " is not an "
+ PDFImageHandler.class.getName());
}
}
/**
* Add an image handler. The handler itself is inspected to find out what it supports.
* @param handler the PDFImageHandler instance
*/
public void addHandler(PDFImageHandler handler) {
String mime = handler.getSupportedMimeType();
handlers.put(mime, handler);
}
/**
* Returns an PDFImageHandler which handles an specific image type given the MIME type
* of the image.
* @param mime the requested MIME type
* @return the PDFImageHandler responsible for handling the image or null if none is available
*/
public PDFImageHandler getHandler(String mime) {
PDFImageHandler handler;

handler = (PDFImageHandler)handlers.get(mime);
return handler;
}

/**
* Discovers PDFImageHandler implementations through the classpath and dynamically
* registers them.
*/
private void discoverHandlers() {
// add mappings from available services
Iterator providers = Service.providers(PDFImageHandler.class);
if (providers != null) {
while (providers.hasNext()) {
PDFImageHandler handler = (PDFImageHandler)providers.next();
try {
if (log.isDebugEnabled()) {
log.debug("Dynamically adding PDFImageHandler: "
+ handler.getClass().getName());
}
addHandler(handler);
} catch (IllegalArgumentException e) {
log.error("Error while adding PDFImageHandler", e);
}

}
}
}
}

+ 50
- 36
src/java/org/apache/fop/render/pdf/PDFRenderer.java View File

@@ -20,58 +20,56 @@
package org.apache.fop.render.pdf;

// Java
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.awt.geom.Point2D;
import java.awt.Color;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.geom.Rectangle2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Iterator;
import java.util.Map;
import java.util.List;
import java.util.Map;

import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;

// XML
import org.w3c.dom.Document;

// Avalon
import org.apache.commons.io.IOUtils;

// FOP
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.area.BookmarkData;
import org.apache.fop.area.CTM;
import org.apache.fop.area.DestinationData;
import org.apache.fop.area.LineArea;
import org.apache.fop.area.OffDocumentExtensionAttachment;
import org.apache.fop.area.OffDocumentItem;
import org.apache.fop.area.PageViewport;
import org.apache.fop.area.RegionViewport;
import org.apache.fop.area.Trait;
import org.apache.fop.area.OffDocumentItem;
import org.apache.fop.area.BookmarkData;
import org.apache.fop.area.inline.AbstractTextArea;
import org.apache.fop.area.inline.TextArea;
import org.apache.fop.area.inline.Image;
import org.apache.fop.area.inline.Leader;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.InlineParent;
import org.apache.fop.area.inline.WordArea;
import org.apache.fop.area.inline.Leader;
import org.apache.fop.area.inline.SpaceArea;
import org.apache.fop.fonts.Typeface;
import org.apache.fop.area.inline.TextArea;
import org.apache.fop.area.inline.WordArea;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.extensions.ExtensionAttachment;
import org.apache.fop.fo.extensions.xmp.XMPMetadata;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.Typeface;
import org.apache.fop.image.FopImage;
import org.apache.fop.image.ImageFactory;
import org.apache.fop.image.XMLImage;
import org.apache.fop.pdf.PDFAction;
import org.apache.fop.pdf.PDFAMode;
import org.apache.fop.pdf.PDFAction;
import org.apache.fop.pdf.PDFAnnotList;
import org.apache.fop.pdf.PDFColor;
import org.apache.fop.pdf.PDFConformanceException;
@@ -102,14 +100,10 @@ import org.apache.fop.render.Graphics2DAdapter;
import org.apache.fop.render.RendererContext;
import org.apache.fop.util.CharUtilities;
import org.apache.fop.util.ColorProfileUtil;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.extensions.ExtensionAttachment;
import org.apache.fop.fo.extensions.xmp.XMPMetadata;
import org.apache.xmlgraphics.xmp.Metadata;
import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter;
import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema;

import org.apache.fop.area.DestinationData;
import org.w3c.dom.Document;

/**
* Renderer that renders areas to PDF.
@@ -256,6 +250,9 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
*/
protected boolean inTextMode = false;

/** Image handler registry */
private PDFImageHandlerRegistry imageHandlerRegistry = new PDFImageHandlerRegistry();
/**
* create the PDF renderer
*/
@@ -1659,21 +1656,21 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
}
/**
* Adds a PDF XObject (a bitmap) to the PDF that will later be referenced.
* Adds a PDF XObject (a bitmap or form) to the PDF that will later be referenced.
* @param url URL of the bitmap
* @param pos Position of the bitmap
*/
protected void putImage(String url, Rectangle2D pos) {
PDFXObject xobject = pdfDoc.getImage(url);
url = ImageFactory.getURL(url);
PDFXObject xobject = pdfDoc.getXObject(url);
if (xobject != null) {
float w = (float) pos.getWidth() / 1000f;
float h = (float) pos.getHeight() / 1000f;
placeImage((float)pos.getX() / 1000f,
(float)pos.getY() / 1000f, w, h, xobject.getXNumber());
(float)pos.getY() / 1000f, w, h, xobject);
return;
}

url = ImageFactory.getURL(url);
ImageFactory fact = userAgent.getFactory().getImageFactory();
FopImage fopimage = fact.getImage(url, userAgent);
if (fopimage == null) {
@@ -1683,7 +1680,24 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
return;
}
String mime = fopimage.getMimeType();
if ("text/xml".equals(mime)) {
//First check for a dynamically registered handler
PDFImageHandler handler = imageHandlerRegistry.getHandler(mime);
if (handler != null) {
PDFXObject xobj;
try {
xobj = handler.generateImage(fopimage, url, pdfDoc);
} catch (IOException ioe) {
log.error("I/O error while handling " + mime + " image", ioe);
return;
}
fact.releaseImage(url, userAgent);
float w = (float)pos.getWidth() / 1000f;
float h = (float)pos.getHeight() / 1000f;
placeImage((float) pos.getX() / 1000,
(float) pos.getY() / 1000, w, h, xobj);
} else if ("text/xml".equals(mime)) {
if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
return;
}
@@ -1701,7 +1715,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
renderDocument(doc, ns, pos, null);
} else if ("image/eps".equals(mime)) {
FopPDFImage pdfimage = new FopPDFImage(fopimage, url);
int xobj = pdfDoc.addImage(currentContext, pdfimage).getXNumber();
PDFXObject xobj = pdfDoc.addImage(currentContext, pdfimage);
fact.releaseImage(url, userAgent);
float w = (float)pos.getWidth() / 1000f;
@@ -1710,7 +1724,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
(float) pos.getY() / 1000, w, h, xobj);
} else if ("image/jpeg".equals(mime) || "image/tiff".equals(mime)) {
FopPDFImage pdfimage = new FopPDFImage(fopimage, url);
int xobj = pdfDoc.addImage(currentContext, pdfimage).getXNumber();
PDFXObject xobj = pdfDoc.addImage(currentContext, pdfimage);
fact.releaseImage(url, userAgent);

float w = (float)pos.getWidth() / 1000f;
@@ -1722,7 +1736,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
return;
}
FopPDFImage pdfimage = new FopPDFImage(fopimage, url);
int xobj = pdfDoc.addImage(currentContext, pdfimage).getXNumber();
PDFXObject xobj = pdfDoc.addImage(currentContext, pdfimage);
fact.releaseImage(url, userAgent);

float w = (float) pos.getWidth() / 1000f;
@@ -1745,15 +1759,15 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
* @param y Y coordinate
* @param w width for image
* @param h height for image
* @param xobj object number of the referenced image
* @param xobj the image XObject
*/
protected void placeImage(float x, float y, float w, float h, int xobj) {
protected void placeImage(float x, float y, float w, float h, PDFXObject xobj) {
saveGraphicsState();
currentStream.add(format(w) + " 0 0 "
+ format(-h) + " "
+ format(currentIPPosition / 1000f + x) + " "
+ format(currentBPPosition / 1000f + h + y)
+ " cm\n" + "/Im" + xobj + " Do\n");
+ " cm\n" + xobj.getName() + " Do\n");
restoreGraphicsState();
}


+ 63
- 66
src/java/org/apache/fop/svg/PDFGraphics2D.java View File

@@ -19,80 +19,77 @@

package org.apache.fop.svg;

import org.apache.fop.pdf.PDFConformanceException;
import org.apache.fop.pdf.PDFResourceContext;
import org.apache.fop.pdf.PDFResources;
import org.apache.fop.pdf.PDFGState;
import org.apache.fop.pdf.PDFDeviceColorSpace;
import org.apache.fop.pdf.PDFColor;
import org.apache.fop.pdf.PDFState;
import org.apache.fop.pdf.PDFNumber;
import org.apache.fop.pdf.PDFText;
import org.apache.fop.pdf.PDFXObject;
import org.apache.fop.pdf.PDFPattern;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFLink;
import org.apache.fop.pdf.PDFAnnotList;
import org.apache.fop.pdf.BitmapImage;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontSetup;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.LazyFont;
import org.apache.fop.image.JpegImage;
import org.apache.fop.fonts.CIDFont;
import org.apache.fop.render.pdf.FopPDFImage;
import org.apache.fop.util.ColorExt;

import org.apache.xmlgraphics.java2d.AbstractGraphics2D;
import org.apache.xmlgraphics.java2d.GraphicContext;

import org.apache.batik.ext.awt.RadialGradientPaint;
import org.apache.batik.ext.awt.LinearGradientPaint;
import org.apache.batik.ext.awt.MultipleGradientPaint;
import org.apache.batik.ext.awt.RenderingHintsKeyExt;
import org.apache.batik.gvt.PatternPaint;
import org.apache.batik.gvt.GraphicsNode;

import java.text.AttributedCharacterIterator;
import java.text.CharacterIterator;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.GraphicsConfiguration;
/* java.awt.Font is not imported to avoid confusion with
org.apache.fop.fonts.Font */
import java.awt.GradientPaint;
import java.awt.Image;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.Paint;
import java.awt.PaintContext;
import java.awt.Rectangle;
import java.awt.Dimension;
import java.awt.BasicStroke;
import java.awt.AlphaComposite;
import java.awt.geom.AffineTransform;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DirectColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;
import java.awt.image.DirectColorModel;
import java.awt.image.ImageObserver;
import java.awt.image.RenderedImage;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
import java.awt.image.renderable.RenderableImage;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.StringWriter;
import java.io.IOException;
import java.io.OutputStream;

import java.util.Map;
import java.io.StringWriter;
import java.text.AttributedCharacterIterator;
import java.text.CharacterIterator;
import java.util.List;
import java.util.Map;

import org.apache.batik.ext.awt.LinearGradientPaint;
import org.apache.batik.ext.awt.MultipleGradientPaint;
import org.apache.batik.ext.awt.RadialGradientPaint;
import org.apache.batik.ext.awt.RenderingHintsKeyExt;
import org.apache.batik.gvt.GraphicsNode;
import org.apache.batik.gvt.PatternPaint;
import org.apache.fop.fonts.CIDFont;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontSetup;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.LazyFont;
import org.apache.fop.image.JpegImage;
import org.apache.fop.pdf.BitmapImage;
import org.apache.fop.pdf.PDFAnnotList;
import org.apache.fop.pdf.PDFColor;
import org.apache.fop.pdf.PDFConformanceException;
import org.apache.fop.pdf.PDFDeviceColorSpace;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFGState;
import org.apache.fop.pdf.PDFImageXObject;
import org.apache.fop.pdf.PDFLink;
import org.apache.fop.pdf.PDFName;
import org.apache.fop.pdf.PDFNumber;
import org.apache.fop.pdf.PDFPattern;
import org.apache.fop.pdf.PDFResourceContext;
import org.apache.fop.pdf.PDFResources;
import org.apache.fop.pdf.PDFState;
import org.apache.fop.pdf.PDFText;
import org.apache.fop.pdf.PDFXObject;
import org.apache.fop.render.pdf.FopPDFImage;
import org.apache.fop.util.ColorExt;
import org.apache.xmlgraphics.java2d.AbstractGraphics2D;
import org.apache.xmlgraphics.java2d.GraphicContext;

/**
* PDF Graphics 2D.
@@ -406,8 +403,8 @@ public class PDFGraphics2D extends AbstractGraphics2D {
String key = "__AddJPEG_" + hashCode() + "_" + jpegCount[0];
jpegCount[0]++;
FopPDFImage fopimage = new FopPDFImage(jpeg, key);
int xObjectNum = this.pdfDoc.addImage(resourceContext,
fopimage).getXNumber();
PDFName imageName = this.pdfDoc.addImage(resourceContext,
fopimage).getName();
AffineTransform at = getTransform();
double[] matrix = new double[6];
at.getMatrix(matrix);
@@ -421,8 +418,8 @@ public class PDFGraphics2D extends AbstractGraphics2D {
currentStream.write("" + width + " 0 0 "
+ (-height) + " "
+ x + " "
+ (y + height) + " cm\n" + "/Im"
+ xObjectNum + " Do\nQ\n");
+ (y + height) + " cm\n"
+ imageName + " Do\nQ\n");

if (outputStream != null) {
try {
@@ -518,7 +515,7 @@ public class PDFGraphics2D extends AbstractGraphics2D {
// the pdf document. If so, we just reuse the reference;
// otherwise we have to build a FopImage and add it to the pdf
// document
PDFXObject imageInfo = pdfDoc.getImage("TempImage:" + img.toString());
PDFXObject imageInfo = pdfDoc.getXObject("TempImage:" + img.toString());
if (imageInfo == null) {
// OK, have to build and add a PDF image

@@ -579,7 +576,7 @@ public class PDFGraphics2D extends AbstractGraphics2D {
+ img.toString(), buf.getWidth(),
buf.getHeight(), mask, null);
fopimg.setColorSpace(new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_GRAY));
PDFXObject xobj = pdfDoc.addImage(resourceContext, fopimg);
PDFImageXObject xobj = pdfDoc.addImage(resourceContext, fopimg);
ref = xobj.referencePDF();

if (outputStream != null) {
@@ -623,7 +620,7 @@ public class PDFGraphics2D extends AbstractGraphics2D {
writeClip(imclip);
currentStream.write("" + width + " 0 0 " + (-height) + " " + x
+ " " + (y + height) + " cm\n" + "/Im"
+ imageInfo.getXNumber() + " Do\nQ\n");
+ imageInfo.getName() + " Do\nQ\n");
return true;
}

@@ -1193,7 +1190,7 @@ public class PDFGraphics2D extends AbstractGraphics2D {

PaintContext pctx = paint.createContext(rgbCM, devBounds, usrBounds,
at, getRenderingHints());
PDFXObject imageInfo = pdfDoc.getImage
PDFXObject imageInfo = pdfDoc.getXObject
("TempImage:" + pctx.toString());
if (imageInfo != null) {
resourceContext.getPDFResources().addXObject(imageInfo);
@@ -1241,7 +1238,7 @@ public class PDFGraphics2D extends AbstractGraphics2D {
BitmapImage fopimg = new BitmapImage
("TempImageMask:" + pctx.toString(), devW, devH, mask, null);
fopimg.setColorSpace(new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_GRAY));
PDFXObject xobj = pdfDoc.addImage(resourceContext, fopimg);
PDFImageXObject xobj = pdfDoc.addImage(resourceContext, fopimg);
maskRef = xobj.referencePDF();

if (outputStream != null) {
@@ -1269,8 +1266,8 @@ public class PDFGraphics2D extends AbstractGraphics2D {
currentStream.write("q\n");
writeClip(shape);
currentStream.write("" + usrW + " 0 0 " + (-usrH) + " " + usrX
+ " " + (usrY + usrH) + " cm\n" + "/Im"
+ imageInfo.getXNumber() + " Do\nQ\n");
+ " " + (usrY + usrH) + " cm\n"
+ imageInfo.getName() + " Do\nQ\n");
return true;
}


Loading…
Cancel
Save