Browse Source

Started the IFParser.

Started a PDF painter.
Factored out common code to PDFRenderingUtil.
Smaller infrastructure changes for the new IF (like MIME type reporting).

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_AreaTreeNewDesign@678780 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-1_0
Jeremias Maerki 16 years ago
parent
commit
8091bd1121
22 changed files with 2263 additions and 516 deletions
  1. 4
    3
      src/java/org/apache/fop/render/AbstractRendererConfigurator.java
  2. 7
    6
      src/java/org/apache/fop/render/RendererFactory.java
  3. 167
    0
      src/java/org/apache/fop/render/intermediate/AbstractBinaryWritingIFPainter.java
  4. 4
    7
      src/java/org/apache/fop/render/intermediate/AbstractIFPainterMaker.java
  5. 0
    5
      src/java/org/apache/fop/render/intermediate/AbstractXMLWritingIFPainter.java
  6. 146
    0
      src/java/org/apache/fop/render/intermediate/AffineTransformArrayParser.java
  7. 7
    1
      src/java/org/apache/fop/render/intermediate/IFPainter.java
  8. 35
    0
      src/java/org/apache/fop/render/intermediate/IFPainterConfigurator.java
  9. 552
    0
      src/java/org/apache/fop/render/intermediate/IFParser.java
  10. 5
    0
      src/java/org/apache/fop/render/intermediate/IFRenderer.java
  11. 5
    0
      src/java/org/apache/fop/render/intermediate/IFSerializer.java
  12. 52
    0
      src/java/org/apache/fop/render/pdf/PDFConfigurationConstants.java
  13. 537
    0
      src/java/org/apache/fop/render/pdf/PDFPainter.java
  14. 54
    0
      src/java/org/apache/fop/render/pdf/PDFPainterMaker.java
  15. 109
    402
      src/java/org/apache/fop/render/pdf/PDFRenderer.java
  16. 94
    72
      src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java
  17. 439
    0
      src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
  18. 22
    20
      src/java/org/apache/fop/util/ConversionUtils.java
  19. 5
    0
      src/sandbox/org/apache/fop/render/svg/SVGPainter.java
  20. 7
    0
      src/sandbox/org/apache/fop/render/svg/SVGPainterMaker.java
  21. 5
    0
      src/sandbox/org/apache/fop/render/svg/SVGPrintPainter.java
  22. 7
    0
      src/sandbox/org/apache/fop/render/svg/SVGPrintPainterMaker.java

+ 4
- 3
src/java/org/apache/fop/render/AbstractRendererConfigurator.java View File

@@ -5,9 +5,9 @@
* 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.
@@ -23,6 +23,7 @@ import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.apps.FOUserAgent;

/**
@@ -68,7 +69,7 @@ public abstract class AbstractRendererConfigurator {
* @param mimeType the MIME type of the renderer
* @return the requested configuration subtree, null if there's no configuration
*/
private Configuration getRendererConfig(String mimeType) {
protected Configuration getRendererConfig(String mimeType) {
Configuration cfg = userAgent.getFactory().getUserConfig();
if (cfg == null) {
if (log.isDebugEnabled()) {

+ 7
- 6
src/java/org/apache/fop/render/RendererFactory.java View File

@@ -36,6 +36,7 @@ import org.apache.fop.area.AreaTreeHandler;
import org.apache.fop.fo.FOEventHandler;
import org.apache.fop.render.intermediate.AbstractIFPainterMaker;
import org.apache.fop.render.intermediate.IFPainter;
import org.apache.fop.render.intermediate.IFPainterConfigurator;
import org.apache.fop.render.intermediate.IFRenderer;

/**
@@ -247,7 +248,7 @@ public class RendererFactory {
if (painterMaker != null) {
IFRenderer rend = new IFRenderer();
rend.setUserAgent(userAgent);
IFPainter painter = painterMaker.makePainter(userAgent);
IFPainter painter = createPainter(userAgent, outputFormat);
rend.setPainter(painter);
return rend;
} else {
@@ -281,7 +282,9 @@ public class RendererFactory {
boolean outputStreamMissing = (userAgent.getRendererOverride() == null);
if (rendMaker == null) {
painterMaker = getPainterMaker(outputFormat);
outputStreamMissing &= (out == null) && (painterMaker.needsOutputStream());
if (painterMaker != null) {
outputStreamMissing &= (out == null) && (painterMaker.needsOutputStream());
}
} else {
outputStreamMissing &= (out == null) && (rendMaker.needsOutputStream());
}
@@ -325,12 +328,10 @@ public class RendererFactory {
}
IFPainter painter = maker.makePainter(userAgent);
painter.setUserAgent(userAgent);
//TODO Add configuration
/*
RendererConfigurator configurator = maker.getConfigurator(userAgent);
IFPainterConfigurator configurator = maker.getConfigurator(userAgent);
if (configurator != null) {
configurator.configure(painter);
}*/
}
return painter;
//}
}

+ 167
- 0
src/java/org/apache/fop/render/intermediate/AbstractBinaryWritingIFPainter.java View File

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

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.util.List;

import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

import org.apache.fop.fonts.CustomFontCollection;
import org.apache.fop.fonts.FontCollection;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontManager;
import org.apache.fop.fonts.FontResolver;
import org.apache.fop.fonts.base14.Base14FontCollection;
import org.apache.fop.render.DefaultFontResolver;

/**
* Abstract base class for binary-writing IFPainter implementations.
*/
public abstract class AbstractBinaryWritingIFPainter extends AbstractIFPainter {

/** The output stream to write the document to */
protected OutputStream outputStream;

private boolean ownOutputStream;

/** Font configuration */
protected FontInfo fontInfo;

/** Font resolver */
protected FontResolver fontResolver = null;

/** list of fonts */
protected List/*<EmbedFontInfo>*/ embedFontInfoList = null;

/** {@inheritDoc} */
public void setResult(Result result) throws IFException {
if (result instanceof StreamResult) {
StreamResult streamResult = (StreamResult)result;
OutputStream out = streamResult.getOutputStream();
if (out == null) {
if (streamResult.getWriter() != null) {
throw new IllegalArgumentException(
"FOP cannot use a Writer. Please supply an OutputStream!");
}
try {
URL url = new URL(streamResult.getSystemId());
File f = FileUtils.toFile(url);
if (f != null) {
out = new java.io.FileOutputStream(f);
} else {
out = url.openConnection().getOutputStream();
}
} catch (IOException ioe) {
throw new IFException("I/O error while opening output stream" , ioe);
}
out = new java.io.BufferedOutputStream(out);
this.ownOutputStream = true;
}
if (out == null) {
throw new IllegalArgumentException("Need a StreamResult with an OutputStream");
}
this.outputStream = out;
} else {
throw new UnsupportedOperationException(
"Unsupported Result subclass: " + result.getClass().getName());
}
}

/**
* Adds a font list to current list of fonts
* @param fontList a font info list
*/
public void addFontList(List/*<EmbedFontInfo>*/ fontList) {
if (embedFontInfoList == null) {
setFontList(fontList);
} else {
embedFontInfoList.addAll(fontList);
}
}

/**
* @param embedFontInfoList list of available fonts
*/
public void setFontList(List/*<EmbedFontInfo>*/ embedFontInfoList) {
this.embedFontInfoList = embedFontInfoList;
}

/**
* @return list of available embedded fonts
*/
public List/*<EmbedFontInfo>*/ getFontList() {
return this.embedFontInfoList;
}

/**
* Returns the {@code FontResolver} used by this painter.
* @return the font resolver
*/
public FontResolver getFontResolver() {
if (this.fontResolver == null) {
this.fontResolver = new DefaultFontResolver(getUserAgent());
}
return this.fontResolver;
}

/**
* Returns the {@code FontInfo} object.
* @return the font info
*/
public FontInfo getFontInfo() {
return this.fontInfo;
}

public void setFontInfo(FontInfo fontInfo) {
this.fontInfo = fontInfo;
}

/**
* Set up the font info
*
* @param inFontInfo font info to set up
*/
public void setupFontInfo(FontInfo inFontInfo) {
setFontInfo(inFontInfo);
FontManager fontManager = getUserAgent().getFactory().getFontManager();
FontCollection[] fontCollections = new FontCollection[] {
new Base14FontCollection(fontManager.isBase14KerningEnabled()),
new CustomFontCollection(getFontResolver(), getFontList())
};
fontManager.setup(getFontInfo(), fontCollections);
}

/** {@inheritDoc} */
public void endDocument() throws IFException {
if (this.ownOutputStream) {
IOUtils.closeQuietly(this.outputStream);
this.outputStream = null;
}
}

}

+ 4
- 7
src/java/org/apache/fop/render/intermediate/AbstractIFPainterMaker.java View File

@@ -45,15 +45,12 @@ public abstract class AbstractIFPainterMaker {
public abstract String[] getSupportedMimeTypes();

/**
* Returns a renderer config object that can be used to
* Returns a configurator object that can be used to
* configure the painter.
* @param userAgent user agent
* @return a config object that can be used to configure the painter
* @param userAgent the user agent
* @return a configurator object that can be used to configure the painter
*/
/*
public RendererConfigurator getConfigurator(FOUserAgent userAgent) {
return null;
}*/
public abstract IFPainterConfigurator getConfigurator(FOUserAgent userAgent);

/**
* Indicates whether a specific MIME type is supported by this painter.

+ 0
- 5
src/java/org/apache/fop/render/intermediate/AbstractXMLWritingIFPainter.java View File

@@ -56,11 +56,6 @@ public abstract class AbstractXMLWritingIFPainter extends AbstractIFPainter {
/** Main SAX ContentHandler to receive the generated SAX events. */
protected ContentHandler handler;

/** {@inheritDoc} */
public ContentHandler getContentHandler() {
return this.handler;
}

/** {@inheritDoc} */
public void setResult(Result result) throws IFException {
if (result instanceof SAXResult) {

+ 146
- 0
src/java/org/apache/fop/render/intermediate/AffineTransformArrayParser.java View File

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

import java.awt.geom.AffineTransform;
import java.io.Reader;
import java.util.List;

import org.apache.batik.parser.ParseException;
import org.apache.batik.parser.TransformListHandler;
import org.apache.batik.parser.TransformListParser;

/**
* This class parses a sequence of transformations into an array of {@code AffineTransform}
* instances.
*/
public class AffineTransformArrayParser implements TransformListHandler {

private List transforms;

/**
* Utility method for creating an AffineTransform array.
* @param r The reader used to read the transform specification.
* @return the AffineTransform array
* @throws ParseException if there's a parse error
*/
public static AffineTransform[] createAffineTransform(Reader r)
throws ParseException {
TransformListParser p = new TransformListParser();
AffineTransformArrayParser th = new AffineTransformArrayParser();

p.setTransformListHandler(th);
p.parse(r);

return th.getAffineTransforms();
}

/**
* Utility method for creating an AffineTransform.
* @param s The transform specification.
* @return the AffineTransform array
* @throws ParseException if there's a parse error
*/
public static AffineTransform[] createAffineTransform(String s)
throws ParseException {
TransformListParser p = new TransformListParser();
AffineTransformArrayParser th = new AffineTransformArrayParser();

p.setTransformListHandler(th);
p.parse(s);

return th.getAffineTransforms();
}

/**
* Returns the AffineTransform array initialized during the last parsing.
* @return the array or null if this handler has not been used by
* a parser.
*/
public AffineTransform[] getAffineTransforms() {
if (this.transforms == null) {
return null;
} else {
int count = this.transforms.size();
return (AffineTransform[])this.transforms.toArray(new AffineTransform[count]);
}
}

/** {@inheritDoc} */
public void startTransformList() throws ParseException {
this.transforms = new java.util.ArrayList();
}

/** {@inheritDoc} */
public void matrix(float a, float b, float c, float d, float e, float f)
throws ParseException {
this.transforms.add(new AffineTransform(a, b, c, d, e, f));
}

/** {@inheritDoc} */
public void rotate(float theta) throws ParseException {
this.transforms.add(AffineTransform.getRotateInstance(Math.toRadians(theta)));
}

/** {@inheritDoc} */
public void rotate(float theta, float cx, float cy) throws ParseException {
AffineTransform at
= AffineTransform.getRotateInstance(Math.toRadians(theta), cx, cy);
this.transforms.add(at);
}

/** {@inheritDoc} */
public void translate(float tx) throws ParseException {
AffineTransform at = AffineTransform.getTranslateInstance(tx, 0);
this.transforms.add(at);
}

/** {@inheritDoc} */
public void translate(float tx, float ty) throws ParseException {
AffineTransform at = AffineTransform.getTranslateInstance(tx, ty);
this.transforms.add(at);
}

/** {@inheritDoc} */
public void scale(float sx) throws ParseException {
this.transforms.add(AffineTransform.getScaleInstance(sx, sx));
}

/** {@inheritDoc} */
public void scale(float sx, float sy) throws ParseException {
this.transforms.add(AffineTransform.getScaleInstance(sx, sy));
}

/** {@inheritDoc} */
public void skewX(float skx) throws ParseException {
this.transforms.add
(AffineTransform.getShearInstance(Math.tan(Math.toRadians(skx)), 0));
}

/** {@inheritDoc} */
public void skewY(float sky) throws ParseException {
this.transforms.add
(AffineTransform.getShearInstance(0, Math.tan(Math.toRadians(sky))));
}

/** {@inheritDoc} */
public void endTransformList() throws ParseException {
}
}

+ 7
- 1
src/java/org/apache/fop/render/intermediate/IFPainter.java View File

@@ -96,6 +96,12 @@ public interface IFPainter {
*/
boolean supportsPagesOutOfOrder();

/**
* Returns the MIME type of the output format that is generated by this implementation.
* @return the MIME type
*/
String getMimeType();

/**
* Indicates the start of a document. This method may only be called once before any other
* event method.
@@ -141,7 +147,7 @@ public interface IFPainter {

/**
* Indicates the start of a new page.
* @param index the index of the page within the document (0-based)
* @param index the index of the page (0-based)
* @param name the page name (usually the formatted page number)
* @param size the size of the page (equivalent to the MediaBox in PDF)
* @throws IFException if an error occurs while handling this event

+ 35
- 0
src/java/org/apache/fop/render/intermediate/IFPainterConfigurator.java View File

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

import org.apache.fop.apps.FOPException;

/**
* This interface is implemented by classes that configure an {@code IFPainter} instance.
*/
public interface IFPainterConfigurator {

/**
* Configures a painter.
* @param painter the painter instance
* @throws FOPException if an error occurs while configuring the object
*/
void configure(IFPainter painter) throws FOPException;
}

+ 552
- 0
src/java/org/apache/fop/render/intermediate/IFParser.java View File

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

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.util.Map;

import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;

import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

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

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fo.ElementMappingRegistry;
import org.apache.fop.fo.expr.PropertyException;
import org.apache.fop.fo.extensions.ExtensionAttachment;
import org.apache.fop.util.ColorUtil;
import org.apache.fop.util.ContentHandlerFactory;
import org.apache.fop.util.ContentHandlerFactoryRegistry;
import org.apache.fop.util.ConversionUtils;
import org.apache.fop.util.DefaultErrorListener;

/**
* This is a parser for the intermediate format XML which converts the intermediate file into
* {@code IFPainter} events.
*/
public class IFParser implements IFConstants {

/** Logger instance */
protected static Log log = LogFactory.getLog(IFParser.class);

private static SAXTransformerFactory tFactory
= (SAXTransformerFactory)SAXTransformerFactory.newInstance();

/**
* Parses an intermediate file and paints it.
* @param src the Source instance pointing to the intermediate file
* @param painter the intermediate format painter used to process the IF events
* @param userAgent the user agent
* @throws TransformerException if an error occurs while parsing the area tree XML
*/
public void parse(Source src, IFPainter painter, FOUserAgent userAgent)
throws TransformerException {
Transformer transformer = tFactory.newTransformer();
transformer.setErrorListener(new DefaultErrorListener(log));

SAXResult res = new SAXResult(getContentHandler(painter, userAgent));

transformer.transform(src, res);
}

/**
* Creates a new ContentHandler instance that you can send the area tree XML to. The parsed
* pages are added to the AreaTreeModel instance you pass in as a parameter.
* @param painter the intermediate format painter used to process the IF events
* @param userAgent the user agent
* @return the ContentHandler instance to receive the SAX stream from the area tree XML
*/
public ContentHandler getContentHandler(IFPainter painter, FOUserAgent userAgent) {
ElementMappingRegistry elementMappingRegistry
= userAgent.getFactory().getElementMappingRegistry();
return new Handler(painter, userAgent, elementMappingRegistry);
}

private static class Handler extends DefaultHandler {

private Map elementHandlers = new java.util.HashMap();

private IFPainter painter;
private FOUserAgent userAgent;
private ElementMappingRegistry elementMappingRegistry;

private Attributes lastAttributes;

private StringBuffer content = new StringBuffer();
private boolean ignoreCharacters = true;

//private Stack delegateStack = new Stack();
private int delegateDepth;
private ContentHandler delegate;
private DOMImplementation domImplementation;


public Handler(IFPainter painter, FOUserAgent userAgent,
ElementMappingRegistry elementMappingRegistry) {
this.painter = painter;
this.userAgent = userAgent;
this.elementMappingRegistry = elementMappingRegistry;
elementHandlers.put("document", new DocumentHandler());
elementHandlers.put("header", new DocumentHeaderHandler());
elementHandlers.put("page-sequence", new PageSequenceHandler());
elementHandlers.put("page", new PageHandler());
elementHandlers.put("page-header", new PageHeaderHandler());
elementHandlers.put("content", new PageContentHandler());
elementHandlers.put("page-trailer", new PageTrailerHandler());
//Page content
elementHandlers.put("box", new BoxHandler());
elementHandlers.put("font", new FontHandler());
elementHandlers.put("text", new TextHandler());
elementHandlers.put("rect", new RectHandler());
}


/** {@inheritDoc} */
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
if (delegate != null) {
//delegateStack.push(qName);
delegateDepth++;
delegate.startElement(uri, localName, qName, attributes);
} else if (domImplementation != null) {
//domImplementation is set so we need to start a new DOM building sub-process
TransformerHandler handler;
try {
handler = tFactory.newTransformerHandler();
} catch (TransformerConfigurationException e) {
throw new SAXException("Error creating a new TransformerHandler", e);
}
Document doc = domImplementation.createDocument(uri, qName, null);
//It's easier to work with an empty document, so remove the root element
doc.removeChild(doc.getDocumentElement());
handler.setResult(new DOMResult(doc));
//Area parent = (Area)areaStack.peek();
//((ForeignObject)parent).setDocument(doc);

//activate delegate for nested foreign document
domImplementation = null; //Not needed anymore now
this.delegate = handler;
//delegateStack.push(qName);
delegateDepth++;
delegate.startDocument();
delegate.startElement(uri, localName, qName, attributes);
} else {
lastAttributes = attributes;
boolean handled = true;
if (NAMESPACE.equals(uri)) {
ElementHandler elementHandler = (ElementHandler)elementHandlers.get(localName);
content.setLength(0);
ignoreCharacters = true;
if (elementHandler != null) {
ignoreCharacters = elementHandler.ignoreCharacters();
try {
elementHandler.startElement(attributes);
} catch (IFException ife) {
handleIFException(ife);
}
} else if ("extension-attachments".equals(localName)) {
//TODO implement me
} else {
handled = false;
}
} else {
ContentHandlerFactoryRegistry registry
= userAgent.getFactory().getContentHandlerFactoryRegistry();
ContentHandlerFactory factory = registry.getFactory(uri);
if (factory != null) {
delegate = factory.createContentHandler();
//delegateStack.push(qName);
delegateDepth++;
delegate.startDocument();
delegate.startElement(uri, localName, qName, attributes);
} else {
handled = false;
}
}
if (!handled) {
if (uri == null || uri.length() == 0) {
throw new SAXException("Unhandled element " + localName
+ " in namespace: " + uri);
} else {
log.warn("Unhandled element " + localName
+ " in namespace: " + uri);
}
}
}
}

private void handleIFException(IFException ife) throws SAXException {
if (ife.getCause() instanceof SAXException) {
//unwrap
throw (SAXException)ife.getCause();
} else {
//wrap
throw new SAXException(ife);
}
}


/** {@inheritDoc} */
public void endElement(String uri, String localName, String qName) throws SAXException {
if (delegate != null) {
delegate.endElement(uri, localName, qName);
//delegateStack.pop();
delegateDepth--;
if (delegateDepth == 0) {
delegate.endDocument();
if (delegate instanceof ContentHandlerFactory.ObjectSource) {
Object obj = ((ContentHandlerFactory.ObjectSource)delegate).getObject();
handleExternallyGeneratedObject(obj);
}
delegate = null; //Sub-document is processed, return to normal processing
}
} else {
if (NAMESPACE.equals(uri)) {
ElementHandler elementHandler = (ElementHandler)elementHandlers.get(localName);
if (elementHandler != null) {
try {
elementHandler.endElement();
} catch (IFException ife) {
handleIFException(ife);
}
content.setLength(0);
}
ignoreCharacters = true;
} else {
//log.debug("Ignoring " + localName + " in namespace: " + uri);
}
}
}

// ============== Element handlers for the intermediate format =============

private static interface ElementHandler {
void startElement(Attributes attributes) throws IFException, SAXException;
void endElement() throws IFException;
boolean ignoreCharacters();
}

private abstract class AbstractElementHandler implements ElementHandler {

public void startElement(Attributes attributes) throws IFException, SAXException {
//nop
}

public void endElement() throws IFException {
//nop
}

public boolean ignoreCharacters() {
return true;
}
}

private class DocumentHandler extends AbstractElementHandler {

public void startElement(Attributes attributes) throws IFException {
painter.startDocument();
}

public void endElement() throws IFException {
painter.endDocument();
}

}

private class DocumentHeaderHandler extends AbstractElementHandler {

public void startElement(Attributes attributes) throws IFException {
painter.startDocumentHeader();
}

public void endElement() throws IFException {
painter.endDocumentHeader();
}

}

private class PageSequenceHandler extends AbstractElementHandler {

public void startElement(Attributes attributes) throws IFException {
String id = attributes.getValue("id");
painter.startPageSequence(id);
}

public void endElement() throws IFException {
painter.endPageSequence();
}

}

private class PageHandler extends AbstractElementHandler {

public void startElement(Attributes attributes) throws IFException {
int index = Integer.parseInt(attributes.getValue("index"));
String name = attributes.getValue("name");
int width = Integer.parseInt(attributes.getValue("width"));
int height = Integer.parseInt(attributes.getValue("height"));
painter.startPage(index, name, new Dimension(width, height));
}

public void endElement() throws IFException {
painter.endPage();
}

}

private class PageHeaderHandler extends AbstractElementHandler {

public void startElement(Attributes attributes) throws IFException {
painter.startPageHeader();
}

public void endElement() throws IFException {
painter.endPageHeader();
}

}

private class PageContentHandler extends AbstractElementHandler {

public void startElement(Attributes attributes) throws IFException {
painter.startPageContent();
}

public void endElement() throws IFException {
painter.endPageContent();
}

}

private class PageTrailerHandler extends AbstractElementHandler {

public void startElement(Attributes attributes) throws IFException {
painter.startPageTrailer();
}

public void endElement() throws IFException {
painter.endPageTrailer();
}

}

private class BoxHandler extends AbstractElementHandler {

public void startElement(Attributes attributes) throws IFException {
String transform = attributes.getValue("transform");
AffineTransform[] transforms
= AffineTransformArrayParser.createAffineTransform(transform);
//TODO Incomplete implementation
painter.startBox(transforms, null, false);
}

public void endElement() throws IFException {
painter.endBox();
}

}

private class FontHandler extends AbstractElementHandler {

public void startElement(Attributes attributes) throws IFException {
String family = attributes.getValue("family");
String style = attributes.getValue("style");
Integer weight = getAttributeAsInteger(attributes, "weight");
String variant = attributes.getValue("variant");
Integer size = getAttributeAsInteger(attributes, "size");
Color color;
try {
color = getAttributeAsColor(attributes, "color");
} catch (PropertyException pe) {
throw new IFException("Error parsing the color attribute", pe);
}
painter.setFont(family, style, weight, variant, size, color);
}

}

private class TextHandler extends AbstractElementHandler {

public void endElement() throws IFException {
int x = Integer.parseInt(lastAttributes.getValue("x"));
int y = Integer.parseInt(lastAttributes.getValue("y"));
int[] dx = getAttributeAsIntArray(lastAttributes, "dx");
int[] dy = getAttributeAsIntArray(lastAttributes, "dy");
painter.drawText(x, y, dx, dy, content.toString());
}

public boolean ignoreCharacters() {
return false;
}

}

private class RectHandler extends AbstractElementHandler {

public void startElement(Attributes attributes) throws IFException {
int x = Integer.parseInt(lastAttributes.getValue("x"));
int y = Integer.parseInt(lastAttributes.getValue("y"));
int width = Integer.parseInt(lastAttributes.getValue("width"));
int height = Integer.parseInt(lastAttributes.getValue("height"));
Color fillColor;
try {
fillColor = getAttributeAsColor(attributes, "fill");
} catch (PropertyException pe) {
throw new IFException("Error parsing the fill attribute", pe);
}
Color strokeColor;
try {
strokeColor = getAttributeAsColor(attributes, "stroke");
} catch (PropertyException pe) {
throw new IFException("Error parsing the stroke attribute", pe);
}
painter.drawRect(new Rectangle(x, y, width, height), fillColor, strokeColor);
}

}


// ====================================================================


private void assertObjectOfClass(Object obj, Class clazz) {
if (!clazz.isInstance(obj)) {
throw new IllegalStateException("Object is not an instance of "
+ clazz.getName() + " but of " + obj.getClass().getName());
}
}

/**
* Handles objects created by "sub-parsers" that implement the ObjectSource interface.
* An example of object handled here are ExtensionAttachments.
* @param obj the Object to be handled.
*/
protected void handleExternallyGeneratedObject(Object obj) {
if (obj instanceof ExtensionAttachment) {
ExtensionAttachment attachment = (ExtensionAttachment)obj;
//TODO Implement me
/*
if (this.currentPageViewport == null) {
this.treeModel.handleOffDocumentItem(
new OffDocumentExtensionAttachment(attachment));
} else {
this.currentPageViewport.addExtensionAttachment(attachment);
}
*/
} else {
log.warn("Don't know how to handle externally generated object: " + obj);
}
}

private static boolean getAttributeAsBoolean(Attributes attributes, String name,
boolean defaultValue) {
String s = attributes.getValue(name);
if (s == null) {
return defaultValue;
} else {
return Boolean.valueOf(s).booleanValue();
}
}

private static int getAttributeAsInteger(Attributes attributes, String name,
int defaultValue) {
String s = attributes.getValue(name);
if (s == null) {
return defaultValue;
} else {
return Integer.parseInt(s);
}
}

private static Integer getAttributeAsInteger(Attributes attributes, String name) {
String s = attributes.getValue(name);
if (s == null) {
return null;
} else {
return new Integer(s);
}
}

private Color getAttributeAsColor(Attributes attributes, String name)
throws PropertyException {
String s = attributes.getValue(name);
if (s == null) {
return null;
} else {
return ColorUtil.parseColorString(userAgent, s);
}
}

private static Rectangle2D getAttributeAsRectangle2D(Attributes attributes, String name) {
String s = attributes.getValue(name).trim();
double[] values = ConversionUtils.toDoubleArray(s, "\\s");
if (values.length != 4) {
throw new IllegalArgumentException("Rectangle must consist of 4 double values!");
}
return new Rectangle2D.Double(values[0], values[1], values[2], values[3]);
}

private static Rectangle getAttributeAsRectangle(Attributes attributes, String name) {
String s = attributes.getValue(name).trim();
int[] values = ConversionUtils.toIntArray(s, "\\s");
if (values.length != 4) {
throw new IllegalArgumentException("Rectangle must consist of 4 int values!");
}
return new Rectangle(values[0], values[1], values[2], values[3]);
}

private static int[] getAttributeAsIntArray(Attributes attributes, String name) {
String s = attributes.getValue(name);
if (s == null) {
return null;
} else {
return ConversionUtils.toIntArray(s.trim(), "\\s");
}
}

/** {@inheritDoc} */
public void characters(char[] ch, int start, int length) throws SAXException {
if (delegate != null) {
delegate.characters(ch, start, length);
} else if (!ignoreCharacters) {
this.content.append(ch, start, length);
}
}
}
}

+ 5
- 0
src/java/org/apache/fop/render/intermediate/IFRenderer.java View File

@@ -121,6 +121,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
public void setupFontInfo(FontInfo inFontInfo) {
if (mimic != null) {
mimic.setupFontInfo(inFontInfo);
this.fontInfo = inFontInfo;
} else {
super.setupFontInfo(inFontInfo);
}
@@ -164,6 +165,10 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
this.painter = new IFSerializer();
}
this.painter.setUserAgent(getUserAgent());
if (this.painter instanceof AbstractBinaryWritingIFPainter) {
//TODO THIS IS UGLY. FIX ME!!!
((AbstractBinaryWritingIFPainter)this.painter).setFontInfo(fontInfo);
}
this.painter.setResult(result);
}
super.startRenderer(null);

+ 5
- 0
src/java/org/apache/fop/render/intermediate/IFSerializer.java View File

@@ -55,6 +55,11 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst
//rendering the IF to the final format later on
}

/** {@inheritDoc} */
public String getMimeType() {
return MIME_TYPE;
}

/** {@inheritDoc} */
public void startDocument() throws IFException {
try {

+ 52
- 0
src/java/org/apache/fop/render/pdf/PDFConfigurationConstants.java View File

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

/**
* Constants used for configuring PDF output.
*/
public interface PDFConfigurationConstants {

/** PDF encryption parameter: all parameters as object, datatype: PDFEncryptionParams */
String ENCRYPTION_PARAMS = "encryption-params";
/** PDF encryption parameter: user password, datatype: String */
String USER_PASSWORD = "user-password";
/** PDF encryption parameter: owner password, datatype: String */
String OWNER_PASSWORD = "owner-password";
/** PDF encryption parameter: Forbids printing, datatype: Boolean or "true"/"false" */
String NO_PRINT = "noprint";
/** PDF encryption parameter: Forbids copying content, datatype: Boolean or "true"/"false" */
String NO_COPY_CONTENT = "nocopy";
/** PDF encryption parameter: Forbids editing content, datatype: Boolean or "true"/"false" */
String NO_EDIT_CONTENT = "noedit";
/** PDF encryption parameter: Forbids annotations, datatype: Boolean or "true"/"false" */
String NO_ANNOTATIONS = "noannotations";
/** Rendering Options key for the PDF/A mode. */
String PDF_A_MODE = "pdf-a-mode";
/** Rendering Options key for the PDF/X mode. */
String PDF_X_MODE = "pdf-x-mode";
/** Rendering Options key for the ICC profile for the output intent. */
String KEY_OUTPUT_PROFILE = "output-profile";
/**
* Rendering Options key for disabling the sRGB color space (only possible if no PDF/A or
* PDF/X profile is active).
*/
String KEY_DISABLE_SRGB_COLORSPACE = "disable-srgb-colorspace";
}

+ 537
- 0
src/java/org/apache/fop/render/pdf/PDFPainter.java View File

@@ -0,0 +1,537 @@
/*
* 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.awt.Color;
import java.awt.Dimension;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.io.IOException;
import java.util.Map;

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

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.fo.extensions.xmp.XMPMetadata;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.LazyFont;
import org.apache.fop.fonts.SingleByteFont;
import org.apache.fop.fonts.Typeface;
import org.apache.fop.pdf.PDFAnnotList;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFFilterList;
import org.apache.fop.pdf.PDFNumber;
import org.apache.fop.pdf.PDFPage;
import org.apache.fop.pdf.PDFResourceContext;
import org.apache.fop.pdf.PDFResources;
import org.apache.fop.pdf.PDFState;
import org.apache.fop.pdf.PDFStream;
import org.apache.fop.pdf.PDFTextUtil;
import org.apache.fop.render.intermediate.AbstractBinaryWritingIFPainter;
import org.apache.fop.render.intermediate.IFException;
import org.apache.fop.render.intermediate.IFState;
import org.apache.fop.util.CharUtilities;
import org.apache.fop.util.ColorUtil;

/**
* IFPainter implementation that produces PDF.
*/
public class PDFPainter extends AbstractBinaryWritingIFPainter {

/** logging instance */
private static Log log = LogFactory.getLog(PDFPainter.class);

/** Holds the intermediate format state */
protected IFState state;

/** the PDF Document being created */
protected PDFDocument pdfDoc;

/**
* Utility class which enables all sorts of features that are not directly connected to the
* normal rendering process.
*/
protected PDFRenderingUtil pdfUtil;

/** the /Resources object of the PDF document being created */
protected PDFResources pdfResources;

/** the current stream to add PDF commands to */
protected PDFStream currentStream;

/** the current annotation list to add annotations to */
protected PDFResourceContext currentContext;

/**
* Map of pages using the PageViewport as the key
* this is used for prepared pages that cannot be immediately
* rendered
*/
protected Map pages;

/** the current page to add annotations to */
protected PDFPage currentPage;

/** the current page's PDF reference string (to avoid numerous function calls) */
protected String currentPageRef;

/** drawing state */
protected PDFState currentState;

/** Text generation utility holding the current font status */
protected PDFTextUtil textutil;


/** Image handler registry */
private PDFImageHandlerRegistry imageHandlerRegistry = new PDFImageHandlerRegistry();

/**
* Default constructor.
*/
public PDFPainter() {
}

/** {@inheritDoc} */
public boolean supportsPagesOutOfOrder() {
return true;
}

/** {@inheritDoc} */
public String getMimeType() {
return MimeConstants.MIME_PDF;
}

/** {@inheritDoc} */
public void setUserAgent(FOUserAgent ua) {
super.setUserAgent(ua);
this.pdfUtil = new PDFRenderingUtil(ua);
}

PDFRenderingUtil getPDFUtil() {
return this.pdfUtil;
}

/** {@inheritDoc} */
public void startDocument() throws IFException {
try {
if (getUserAgent() == null) {
throw new IllegalStateException(
"User agent must be set before starting PDF generation");
}
if (this.outputStream == null) {
throw new IllegalStateException("OutputStream hasn't been set through setResult()");
}
this.pdfDoc = pdfUtil.setupPDFDocument(this.outputStream);
} catch (IOException e) {
throw new IFException("I/O error in startDocument()", e);
}
}

/** {@inheritDoc} */
public void startDocumentHeader() throws IFException {
}

/** {@inheritDoc} */
public void endDocumentHeader() throws IFException {
pdfUtil.generateDefaultXMPMetadata();
}

/** {@inheritDoc} */
public void endDocument() throws IFException {
try {
//finishOpenGoTos();

pdfDoc.getResources().addFonts(pdfDoc, fontInfo);
pdfDoc.outputTrailer(this.outputStream);

this.pdfDoc = null;

this.pages = null;

//pageReferences.clear();
pdfResources = null;
currentStream = null;
currentContext = null;
currentPage = null;
currentState = null;
this.textutil = null;

//idPositions.clear();
//idGoTos.clear();
} catch (IOException ioe) {
throw new IFException("I/O error in endDocument()", ioe);
}
super.endDocument();
}

/** {@inheritDoc} */
public void startPageSequence(String id) throws IFException {
//TODO page sequence title, country and language
}

/** {@inheritDoc} */
public void endPageSequence() throws IFException {
//nop
}

/** {@inheritDoc} */
public void startPage(int index, String name, Dimension size) throws IFException {
this.pdfResources = this.pdfDoc.getResources();

this.currentPage = this.pdfDoc.getFactory().makePage(
this.pdfResources,
(int)Math.round(size.getWidth() / 1000),
(int)Math.round(size.getHeight() / 1000),
index);
//pageReferences.put(new Integer(index)/*page.getKey()*/, currentPage.referencePDF());
//pvReferences.put(page.getKey(), page);

pdfUtil.generatePageLabel(index, name);

currentPageRef = currentPage.referencePDF();

currentStream = this.pdfDoc.getFactory()
.makeStream(PDFFilterList.CONTENT_FILTER, false);
this.textutil = new PDFTextUtil() {
protected void write(String code) {
currentStream.add(code);
}
};

currentState = new PDFState();
// Transform the PDF's default coordinate system (0,0 at lower left) to the PDFPainter's
AffineTransform basicPageTransform = new AffineTransform(1, 0, 0, -1, 0,
size.height);
currentState.concatenate(basicPageTransform);
currentStream.add(CTMHelper.toPDFString(basicPageTransform, true) + " cm\n");
}

/** {@inheritDoc} */
public void startPageHeader() throws IFException {
}

/** {@inheritDoc} */
public void endPageHeader() throws IFException {
}

/** {@inheritDoc} */
public void startPageContent() throws IFException {
this.state = IFState.create();
}

/** {@inheritDoc} */
public void endPageContent() throws IFException {
assert this.state.pop() == null;
}

/** {@inheritDoc} */
public void startPageTrailer() throws IFException {
}

/** {@inheritDoc} */
public void endPageTrailer() throws IFException {
}

/** {@inheritDoc} */
public void endPage() throws IFException {
try {
this.pdfDoc.registerObject(currentStream);
currentPage.setContents(currentStream);
PDFAnnotList annots = currentPage.getAnnotations();
if (annots != null) {
this.pdfDoc.addObject(annots);
}
this.pdfDoc.addObject(currentPage);
this.pdfDoc.output(this.outputStream);
this.textutil = null;
} catch (IOException ioe) {
throw new IFException("I/O error in endPage()", ioe);
}
}

/** {@inheritDoc} */
private void saveGraphicsState() {
//endTextObject();
currentState.push();
this.state = this.state.push();
currentStream.add("q\n");
}

private void restoreGraphicsState(boolean popState) {
endTextObject();
currentStream.add("Q\n");
if (popState) {
currentState.pop();
this.state = this.state.pop();
}
}

private void restoreGraphicsState() {
restoreGraphicsState(true);
}

/** {@inheritDoc} */
public void startBox(AffineTransform transform, Dimension size, boolean clip)
throws IFException {
saveGraphicsState();
currentStream.add(CTMHelper.toPDFString(transform, true) + " cm\n");
}

/** {@inheritDoc} */
public void startBox(AffineTransform[] transforms, Dimension size, boolean clip)
throws IFException {
AffineTransform at = new AffineTransform();
for (int i = 0, c = transforms.length; i < c; i++) {
at.concatenate(transforms[i]);
}
startBox(at, size, clip);
}

/** {@inheritDoc} */
public void endBox() throws IFException {
restoreGraphicsState();
}

/** {@inheritDoc} */
public void startImage(Rectangle rect) throws IFException {
// TODO Auto-generated method stub

}

/** {@inheritDoc} */
public void drawImage(String uri, Rectangle rect) throws IFException {
// TODO Auto-generated method stub

}

/** {@inheritDoc} */
public void endImage() throws IFException {
// TODO Auto-generated method stub

}

/** {@inheritDoc} */
public void addTarget(String name, int x, int y) throws IFException {
// TODO Auto-generated method stub

}

private static String toString(Paint paint) {
if (paint instanceof Color) {
return ColorUtil.colorToString((Color)paint);
} else {
throw new UnsupportedOperationException("Paint not supported: " + paint);
}
}

/**
* Formats a int value (normally coordinates in millipoints) as Strings.
* @param value the value (in millipoints)
* @return the formatted value
*/
protected static String format(int value) {
return PDFNumber.doubleOut(value / 1000f);
}

/**
* Establishes a new foreground or fill color.
* @param col the color to apply (null skips this operation)
* @param fill true to set the fill color, false for the foreground color
*/
private void updateColor(Color col, boolean fill) {
if (col == null) {
return;
}
boolean update = false;
if (fill) {
update = currentState.setBackColor(col);
} else {
update = currentState.setColor(col);
}

if (update) {
pdfUtil.setColor(col, fill, this.currentStream);
}
}

/** {@inheritDoc} */
public void drawRect(Rectangle rect, Paint fill, Color stroke) throws IFException {
if (fill == null && stroke == null) {
return;
}
endTextObject();
if (rect.width != 0 && rect.height != 0) {
if (fill != null) {
if (fill instanceof Color) {
updateColor((Color)fill, true);
} else {
throw new UnsupportedOperationException("Non-Color paints NYI");
}
}
if (stroke != null) {
throw new UnsupportedOperationException("stroke NYI");
}
StringBuffer sb = new StringBuffer();
sb.append(format(rect.x)).append(' ');
sb.append(format(rect.y)).append(' ');
sb.append(format(rect.width)).append(' ');
sb.append(format(rect.height)).append(" re");
if (fill != null) {
sb.append(" f");
}
if (stroke != null) {
sb.append(" S");
}
sb.append('\n');
currentStream.add(sb.toString());
}
}

/** Indicates the beginning of a text object. */
private void beginTextObject() {
if (!textutil.isInTextObject()) {
textutil.beginTextObject();
}
}

/** Indicates the end of a text object. */
private void endTextObject() {
if (textutil.isInTextObject()) {
textutil.endTextObject();
}
}

private Typeface getTypeface(String fontName) {
Typeface tf = (Typeface) fontInfo.getFonts().get(fontName);
if (tf instanceof LazyFont) {
tf = ((LazyFont)tf).getRealFont();
}
return tf;
}

/** {@inheritDoc} */
public void drawText(int x, int y, int[] dx, int[] dy, String text) throws IFException {
//Note: dy is currently ignored
beginTextObject();
FontTriplet triplet = new FontTriplet(
state.getFontFamily(), state.getFontStyle(), state.getFontWeight());
//TODO Ignored: state.getFontVariant()
String fontKey = fontInfo.getInternalFontKey(triplet);
int sizeMillipoints = state.getFontSize();
float fontSize = sizeMillipoints / 1000f;
updateColor(state.getTextColor(), true);

// This assumes that *all* CIDFonts use a /ToUnicode mapping
Typeface tf = getTypeface(fontKey);
SingleByteFont singleByteFont = null;
if (tf instanceof SingleByteFont) {
singleByteFont = (SingleByteFont)tf;
}
Font font = fontInfo.getFontInstance(triplet, sizeMillipoints);
String fontName = font.getFontName();

textutil.updateTf(fontKey, fontSize, tf.isMultiByte());

textutil.writeTextMatrix(new AffineTransform(1, 0, 0, -1, x / 1000f, y / 1000f));
int l = text.length();
int dxl = (dx != null ? dx.length : 0);

if (dx != null && dxl > 0 && dx[0] != 0) {
textutil.adjustGlyphTJ(dx[0] / fontSize);
}
for (int i = 0; i < l; i++) {
char orgChar = text.charAt(i);
char ch;
float glyphAdjust = 0;
if (font.hasChar(orgChar)) {
ch = font.mapChar(orgChar);
if (singleByteFont != null && singleByteFont.hasAdditionalEncodings()) {
int encoding = ch / 256;
if (encoding == 0) {
textutil.updateTf(fontName, fontSize, tf.isMultiByte());
} else {
textutil.updateTf(fontName + "_" + Integer.toString(encoding),
fontSize, tf.isMultiByte());
ch = (char)(ch % 256);
}
}
//int tls = (i < l - 1 ? parentArea.getTextLetterSpaceAdjust() : 0);
//glyphAdjust -= tls;
} else {
if (CharUtilities.isFixedWidthSpace(orgChar)) {
//Fixed width space are rendered as spaces so copy/paste works in a reader
ch = font.mapChar(CharUtilities.SPACE);
glyphAdjust = font.getCharWidth(ch) - font.getCharWidth(orgChar);
} else {
ch = font.mapChar(orgChar);
}
}
textutil.writeTJMappedChar(ch);

if (dx != null && i < dxl) {
glyphAdjust += dx[i + 1];
}

if (glyphAdjust != 0) {
textutil.adjustGlyphTJ(glyphAdjust / fontSize);
}

}
textutil.writeTJ();
}

/** {@inheritDoc} */
public void setFont(String family, String style, Integer weight, String variant, Integer size,
Color color) throws IFException {
if (family != null) {
state.setFontFamily(family);
}
if (style != null) {
state.setFontStyle(style);
}
if (weight != null) {
state.setFontWeight(weight.intValue());
}
if (variant != null) {
state.setFontVariant(variant);
}
if (size != null) {
state.setFontSize(size.intValue());
}
if (color != null) {
state.setTextColor(color);
}
}

/** {@inheritDoc} */
public void handleExtensionObject(Object extension) throws IFException {
if (extension instanceof XMPMetadata) {
pdfUtil.renderXMPMetadata((XMPMetadata)extension);
} else {
throw new UnsupportedOperationException(
"Don't know how to handle extension object: " + extension);
}
}

}

+ 54
- 0
src/java/org/apache/fop/render/pdf/PDFPainterMaker.java View File

@@ -0,0 +1,54 @@
/*
* 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 org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.render.intermediate.AbstractIFPainterMaker;
import org.apache.fop.render.intermediate.IFPainter;
import org.apache.fop.render.intermediate.IFPainterConfigurator;

/**
* Painter factory for PDF output.
*/
public class PDFPainterMaker extends AbstractIFPainterMaker {

private static final String[] MIMES = new String[] {MimeConstants.MIME_PDF};

/** {@inheritDoc} */
public IFPainter makePainter(FOUserAgent ua) {
return new PDFPainter();
}

/** {@inheritDoc} */
public boolean needsOutputStream() {
return true;
}

/** {@inheritDoc} */
public String[] getSupportedMimeTypes() {
return MIMES;
}

public IFPainterConfigurator getConfigurator(FOUserAgent userAgent) {
return new PDFRendererConfigurator(userAgent);
}

}

+ 109
- 402
src/java/org/apache/fop/render/pdf/PDFRenderer.java
File diff suppressed because it is too large
View File


+ 94
- 72
src/java/org/apache/fop/render/pdf/PDFRendererConfigurator.java View File

@@ -5,9 +5,9 @@
* 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.
@@ -33,12 +33,15 @@ import org.apache.fop.pdf.PDFFilterList;
import org.apache.fop.pdf.PDFXMode;
import org.apache.fop.render.PrintRendererConfigurator;
import org.apache.fop.render.Renderer;
import org.apache.fop.render.intermediate.IFPainter;
import org.apache.fop.render.intermediate.IFPainterConfigurator;
import org.apache.fop.util.LogUtil;

/**
* PDF renderer configurator
* PDF renderer configurator
*/
public class PDFRendererConfigurator extends PrintRendererConfigurator {
public class PDFRendererConfigurator extends PrintRendererConfigurator
implements IFPainterConfigurator {

/**
* Default constructor
@@ -59,75 +62,93 @@ public class PDFRendererConfigurator extends PrintRendererConfigurator {
Configuration cfg = super.getRendererConfig(renderer);
if (cfg != null) {
PDFRenderer pdfRenderer = (PDFRenderer)renderer;
//PDF filters
try {
Map filterMap = buildFilterMapFromConfiguration(cfg);
if (filterMap != null) {
pdfRenderer.setFilterMap(filterMap);
}
} catch (ConfigurationException e) {
LogUtil.handleException(log, e, false);
}
super.configure(renderer);
String s = cfg.getChild(PDFRenderer.PDF_A_MODE, true).getValue(null);
if (s != null) {
pdfRenderer.setAMode(PDFAMode.valueOf(s));
}
s = cfg.getChild(PDFRenderer.PDF_X_MODE, true).getValue(null);
if (s != null) {
pdfRenderer.setXMode(PDFXMode.valueOf(s));

PDFRenderingUtil pdfUtil = pdfRenderer.getPDFUtil();
configure(cfg, pdfUtil);
}
}

private void configure(Configuration cfg, PDFRenderingUtil pdfUtil) throws FOPException {
//PDF filters
try {
Map filterMap = buildFilterMapFromConfiguration(cfg);
if (filterMap != null) {
pdfUtil.setFilterMap(filterMap);
}
Configuration encryptionParamsConfig = cfg.getChild(PDFRenderer.ENCRYPTION_PARAMS, false);
if (encryptionParamsConfig != null) {
PDFEncryptionParams encryptionParams = new PDFEncryptionParams();
Configuration ownerPasswordConfig = encryptionParamsConfig.getChild(
PDFRenderer.OWNER_PASSWORD, false);
if (ownerPasswordConfig != null) {
String ownerPassword = ownerPasswordConfig.getValue(null);
if (ownerPassword != null) {
encryptionParams.setOwnerPassword(ownerPassword);
}
}
Configuration userPasswordConfig = encryptionParamsConfig.getChild(
PDFRenderer.USER_PASSWORD, false);
if (userPasswordConfig != null) {
String userPassword = userPasswordConfig.getValue(null);
if (userPassword != null) {
encryptionParams.setUserPassword(userPassword);
}
}
Configuration noPrintConfig = encryptionParamsConfig.getChild(
PDFRenderer.NO_PRINT, false);
if (noPrintConfig != null) {
encryptionParams.setAllowPrint(false);
}
Configuration noCopyContentConfig = encryptionParamsConfig.getChild(
PDFRenderer.NO_COPY_CONTENT, false);
if (noCopyContentConfig != null) {
encryptionParams.setAllowCopyContent(false);
}
Configuration noEditContentConfig = encryptionParamsConfig.getChild(
PDFRenderer.NO_EDIT_CONTENT, false);
if (noEditContentConfig != null) {
encryptionParams.setAllowEditContent(false);
} catch (ConfigurationException e) {
LogUtil.handleException(log, e, false);
}

String s = cfg.getChild(PDFRenderer.PDF_A_MODE, true).getValue(null);
if (s != null) {
pdfUtil.setAMode(PDFAMode.valueOf(s));
}
s = cfg.getChild(PDFRenderer.PDF_X_MODE, true).getValue(null);
if (s != null) {
pdfUtil.setXMode(PDFXMode.valueOf(s));
}
Configuration encryptionParamsConfig = cfg.getChild(PDFRenderer.ENCRYPTION_PARAMS, false);
if (encryptionParamsConfig != null) {
PDFEncryptionParams encryptionParams = new PDFEncryptionParams();
Configuration ownerPasswordConfig = encryptionParamsConfig.getChild(
PDFRenderer.OWNER_PASSWORD, false);
if (ownerPasswordConfig != null) {
String ownerPassword = ownerPasswordConfig.getValue(null);
if (ownerPassword != null) {
encryptionParams.setOwnerPassword(ownerPassword);
}
Configuration noAnnotationsConfig = encryptionParamsConfig.getChild(
PDFRenderer.NO_ANNOTATIONS, false);
if (noAnnotationsConfig != null) {
encryptionParams.setAllowEditAnnotations(false);
}
Configuration userPasswordConfig = encryptionParamsConfig.getChild(
PDFRenderer.USER_PASSWORD, false);
if (userPasswordConfig != null) {
String userPassword = userPasswordConfig.getValue(null);
if (userPassword != null) {
encryptionParams.setUserPassword(userPassword);
}
pdfRenderer.setEncryptionParams(encryptionParams);
}
s = cfg.getChild(PDFRenderer.KEY_OUTPUT_PROFILE, true).getValue(null);
if (s != null) {
pdfRenderer.setOutputProfileURI(s);
Configuration noPrintConfig = encryptionParamsConfig.getChild(
PDFRenderer.NO_PRINT, false);
if (noPrintConfig != null) {
encryptionParams.setAllowPrint(false);
}
Configuration noCopyContentConfig = encryptionParamsConfig.getChild(
PDFRenderer.NO_COPY_CONTENT, false);
if (noCopyContentConfig != null) {
encryptionParams.setAllowCopyContent(false);
}
Configuration noEditContentConfig = encryptionParamsConfig.getChild(
PDFRenderer.NO_EDIT_CONTENT, false);
if (noEditContentConfig != null) {
encryptionParams.setAllowEditContent(false);
}
Configuration disableColorSpaceConfig = cfg.getChild(PDFRenderer.KEY_DISABLE_SRGB_COLORSPACE, false);
if (disableColorSpaceConfig != null) {
pdfRenderer.disableSRGBColorSpace = disableColorSpaceConfig.getValueAsBoolean(false);
Configuration noAnnotationsConfig = encryptionParamsConfig.getChild(
PDFRenderer.NO_ANNOTATIONS, false);
if (noAnnotationsConfig != null) {
encryptionParams.setAllowEditAnnotations(false);
}
pdfUtil.setEncryptionParams(encryptionParams);
}
s = cfg.getChild(PDFRenderer.KEY_OUTPUT_PROFILE, true).getValue(null);
if (s != null) {
pdfUtil.setOutputProfileURI(s);
}
Configuration disableColorSpaceConfig
= cfg.getChild(PDFRenderer.KEY_DISABLE_SRGB_COLORSPACE, false);
if (disableColorSpaceConfig != null) {
pdfUtil.setDisableSRGBColorSpace(
disableColorSpaceConfig.getValueAsBoolean(false));
}
}

public void configure(IFPainter painter) throws FOPException {
Configuration cfg = super.getRendererConfig(painter.getMimeType());
if (cfg != null) {
PDFPainter pdfPainter = (PDFPainter)painter;
PDFRenderingUtil pdfUtil = pdfPainter.getPDFUtil();
configure(cfg, pdfUtil);

//TODO Configure fonts
}
}

@@ -137,7 +158,7 @@ public class PDFRendererConfigurator extends PrintRendererConfigurator {
* @return Map the newly built filter map
* @throws ConfigurationException if a filter list is defined twice
*/
public static Map buildFilterMapFromConfiguration(Configuration cfg)
public static Map buildFilterMapFromConfiguration(Configuration cfg)
throws ConfigurationException {
Map filterMap = new java.util.HashMap();
Configuration[] filterLists = cfg.getChildren("filterList");
@@ -150,11 +171,11 @@ public class PDFRendererConfigurator extends PrintRendererConfigurator {
String name = filt[j].getValue();
filterList.add(name);
}
if (type == null) {
type = PDFFilterList.DEFAULT_FILTER;
}
if (!filterList.isEmpty() && log.isDebugEnabled()) {
StringBuffer debug = new StringBuffer("Adding PDF filter");
if (filterList.size() != 1) {
@@ -169,13 +190,14 @@ public class PDFRendererConfigurator extends PrintRendererConfigurator {
}
log.debug(debug.toString());
}
if (filterMap.get(type) != null) {
throw new ConfigurationException("A filterList of type '"
throw new ConfigurationException("A filterList of type '"
+ type + "' has already been defined");
}
filterMap.put(type, filterList);
}
return filterMap;
return filterMap;
}

}

+ 439
- 0
src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java View File

@@ -0,0 +1,439 @@
/*
* 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.awt.Color;
import java.awt.color.ICC_Profile;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Map;

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

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

import org.apache.xmlgraphics.xmp.Metadata;
import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter;
import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fo.extensions.xmp.XMPMetadata;
import org.apache.fop.pdf.PDFAMode;
import org.apache.fop.pdf.PDFColor;
import org.apache.fop.pdf.PDFConformanceException;
import org.apache.fop.pdf.PDFDictionary;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFEncryptionManager;
import org.apache.fop.pdf.PDFEncryptionParams;
import org.apache.fop.pdf.PDFICCBasedColorSpace;
import org.apache.fop.pdf.PDFICCStream;
import org.apache.fop.pdf.PDFInfo;
import org.apache.fop.pdf.PDFMetadata;
import org.apache.fop.pdf.PDFNumsArray;
import org.apache.fop.pdf.PDFOutputIntent;
import org.apache.fop.pdf.PDFPageLabels;
import org.apache.fop.pdf.PDFStream;
import org.apache.fop.pdf.PDFXMode;
import org.apache.fop.util.ColorProfileUtil;

/**
* Utility class which enables all sorts of features that are not directly connected to the
* normal rendering process.
*/
class PDFRenderingUtil implements PDFConfigurationConstants {

/** logging instance */
private static Log log = LogFactory.getLog(PDFRenderingUtil.class);

private FOUserAgent userAgent;

/** the PDF Document being created */
protected PDFDocument pdfDoc;

/** the PDF/A mode (Default: disabled) */
protected PDFAMode pdfAMode = PDFAMode.DISABLED;

/** the PDF/X mode (Default: disabled) */
protected PDFXMode pdfXMode = PDFXMode.DISABLED;

/** the (optional) encryption parameters */
protected PDFEncryptionParams encryptionParams;

/** Registry of PDF filters */
protected Map filterMap;

/** the ICC stream used as output profile by this document for PDF/A and PDF/X functionality. */
protected PDFICCStream outputProfile;
/** the default sRGB color space. */
protected PDFICCBasedColorSpace sRGBColorSpace;
/** controls whether the sRGB color space should be installed */
protected boolean disableSRGBColorSpace = false;

/** Optional URI to an output profile to be used. */
protected String outputProfileURI;


PDFRenderingUtil(FOUserAgent userAgent) {
this.userAgent = userAgent;
initialize();
}

private static boolean booleanValueOf(Object obj) {
if (obj instanceof Boolean) {
return ((Boolean)obj).booleanValue();
} else if (obj instanceof String) {
return Boolean.valueOf((String)obj).booleanValue();
} else {
throw new IllegalArgumentException("Boolean or \"true\" or \"false\" expected.");
}
}

private void initialize() {
PDFEncryptionParams params
= (PDFEncryptionParams)userAgent.getRendererOptions().get(ENCRYPTION_PARAMS);
if (params != null) {
this.encryptionParams = params; //overwrite if available
}
String pwd;
pwd = (String)userAgent.getRendererOptions().get(USER_PASSWORD);
if (pwd != null) {
if (encryptionParams == null) {
this.encryptionParams = new PDFEncryptionParams();
}
this.encryptionParams.setUserPassword(pwd);
}
pwd = (String)userAgent.getRendererOptions().get(OWNER_PASSWORD);
if (pwd != null) {
if (encryptionParams == null) {
this.encryptionParams = new PDFEncryptionParams();
}
this.encryptionParams.setOwnerPassword(pwd);
}
Object setting;
setting = userAgent.getRendererOptions().get(NO_PRINT);
if (setting != null) {
if (encryptionParams == null) {
this.encryptionParams = new PDFEncryptionParams();
}
this.encryptionParams.setAllowPrint(!booleanValueOf(setting));
}
setting = userAgent.getRendererOptions().get(NO_COPY_CONTENT);
if (setting != null) {
if (encryptionParams == null) {
this.encryptionParams = new PDFEncryptionParams();
}
this.encryptionParams.setAllowCopyContent(!booleanValueOf(setting));
}
setting = userAgent.getRendererOptions().get(NO_EDIT_CONTENT);
if (setting != null) {
if (encryptionParams == null) {
this.encryptionParams = new PDFEncryptionParams();
}
this.encryptionParams.setAllowEditContent(!booleanValueOf(setting));
}
setting = userAgent.getRendererOptions().get(NO_ANNOTATIONS);
if (setting != null) {
if (encryptionParams == null) {
this.encryptionParams = new PDFEncryptionParams();
}
this.encryptionParams.setAllowEditAnnotations(!booleanValueOf(setting));
}
String s = (String)userAgent.getRendererOptions().get(PDF_A_MODE);
if (s != null) {
this.pdfAMode = PDFAMode.valueOf(s);
}
s = (String)userAgent.getRendererOptions().get(PDF_X_MODE);
if (s != null) {
this.pdfXMode = PDFXMode.valueOf(s);
}
s = (String)userAgent.getRendererOptions().get(KEY_OUTPUT_PROFILE);
if (s != null) {
this.outputProfileURI = s;
}
setting = userAgent.getRendererOptions().get(KEY_DISABLE_SRGB_COLORSPACE);
if (setting != null) {
this.disableSRGBColorSpace = booleanValueOf(setting);
}
}

public FOUserAgent getUserAgent() {
return this.userAgent;
}

/**
* Sets the PDF/A mode for the PDF renderer.
* @param mode the PDF/A mode
*/
public void setAMode(PDFAMode mode) {
this.pdfAMode = mode;
}

/**
* Sets the PDF/X mode for the PDF renderer.
* @param mode the PDF/X mode
*/
public void setXMode(PDFXMode mode) {
this.pdfXMode = mode;
}

/**
* Sets the output color profile for the PDF renderer.
* @param outputProfileURI the URI to the output color profile
*/
public void setOutputProfileURI(String outputProfileURI) {
this.outputProfileURI = outputProfileURI;
}

/**
* Enables or disables the default sRGB color space needed for the PDF document to preserve
* the sRGB colors used in XSL-FO.
* @param disable true to disable, false to enable
*/
public void setDisableSRGBColorSpace(boolean disable) {
this.disableSRGBColorSpace = disable;
}

/**
* Sets the filter map to be used by the PDF renderer.
* @param filterMap the filter map
*/
public void setFilterMap(Map filterMap) {
this.filterMap = filterMap;
}

/**
* Sets the encryption parameters used by the PDF renderer.
* @param encryptionParams the encryption parameters
*/
public void setEncryptionParams(PDFEncryptionParams encryptionParams) {
this.encryptionParams = encryptionParams;
}

private void updateInfo() {
PDFInfo info = pdfDoc.getInfo();
info.setCreator(userAgent.getCreator());
info.setCreationDate(userAgent.getCreationDate());
info.setAuthor(userAgent.getAuthor());
info.setTitle(userAgent.getTitle());
info.setKeywords(userAgent.getKeywords());
}

private void updatePDFProfiles() {
pdfDoc.getProfile().setPDFAMode(this.pdfAMode);
pdfDoc.getProfile().setPDFXMode(this.pdfXMode);
}

private void addsRGBColorSpace() throws IOException {
if (disableSRGBColorSpace) {
if (this.pdfAMode != PDFAMode.DISABLED
|| this.pdfXMode != PDFXMode.DISABLED
|| this.outputProfileURI != null) {
throw new IllegalStateException("It is not possible to disable the sRGB color"
+ " space if PDF/A or PDF/X functionality is enabled or an"
+ " output profile is set!");
}
} else {
if (this.sRGBColorSpace != null) {
return;
}
//Map sRGB as default RGB profile for DeviceRGB
this.sRGBColorSpace = PDFICCBasedColorSpace.setupsRGBAsDefaultRGBColorSpace(pdfDoc);
}
}

private void addDefaultOutputProfile() throws IOException {
if (this.outputProfile != null) {
return;
}
ICC_Profile profile;
InputStream in = null;
if (this.outputProfileURI != null) {
this.outputProfile = pdfDoc.getFactory().makePDFICCStream();
Source src = getUserAgent().resolveURI(this.outputProfileURI);
if (src == null) {
throw new IOException("Output profile not found: " + this.outputProfileURI);
}
if (src instanceof StreamSource) {
in = ((StreamSource)src).getInputStream();
} else {
in = new URL(src.getSystemId()).openStream();
}
try {
profile = ICC_Profile.getInstance(in);
} finally {
IOUtils.closeQuietly(in);
}
this.outputProfile.setColorSpace(profile, null);
} else {
//Fall back to sRGB profile
outputProfile = sRGBColorSpace.getICCStream();
}
}

/**
* Adds an OutputIntent to the PDF as mandated by PDF/A-1 when uncalibrated color spaces
* are used (which is true if we use DeviceRGB to represent sRGB colors).
* @throws IOException in case of an I/O problem
*/
private void addPDFA1OutputIntent() throws IOException {
addDefaultOutputProfile();

String desc = ColorProfileUtil.getICCProfileDescription(this.outputProfile.getICCProfile());
PDFOutputIntent outputIntent = pdfDoc.getFactory().makeOutputIntent();
outputIntent.setSubtype(PDFOutputIntent.GTS_PDFA1);
outputIntent.setDestOutputProfile(this.outputProfile);
outputIntent.setOutputConditionIdentifier(desc);
outputIntent.setInfo(outputIntent.getOutputConditionIdentifier());
pdfDoc.getRoot().addOutputIntent(outputIntent);
}

/**
* Adds an OutputIntent to the PDF as mandated by PDF/X when uncalibrated color spaces
* are used (which is true if we use DeviceRGB to represent sRGB colors).
* @throws IOException in case of an I/O problem
*/
private void addPDFXOutputIntent() throws IOException {
addDefaultOutputProfile();

String desc = ColorProfileUtil.getICCProfileDescription(this.outputProfile.getICCProfile());
int deviceClass = this.outputProfile.getICCProfile().getProfileClass();
if (deviceClass != ICC_Profile.CLASS_OUTPUT) {
throw new PDFConformanceException(pdfDoc.getProfile().getPDFXMode() + " requires that"
+ " the DestOutputProfile be an Output Device Profile. "
+ desc + " does not match that requirement.");
}
PDFOutputIntent outputIntent = pdfDoc.getFactory().makeOutputIntent();
outputIntent.setSubtype(PDFOutputIntent.GTS_PDFX);
outputIntent.setDestOutputProfile(this.outputProfile);
outputIntent.setOutputConditionIdentifier(desc);
outputIntent.setInfo(outputIntent.getOutputConditionIdentifier());
pdfDoc.getRoot().addOutputIntent(outputIntent);
}

public void renderXMPMetadata(XMPMetadata metadata) {
Metadata docXMP = metadata.getMetadata();
Metadata fopXMP = PDFMetadata.createXMPFromPDFDocument(pdfDoc);
//Merge FOP's own metadata into the one from the XSL-FO document
fopXMP.mergeInto(docXMP);
XMPBasicAdapter xmpBasic = XMPBasicSchema.getAdapter(docXMP);
//Metadata was changed so update metadata date
xmpBasic.setMetadataDate(new java.util.Date());
PDFMetadata.updateInfoFromMetadata(docXMP, pdfDoc.getInfo());

PDFMetadata pdfMetadata = pdfDoc.getFactory().makeMetadata(
docXMP, metadata.isReadOnly());
pdfDoc.getRoot().setMetadata(pdfMetadata);
}

public void generateDefaultXMPMetadata() {
if (pdfDoc.getRoot().getMetadata() == null) {
//If at this time no XMP metadata for the overall document has been set, create it
//from the PDFInfo object.
Metadata xmp = PDFMetadata.createXMPFromPDFDocument(pdfDoc);
PDFMetadata pdfMetadata = pdfDoc.getFactory().makeMetadata(
xmp, true);
pdfDoc.getRoot().setMetadata(pdfMetadata);
}
}

public PDFDocument setupPDFDocument(OutputStream out) throws IOException {
if (this.pdfDoc != null) {
throw new IllegalStateException("PDFDocument already set up");
}
this.pdfDoc = new PDFDocument(
userAgent.getProducer() != null ? userAgent.getProducer() : "");
updateInfo();
updatePDFProfiles();
pdfDoc.setFilterMap(filterMap);
pdfDoc.outputHeader(out);

//Setup encryption if necessary
PDFEncryptionManager.setupPDFEncryption(encryptionParams, pdfDoc);

addsRGBColorSpace();
if (this.outputProfileURI != null) {
addDefaultOutputProfile();
}
if (pdfXMode != PDFXMode.DISABLED) {
log.debug(pdfXMode + " is active.");
log.warn("Note: " + pdfXMode
+ " support is work-in-progress and not fully implemented, yet!");
addPDFXOutputIntent();
}
if (pdfAMode.isPDFA1LevelB()) {
log.debug("PDF/A is active. Conformance Level: " + pdfAMode);
addPDFA1OutputIntent();
}
return this.pdfDoc;
}

/**
* Generates a page label in the PDF document.
* @param pageIndex the index of the page
* @param pageNumber the formatted page number
*/
public void generatePageLabel(int pageIndex, String pageNumber) {
//Produce page labels
PDFPageLabels pageLabels = this.pdfDoc.getRoot().getPageLabels();
if (pageLabels == null) {
//Set up PageLabels
pageLabels = this.pdfDoc.getFactory().makePageLabels();
this.pdfDoc.getRoot().setPageLabels(pageLabels);
}
PDFNumsArray nums = pageLabels.getNums();
PDFDictionary dict = new PDFDictionary(nums);
dict.put("P", pageNumber);
//TODO If the sequence of generated page numbers were inspected, this could be
//expressed in a more space-efficient way
nums.put(pageIndex, dict);
}

/**
* Establishes a new foreground or fill color. In contrast to updateColor
* this method does not check the PDFState for optimization possibilities.
* @param col the color to apply
* @param fill true to set the fill color, false for the foreground color
* @param pdf StringBuffer to write the PDF code to
*/
public void setColor(Color col, boolean fill, StringBuffer pdf) {
assert pdf != null;
PDFColor color = new PDFColor(this.pdfDoc, col);
pdf.append(color.getColorSpaceOut(fill));
}

/**
* Establishes a new foreground or fill color.
* @param col the color to apply
* @param fill true to set the fill color, false for the foreground color
* @param stream the PDFStream to write the PDF code to
*/
public void setColor(Color col, boolean fill, PDFStream stream) {
assert stream != null;
PDFColor color = new PDFColor(this.pdfDoc, col);
stream.add(color.getColorSpaceOut(fill));
}


}

+ 22
- 20
src/java/org/apache/fop/util/ConversionUtils.java View File

@@ -5,7 +5,7 @@
* 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
@@ -14,7 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.util;

/**
@@ -27,84 +29,84 @@ public final class ConversionUtils {
* Converts the given base <code>String</code> into
* an array of <code>int</code>, splitting the base along the
* given separator pattern.
* <em>Note: this method assumes the input is a string containing
* <em>Note: this method assumes the input is a string containing
* only decimal integers, signed or unsigned, that are parsable
* by <code>java.lang.Integer.parseInt(String)</code>. If this
* is not the case, the resulting <code>NumberFormatException</code>
* will have to be handled by the caller.</em>
*
*
* @param baseString the base string
* @param separatorPattern the pattern separating the integer values
* (if this is <code>null</code>, the baseString is parsed as one
* integer value)
* integer value)
* @return an array of <code>int</code> whose size is equal to the number
* values in the input string; <code>null</code> if this number
* is equal to zero.
*/
public static int[] toIntArray(String baseString, String separatorPattern) {
if (baseString == null || "".equals(baseString)) {
return null;
}
if (separatorPattern == null || "".equals(separatorPattern)) {
return new int[] { Integer.parseInt(baseString) };
return new int[] {Integer.parseInt(baseString)};
}
String[] values = baseString.split(separatorPattern);
int numValues = values.length;
if (numValues == 0) {
return null;
}
int[] returnArray = new int[numValues];
for (int i = 0; i < numValues; ++i) {
returnArray[i] = Integer.parseInt(values[i]);
}
return returnArray;
}

/**
* Converts the given base <code>String</code> into
* an array of <code>double</code>, splitting the base along the
* given separator pattern.
* <em>Note: this method assumes the input is a string containing
* <em>Note: this method assumes the input is a string containing
* only decimal doubles, signed or unsigned, that are parsable
* by <code>java.lang.Double.parseDouble(String)</code>. If this
* is not the case, the resulting <code>NumberFormatException</code>
* will have to be handled by the caller.</em>
*
*
* @param baseString the base string
* @param separatorPattern the pattern separating the integer values
* (if this is <code>null</code>, the baseString is parsed as one
* double value)
* double value)
* @return an array of <code>double</code> whose size is equal to the number
* values in the input string; <code>null</code> if this number
* is equal to zero.
*/
public static double[] toDoubleArray(String baseString, String separatorPattern) {
if (baseString == null || "".equals(baseString)) {
return null;
}
if (separatorPattern == null || "".equals(separatorPattern)) {
return new double[] { Double.parseDouble(baseString) };
return new double[] {Double.parseDouble(baseString)};
}
String[] values = baseString.split(separatorPattern);
int numValues = values.length;
if (numValues == 0) {
return null;
}
double[] returnArray = new double[numValues];
for (int i = 0; i < numValues; ++i) {
returnArray[i] = Double.parseDouble(values[i]);
}
return returnArray;
}
}

+ 5
- 0
src/sandbox/org/apache/fop/render/svg/SVGPainter.java View File

@@ -77,6 +77,11 @@ public class SVGPainter extends AbstractSVGPainter {
return true;
}

/** {@inheritDoc} */
public String getMimeType() {
return MIME_TYPE;
}

/** {@inheritDoc} */
public void setResult(Result result) throws IFException {
if (result instanceof StreamResult) {

+ 7
- 0
src/sandbox/org/apache/fop/render/svg/SVGPainterMaker.java View File

@@ -22,6 +22,7 @@ package org.apache.fop.render.svg;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.render.intermediate.AbstractIFPainterMaker;
import org.apache.fop.render.intermediate.IFPainter;
import org.apache.fop.render.intermediate.IFPainterConfigurator;

/**
* Painter factory for SVG output.
@@ -45,4 +46,10 @@ public class SVGPainterMaker extends AbstractIFPainterMaker {
return MIMES;
}

/** {@inheritDoc} */
public IFPainterConfigurator getConfigurator(FOUserAgent userAgent) {
// TODO Auto-generated method stub
return null;
}

}

+ 5
- 0
src/sandbox/org/apache/fop/render/svg/SVGPrintPainter.java View File

@@ -56,6 +56,11 @@ public class SVGPrintPainter extends AbstractSVGPainter {
return false;
}

/** {@inheritDoc} */
public String getMimeType() {
return MIME_SVG_PRINT;
}

/** {@inheritDoc} */
public void startDocument() throws IFException {
try {

+ 7
- 0
src/sandbox/org/apache/fop/render/svg/SVGPrintPainterMaker.java View File

@@ -22,6 +22,7 @@ package org.apache.fop.render.svg;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.render.intermediate.AbstractIFPainterMaker;
import org.apache.fop.render.intermediate.IFPainter;
import org.apache.fop.render.intermediate.IFPainterConfigurator;

/**
* Painter factory for SVG Print output.
@@ -45,4 +46,10 @@ public class SVGPrintPainterMaker extends AbstractIFPainterMaker {
return MIMES;
}

/** {@inheritDoc} */
public IFPainterConfigurator getConfigurator(FOUserAgent userAgent) {
// TODO Auto-generated method stub
return null;
}

}

Loading…
Cancel
Save