aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremias Maerki <jeremias@apache.org>2006-04-05 14:21:39 +0000
committerJeremias Maerki <jeremias@apache.org>2006-04-05 14:21:39 +0000
commitd1c0afa0a3a277b02c7301c37fd6b9fb34f0d2ba (patch)
tree50175cf4652eb077bb84db07cfc363cd498dac79
parent05ff967d64a3050a5ce08cc435bd91844efcf89d (diff)
downloadxmlgraphics-fop-d1c0afa0a3a277b02c7301c37fd6b9fb34f0d2ba.tar.gz
xmlgraphics-fop-d1c0afa0a3a277b02c7301c37fd6b9fb34f0d2ba.zip
Improved JUnit report creation.
Added support for OutputIntent objects in PDF. When PDF/A-1b is activated OutputIntents are created and the sRGB color space is used by default (hardcoded for the moment for lack of better color infrastructure in FOP). The sRGB color profile from HP (covering sRGB IEC61966-2.1) is now embedded in fop.jar as a resource so the PDF library can embed it. The sRGB profile from the Sun JRE is much bigger. That's why it's not used. The Gladiator TrueType font (glb12.ttf) has been copied over from Batik and is used to verify PDF/A-1b's conformance checks. CMYK JPEG image added to test resources so PDF/A-1b color space checks can be performed. With the color space checks, support for PDF/A-1b is complete to the degree that FOP supports the creation of elements described in ISO 19005-1, except for the case where an embedded XMP packet is used in the fo:declarations element. In this case the metadata is not synchronized with the values in the Info PDF object which could lead to validation errors when checking for PDF/A-1b conformance. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@391624 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--README21
-rw-r--r--build.xml58
-rw-r--r--src/java/org/apache/fop/pdf/PDFDocument.java2
-rw-r--r--src/java/org/apache/fop/pdf/PDFFactory.java10
-rw-r--r--src/java/org/apache/fop/pdf/PDFOutputIntent.java173
-rw-r--r--src/java/org/apache/fop/pdf/PDFRoot.java29
-rw-r--r--src/java/org/apache/fop/pdf/sRGB Color Space Profile.icmbin0 -> 3144 bytes
-rw-r--r--src/java/org/apache/fop/pdf/sRGB Color Space Profile.icm.LICENSE.txt14
-rw-r--r--src/java/org/apache/fop/render/pdf/FopPDFImage.java14
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFRenderer.java58
-rw-r--r--src/java/org/apache/fop/svg/PDFGraphics2D.java7
-rw-r--r--test/java/org/apache/fop/StandardTestSuite.java45
-rw-r--r--test/java/org/apache/fop/render/pdf/PDFAConformanceTestCase.java157
-rw-r--r--test/resources/fonts/glb12.README.txt9
-rwxr-xr-xtest/resources/fonts/glb12.ttfbin0 -> 53460 bytes
-rw-r--r--test/resources/fonts/glb12.ttf.ansi.xml282
-rw-r--r--test/resources/fonts/glb12.ttf.xml397
-rw-r--r--test/resources/images/cmyk.jpgbin0 -> 1785 bytes
-rw-r--r--test/test.xconf18
-rw-r--r--test/xml/pdf-a/base14-font.fo13
-rw-r--r--test/xml/pdf-a/minimal-pdf-a.fo13
-rw-r--r--test/xml/pdf-a/with-cmyk-images.fo14
-rw-r--r--test/xml/pdf-a/with-eps.fo14
-rw-r--r--test/xml/pdf-a/with-rgb-images.fo14
24 files changed, 1319 insertions, 43 deletions
diff --git a/README b/README
index fc6ae1bea..bd51f057d 100644
--- a/README
+++ b/README
@@ -27,6 +27,27 @@ Apache FOP is part of Apache's XML Graphics project. The homepage of Apache
FOP is http://xmlgraphics.apache.org/fop/.
+Legal information
+---------------------
+
+Apache FOP is published under the Apache License version 2.0. For the license
+text, please see the following files:
+- LICENSE
+- NOTICE
+
+Legal information on libraries used by Apache FOP can be found in the
+"lib/README.txt" file.
+
+Here is a list of files included in Apache FOP but not published under Apache
+License version 2.0:
+- sRGB IEC61966-2.1 color profile
+ File: src/java/org/apache/fop/pdf/sRGB Color Space Profile.icm
+ Info: src/java/org/apache/fop/pdf/sRGB Color Space Profile.icm.LICENSE.txt
+- K3 3 of 9 barcode font (TrueType)
+ File: examples/fo/advanced/K3.TTF
+ Info: example/fo/advanced/K3.README
+
+
Where to get help?
---------------------
diff --git a/build.xml b/build.xml
index e89fad850..5cb3c81a6 100644
--- a/build.xml
+++ b/build.xml
@@ -397,6 +397,8 @@ list of possible build targets.
<copy todir="${build.classes.dir}">
<fileset dir="${src.java.dir}">
<include name="META-INF/**"/>
+ <include name="**/*.icm"/>
+ <include name="**/*.LICENSE.txt"/>
</fileset>
</copy>
<mkdir dir="${build.viewer.resources.dir}"/>
@@ -670,6 +672,7 @@ list of possible build targets.
</target>
<target name="junit-compile" depends="package, transcoder-pkg, junit-with-xmlunit, junit-without-xmlunit" description="Runs FOP's JUnit tests" if="junit.present">
<mkdir dir="${build.dir}/test-classes"/>
+ <mkdir dir="${build.dir}/test-reports"/>
<javac destdir="${build.dir}/test-classes" fork="${javac.fork}"
debug="${javac.debug}" deprecation="${javac.deprecation}"
optimize="${javac.optimize}" source="${javac.source}"
@@ -687,11 +690,11 @@ list of possible build targets.
<target name="junit-transcoder" depends="junit-compile" description="Runs FOP's JUnit transcoder tests" if="junit.present">
<echo message="Running basic functionality tests for fop-transcoder.jar"/>
- <mkdir dir="${build.dir}/test-reports/fop-transcoder"/>
<junit haltonerror="no" fork="${junit.fork}">
<sysproperty key="basedir" value="${basedir}"/>
<sysproperty key="jawa.awt.headless" value="true"/>
<formatter type="brief" usefile="false"/>
+ <formatter type="plain" usefile="true"/>
<classpath>
<pathelement location="${build.dir}/test-classes"/>
<path refid="libs-build-classpath"/>
@@ -699,11 +702,7 @@ list of possible build targets.
<include name="fop-transcoder.jar"/>
</fileset>
</classpath>
- <batchtest todir="${build.dir}/test-reports/fop-transcoder">
- <fileset dir="${build.dir}/test-classes">
- <include name="org/apache/fop/BasicTranscoderTestSuite.class"/>
- </fileset>
- </batchtest>
+ <test name="org.apache.fop.BasicTranscoderTestSuite" todir="${build.dir}/test-reports" outfile="TEST-transcoder"/>
</junit>
<echo message="Running basic functionality tests for fop-transcoder-allinone.jar"/>
<!-- These are the same tests as in the block above but testing the "allinone" JAR
@@ -712,11 +711,11 @@ list of possible build targets.
previous test block succeeded it indicates that the packaging of the allinone
JAR needs to be updated.
-->
- <mkdir dir="${build.dir}/test-reports/fop-transcoder-allinone"/>
<junit haltonerror="no" fork="${junit.fork}" errorproperty="fop.junit.error" failureproperty="fop.junit.failure">
<sysproperty key="basedir" value="${basedir}"/>
<sysproperty key="jawa.awt.headless" value="true"/>
<formatter type="brief" usefile="false"/>
+ <formatter type="plain" usefile="true"/>
<classpath>
<pathelement location="${build.dir}/test-classes"/>
<fileset dir="build">
@@ -728,21 +727,17 @@ list of possible build targets.
<include name="batik*.jar"/>
</fileset>
</classpath>
- <batchtest todir="${build.dir}/test-reports/fop-transcoder-allinone">
- <fileset dir="${build.dir}/test-classes">
- <include name="org/apache/fop/BasicTranscoderTestSuite.class"/>
- </fileset>
- </batchtest>
+ <test name="org.apache.fop.BasicTranscoderTestSuite" todir="${build.dir}/test-reports" outfile="TEST-transcoder-allinone"/>
</junit>
</target>
<target name="junit-basic" depends="junit-compile" description="Runs FOP's JUnit basic tests" if="junit.present">
<echo message="Running basic functionality tests for fop.jar"/>
- <mkdir dir="${build.dir}/test-reports/fop"/>
<junit haltonerror="no" fork="${junit.fork}" errorproperty="fop.junit.error" failureproperty="fop.junit.failure">
<sysproperty key="basedir" value="${basedir}"/>
<sysproperty key="jawa.awt.headless" value="true"/>
<formatter type="brief" usefile="false"/>
+ <formatter type="plain" usefile="true"/>
<classpath>
<pathelement location="${build.dir}/test-classes"/>
<path refid="libs-build-classpath"/>
@@ -750,12 +745,7 @@ list of possible build targets.
<include name="fop.jar"/>
</fileset>
</classpath>
- <batchtest todir="${build.dir}/test-reports/fop">
- <fileset dir="${build.dir}/test-classes">
- <include name="org/apache/fop/BasicDriverTestSuite.class"/>
- <include name="org/apache/fop/UtilityCodeTestSuite.class"/>
- </fileset>
- </batchtest>
+ <test name="org.apache.fop.StandardTestSuite" todir="${build.dir}/test-reports"/>
</junit>
</target>
@@ -779,43 +769,35 @@ list of possible build targets.
<target name="junit-layout-standard" depends="junit-compile" if="junit.present" description="Runs FOP's standard JUnit layout tests">
<echo message="Running standard layout engine tests"/>
- <mkdir dir="${build.dir}/test-reports/fop"/>
<junit haltonerror="no" fork="${junit.fork}" errorproperty="fop.junit.error" failureproperty="fop.junit.failure">
<sysproperty key="basedir" value="${basedir}"/>
<sysproperty key="jawa.awt.headless" value="true"/>
<sysproperty key="fop.layoutengine.disabled" value="${layoutengine.disabled}"/>
<sysproperty key="fop.layoutengine.testset" value="standard"/>
<formatter type="brief" usefile="false"/>
+ <formatter type="plain" usefile="true"/>
<classpath>
<pathelement location="${build.dir}/test-classes"/>
<path refid="libs-run-classpath"/>
</classpath>
- <batchtest todir="${build.dir}/test-reports/fop">
- <fileset dir="${build.dir}/test-classes">
- <include name="org/apache/fop/layoutengine/LayoutEngineTestSuite.class"/>
- </fileset>
- </batchtest>
+ <test name="org.apache.fop.layoutengine.LayoutEngineTestSuite" todir="${build.dir}/test-reports" outfile="TEST-layoutengine-standard"/>
</junit>
</target>
<target name="junit-layout-hyphenation" depends="hyphenation-present, junit-compile" if="hyphenation.present" description="Runs FOP's JUnit hyphenation layout tests">
<echo message="Running hyphenation layout engine tests"/>
- <mkdir dir="${build.dir}/test-reports/fop"/>
<junit haltonerror="no" fork="${junit.fork}" errorproperty="fop.junit.error" failureproperty="fop.junit.failure">
<sysproperty key="basedir" value="${basedir}"/>
<sysproperty key="jawa.awt.headless" value="true"/>
<sysproperty key="fop.layoutengine.disabled" value="${layoutengine.disabled}"/>
<sysproperty key="fop.layoutengine.testset" value="hyphenation"/>
<formatter type="brief" usefile="false"/>
+ <formatter type="plain" usefile="true"/>
<classpath>
<pathelement location="${build.dir}/test-classes"/>
<path refid="libs-run-classpath"/>
</classpath>
- <batchtest todir="${build.dir}/test-reports/fop">
- <fileset dir="${build.dir}/test-classes">
- <include name="org/apache/fop/layoutengine/LayoutEngineTestSuite.class"/>
- </fileset>
- </batchtest>
+ <test name="org.apache.fop.layoutengine.LayoutEngineTestSuite" todir="${build.dir}/test-reports" outfile="TEST-layoutengine-hyphenation"/>
</junit>
</target>
@@ -828,6 +810,7 @@ list of possible build targets.
<sysproperty key="jawa.awt.headless" value="true"/>
<sysproperty key="fop.layoutengine.disabled" value="${fotree.disabled}"/>
<formatter type="brief" usefile="false"/>
+ <formatter type="plain" usefile="true"/>
<classpath>
<pathelement location="${build.dir}/test-classes"/>
<path refid="libs-build-classpath"/>
@@ -835,11 +818,7 @@ list of possible build targets.
<include name="fop.jar"/>
</fileset>
</classpath>
- <batchtest todir="${build.dir}/test-reports/fop">
- <fileset dir="${build.dir}/test-classes">
- <include name="org/apache/fop/fotreetest/FOTreeTestSuite.class"/>
- </fileset>
- </batchtest>
+ <test name="org.apache.fop.fotreetest.FOTreeTestSuite" todir="${build.dir}/test-reports" outfile="TEST-FO-tree"/>
</junit>
</target>
@@ -851,6 +830,7 @@ list of possible build targets.
<sysproperty key="fop.layoutengine.disabled" value="${layoutengine.disabled}"/>
<sysproperty key="fop.layoutengine.testset" value="standard"/>
<formatter type="brief" usefile="false"/>
+ <formatter type="plain" usefile="true"/>
<classpath>
<pathelement location="${build.dir}/test-classes"/>
<path refid="libs-build-classpath"/>
@@ -858,11 +838,7 @@ list of possible build targets.
<include name="fop.jar"/>
</fileset>
</classpath>
- <batchtest todir="${build.dir}/test-reports/fop">
- <fileset dir="${build.dir}/test-classes">
- <include name="org/apache/fop/intermediate/IntermediateFormatTestSuite.class"/>
- </fileset>
- </batchtest>
+ <test name="org.apache.fop.intermediate.IntermediateFormatTestSuite" todir="${build.dir}/test-reports" outfile="TEST-intermediate-format"/>
</junit>
</target>
diff --git a/src/java/org/apache/fop/pdf/PDFDocument.java b/src/java/org/apache/fop/pdf/PDFDocument.java
index 79b7e52e1..f97c498b6 100644
--- a/src/java/org/apache/fop/pdf/PDFDocument.java
+++ b/src/java/org/apache/fop/pdf/PDFDocument.java
@@ -285,7 +285,7 @@ public class PDFDocument {
if (mode == PDFAMode.PDFA_1A) {
throw new UnsupportedOperationException("PDF/A-1a is not implemented, yet");
} else if (mode == PDFAMode.PDFA_1B) {
- log.warn("Please note: PDF/A-1b is 'WORK IN PROGRESS' and not fully supported, yet!");
+ //you got the green light!
}
this.pdfAMode = mode;
}
diff --git a/src/java/org/apache/fop/pdf/PDFFactory.java b/src/java/org/apache/fop/pdf/PDFFactory.java
index 6222cf1f0..4fddd3e35 100644
--- a/src/java/org/apache/fop/pdf/PDFFactory.java
+++ b/src/java/org/apache/fop/pdf/PDFFactory.java
@@ -150,6 +150,16 @@ public class PDFFactory {
}
/**
+ * Make a OutputIntent dictionary.
+ * @return the newly created OutputIntent dictionary
+ */
+ public PDFOutputIntent makeOutputIntent() {
+ PDFOutputIntent outputIntent = new PDFOutputIntent();
+ getDocument().registerObject(outputIntent);
+ return outputIntent;
+ }
+
+ /**
* Make a /Page object. The page is assigned an object number immediately
* so references can already be made. The page must be added to the
* PDFDocument later using addObject().
diff --git a/src/java/org/apache/fop/pdf/PDFOutputIntent.java b/src/java/org/apache/fop/pdf/PDFOutputIntent.java
new file mode 100644
index 000000000..a18f0e351
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFOutputIntent.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.pdf;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * Represents the OutputIntent dictionary.
+ * @since PDF 1.4
+ */
+public class PDFOutputIntent extends PDFObject {
+
+ /** Subtype for PDF/X output intents */
+ public static final String GTS_PDFX = "GTS_PDFX";
+ /** Subtype for PDF/A-1 output intents */
+ public static final String GTS_PDFA1 = "GTS_PDFA1";
+
+ private String subtype; //S in the PDF spec
+ private String outputCondition;
+ private String outputConditionIdentifier;
+ private String registryName;
+ private String info;
+ private PDFICCStream destOutputProfile;
+
+
+ /** @return the output intent subtype. */
+ public String getSubtype() {
+ return subtype;
+ }
+
+ /**
+ * Sets the output intent subtype.
+ * @param subtype the subtype (usually "GTS_PDFX")
+ */
+ public void setSubtype(String subtype) {
+ this.subtype = subtype;
+ }
+
+ /** @return the OutputCondition field */
+ public String getOutputCondition() {
+ return outputCondition;
+ }
+
+ /**
+ * Sets the human-readable form of the output condition.
+ * @param outputCondition A text string concisely identifying the intended output
+ * device or production condition in human-readable form.
+ */
+ public void setOutputCondition(String outputCondition) {
+ this.outputCondition = outputCondition;
+ }
+
+ /** @return the OutputConditionIdentifier field */
+ public String getOutputConditionIdentifier() {
+ return outputConditionIdentifier;
+ }
+
+ /**
+ * Sets the identifier for the output condition.
+ * @param outputConditionIdentifier A string identifying the intended output device or
+ * production condition in human- or machine-readable form.
+ */
+ public void setOutputConditionIdentifier(String outputConditionIdentifier) {
+ this.outputConditionIdentifier = outputConditionIdentifier;
+ }
+
+ /** @return the RegistryName field */
+ public String getRegistryName() {
+ return registryName;
+ }
+
+ /**
+ * Sets the registry name.
+ * @param registryName A string (conventionally a uniform resource identifier,
+ * or URI) identifying the registry in which the condition designated
+ * by OutputConditionIdentifier is defined.
+ */
+ public void setRegistryName(String registryName) {
+ this.registryName = registryName;
+ }
+
+ /** @return the Info field */
+ public String getInfo() {
+ return info;
+ }
+
+ /**
+ * Sets the Info field.
+ * @param info A human-readable text string containing additional information or comments about
+ * the intended target device or production condition.
+ */
+ public void setInfo(String info) {
+ this.info = info;
+ }
+
+ /** @return the DestOutputProfile */
+ public PDFICCStream getDestOutputProfile() {
+ return destOutputProfile;
+ }
+
+ /**
+ * Sets the destination ICC profile.
+ * @param destOutputProfile An ICC profile stream defining the transformation from the PDF
+ * document’s source colors to output device colorants.
+ */
+ public void setDestOutputProfile(PDFICCStream destOutputProfile) {
+ this.destOutputProfile = destOutputProfile;
+ }
+
+ /** @see org.apache.fop.pdf.PDFObject#toPDF() */
+ public byte[] toPDF() {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream(128);
+ try {
+ bout.write(encode(getObjectID()));
+ bout.write(encode("<<\n"));
+ bout.write(encode("/Type /OutputIntent\n"));
+
+ bout.write(encode("/S /"));
+ bout.write(encode(this.subtype));
+ bout.write(encode("\n"));
+
+ if (outputCondition != null) {
+ bout.write(encode("/OutputCondition "));
+ bout.write(encodeText(this.outputCondition));
+ bout.write(encode("\n"));
+ }
+
+ bout.write(encode("/OutputConditionIdentifier "));
+ bout.write(encodeText(this.outputConditionIdentifier));
+ bout.write(encode("\n"));
+
+ if (registryName != null) {
+ bout.write(encode("/RegistryName "));
+ bout.write(encodeText(this.registryName));
+ bout.write(encode("\n"));
+ }
+
+ if (info != null) {
+ bout.write(encode("/Info "));
+ bout.write(encodeText(this.info));
+ bout.write(encode("\n"));
+ }
+
+ if (destOutputProfile != null) {
+ bout.write(encode("/DestOutputProfile " + destOutputProfile.referencePDF() + "\n"));
+ }
+
+ bout.write(encode(">>\nendobj\n"));
+ } catch (IOException ioe) {
+ log.error("Ignored I/O exception", ioe);
+ }
+ return bout.toByteArray();
+ }
+
+
+}
diff --git a/src/java/org/apache/fop/pdf/PDFRoot.java b/src/java/org/apache/fop/pdf/PDFRoot.java
index 3d483f587..9ac4e1b0f 100644
--- a/src/java/org/apache/fop/pdf/PDFRoot.java
+++ b/src/java/org/apache/fop/pdf/PDFRoot.java
@@ -18,6 +18,8 @@
package org.apache.fop.pdf;
+import java.util.List;
+
/**
* class representing a Root (/Catalog) object
*/
@@ -56,6 +58,9 @@ public class PDFRoot extends PDFObject {
/** Optional Metadata object */
private PDFMetadata metadata;
+ /** The array of OutputIntents */
+ private List outputIntents;
+
private int pageMode = PAGEMODE_USENONE;
/**
@@ -137,6 +142,17 @@ public class PDFRoot extends PDFObject {
}
/**
+ * Adds an OutputIntent to the PDF
+ * @param outputIntent the OutputIntent dictionary
+ */
+ public void addOutputIntent(PDFOutputIntent outputIntent) {
+ if (this.outputIntents == null) {
+ this.outputIntents = new java.util.ArrayList();
+ }
+ this.outputIntents.add(outputIntent);
+ }
+
+ /**
* @see org.apache.fop.pdf.PDFObject#toPDFString()
*/
public String toPDFString() {
@@ -168,6 +184,19 @@ public class PDFRoot extends PDFObject {
&& getDocumentSafely().getPDFVersion() >= PDFDocument.PDF_VERSION_1_4) {
p.append("/Metadata " + getMetadata().referencePDF() + "\n");
}
+ if (this.outputIntents != null
+ && this.outputIntents.size() > 0
+ && getDocumentSafely().getPDFVersion() >= PDFDocument.PDF_VERSION_1_4) {
+ p.append("/OutputIntents [");
+ for (int i = 0, c = this.outputIntents.size(); i < c; i++) {
+ PDFOutputIntent outputIntent = (PDFOutputIntent)this.outputIntents.get(i);
+ if (i > 0) {
+ p.append(" ");
+ }
+ p.append(outputIntent.referencePDF());
+ }
+ p.append("]\n");
+ }
p.append(">>\nendobj\n");
return p.toString();
}
diff --git a/src/java/org/apache/fop/pdf/sRGB Color Space Profile.icm b/src/java/org/apache/fop/pdf/sRGB Color Space Profile.icm
new file mode 100644
index 000000000..7f9d18d09
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/sRGB Color Space Profile.icm
Binary files differ
diff --git a/src/java/org/apache/fop/pdf/sRGB Color Space Profile.icm.LICENSE.txt b/src/java/org/apache/fop/pdf/sRGB Color Space Profile.icm.LICENSE.txt
new file mode 100644
index 000000000..9b817e339
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/sRGB Color Space Profile.icm.LICENSE.txt
@@ -0,0 +1,14 @@
+Obtained from: http://www.srgb.com/usingsrgb.html
+
+The file "sRGB Color Space Profile.icm" is:
+Copyright (c) 1998 Hewlett-Packard Company
+
+To anyone who acknowledges that the file "sRGB Color Space Profile.icm"
+is provided "AS IS" WITH NO EXPRESS OR IMPLIED WARRANTY:
+permission to use, copy and distribute this file for any purpose is hereby
+granted without fee, provided that the file is not changed including the HP
+copyright notice tag, and that the name of Hewlett-Packard Company not be
+used in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission. Hewlett-Packard Company makes
+no representations about the suitability of this software for any purpose.
+
diff --git a/src/java/org/apache/fop/render/pdf/FopPDFImage.java b/src/java/org/apache/fop/render/pdf/FopPDFImage.java
index d1beb0961..2ecdcbcec 100644
--- a/src/java/org/apache/fop/render/pdf/FopPDFImage.java
+++ b/src/java/org/apache/fop/render/pdf/FopPDFImage.java
@@ -17,6 +17,7 @@
/* $Id$ */
package org.apache.fop.render.pdf;
+import org.apache.fop.pdf.PDFConformanceException;
import org.apache.fop.pdf.PDFFilterList;
import org.apache.fop.pdf.PDFImage;
import org.apache.fop.pdf.PDFFilter;
@@ -24,6 +25,7 @@ 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.PDFColorSpace;
import org.apache.fop.pdf.PDFXObject;
import org.apache.fop.pdf.BitmapImage;
@@ -36,7 +38,6 @@ import java.io.IOException;
import java.io.OutputStream;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
-import org.apache.fop.pdf.CCFFilter;
/**
* PDFImage implementation for the PDF renderer.
@@ -129,6 +130,17 @@ public class FopPDFImage implements PDFImage {
PDFXObject xobj = doc.addImage(null, fopimg);
softMaskRef = xobj.referencePDF();
}
+ if (doc.getPDFAMode().isPDFA1LevelB()) {
+ if (pdfCS != null
+ && pdfCS.getColorSpace() != PDFColorSpace.DEVICE_RGB
+ && pdfCS.getColorSpace() != PDFColorSpace.DEVICE_GRAY
+ && prof == null) {
+ //See PDF/A-1, ISO 19005:1:2005(E), 6.2.3.3
+ //FOP is currently restricted to DeviceRGB if PDF/A-1 is active.
+ throw new PDFConformanceException(
+ "PDF/A-1 does not allow mixing DeviceRGB and DeviceCMYK.");
+ }
+ }
}
/**
diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java
index 68e9aa022..48eef1750 100644
--- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java
+++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java
@@ -20,8 +20,12 @@ package org.apache.fop.render.pdf;
// Java
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
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.util.Iterator;
@@ -34,6 +38,7 @@ import org.w3c.dom.Document;
// Avalon
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.commons.io.IOUtils;
// FOP
import org.apache.fop.apps.FOPException;
@@ -69,11 +74,13 @@ import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFEncryptionManager;
import org.apache.fop.pdf.PDFEncryptionParams;
import org.apache.fop.pdf.PDFFilterList;
+import org.apache.fop.pdf.PDFICCStream;
import org.apache.fop.pdf.PDFInfo;
import org.apache.fop.pdf.PDFLink;
import org.apache.fop.pdf.PDFMetadata;
import org.apache.fop.pdf.PDFNumber;
import org.apache.fop.pdf.PDFOutline;
+import org.apache.fop.pdf.PDFOutputIntent;
import org.apache.fop.pdf.PDFPage;
import org.apache.fop.pdf.PDFResourceContext;
import org.apache.fop.pdf.PDFResources;
@@ -352,11 +359,62 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
this.pdfDoc.setFilterMap(filterMap);
this.pdfDoc.outputHeader(stream);
+ if (pdfAMode.isPDFA1LevelB()) {
+ log.debug("PDF/A is active. Conformance Level: " + pdfAMode);
+ addPDFA1OutputIntent();
+ }
+
//Setup encryption if necessary
PDFEncryptionManager.setupPDFEncryption(encryptionParams, this.pdfDoc);
}
/**
+ * 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 {
+ PDFOutputIntent outputIntent = pdfDoc.getFactory().makeOutputIntent();
+ outputIntent.setSubtype(PDFOutputIntent.GTS_PDFA1);
+ PDFICCStream icc = pdfDoc.getFactory().makePDFICCStream();
+ ICC_Profile profile;
+ InputStream in = PDFDocument.class.getResourceAsStream("sRGB Color Space Profile.icm");
+ if (in != null) {
+ try {
+ profile = ICC_Profile.getInstance(in);
+ } finally {
+ IOUtils.closeQuietly(in);
+ }
+ } else {
+ //Fallback: Use the sRGB profile from the JRE (about 140KB)
+ profile = ICC_Profile.getInstance(ColorSpace.CS_sRGB);
+ }
+ String desc = getICCProfileDescription(profile);
+
+ icc.setColorSpace(profile, null);
+ outputIntent.setDestOutputProfile(icc);
+ outputIntent.setOutputConditionIdentifier(desc);
+ outputIntent.setInfo(outputIntent.getOutputConditionIdentifier());
+ pdfDoc.getRoot().addOutputIntent(outputIntent);
+ }
+
+ private String getICCProfileDescription(ICC_Profile profile) {
+ byte[] data = profile.getData(ICC_Profile.icSigProfileDescriptionTag);
+ if (data == null) {
+ return null;
+ } else {
+ //Info on the data format: http://www.color.org/ICC-1_1998-09.PDF
+ int length = (data[8] << 3 * 8) | (data[9] << 2 * 8) | (data[10] << 8) | data[11];
+ length--; //Remove trailing NUL character
+ try {
+ return new String(data, 12, length, "US-ASCII");
+ } catch (UnsupportedEncodingException e) {
+ throw new UnsupportedOperationException("Incompatible VM");
+ }
+ }
+ }
+
+ /**
* @see org.apache.fop.render.Renderer#stopRenderer()
*/
public void stopRenderer() throws IOException {
diff --git a/src/java/org/apache/fop/svg/PDFGraphics2D.java b/src/java/org/apache/fop/svg/PDFGraphics2D.java
index 59cb6612d..31f0567a2 100644
--- a/src/java/org/apache/fop/svg/PDFGraphics2D.java
+++ b/src/java/org/apache/fop/svg/PDFGraphics2D.java
@@ -18,6 +18,7 @@
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;
@@ -812,6 +813,12 @@ public class PDFGraphics2D extends AbstractGraphics2D {
currentStream.write(currentColour.getColorSpaceOut(fill));
} else if (c.getColorSpace().getType()
== ColorSpace.TYPE_CMYK) {
+ if (pdfDoc.getPDFAMode().isPDFA1LevelB()) {
+ //See PDF/A-1, ISO 19005:1:2005(E), 6.2.3.3
+ //FOP is currently restricted to DeviceRGB if PDF/A-1 is active.
+ throw new PDFConformanceException(
+ "PDF/A-1 does not allow mixing DeviceRGB and DeviceCMYK.");
+ }
float[] cComps = c.getColorComponents(new float[3]);
double[] cmyk = new double[3];
for (int i = 0; i < 3; i++) {
diff --git a/test/java/org/apache/fop/StandardTestSuite.java b/test/java/org/apache/fop/StandardTestSuite.java
new file mode 100644
index 000000000..ee3c5add8
--- /dev/null
+++ b/test/java/org/apache/fop/StandardTestSuite.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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: BasicDriverTestSuite.java 231325 2005-08-10 21:05:39Z jeremias $ */
+
+package org.apache.fop;
+
+import org.apache.fop.render.pdf.PDFAConformanceTestCase;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Test suite for basic functionality of FOP.
+ */
+public class StandardTestSuite {
+
+ /**
+ * Builds the test suite
+ * @return the test suite
+ */
+ public static Test suite() {
+ TestSuite suite = new TestSuite(
+ "Basic functionality test suite for FOP");
+ //$JUnit-BEGIN$
+ suite.addTest(BasicDriverTestSuite.suite());
+ suite.addTest(UtilityCodeTestSuite.suite());
+ suite.addTest(new TestSuite(PDFAConformanceTestCase.class));
+ //$JUnit-END$
+ return suite;
+ }
+}
diff --git a/test/java/org/apache/fop/render/pdf/PDFAConformanceTestCase.java b/test/java/org/apache/fop/render/pdf/PDFAConformanceTestCase.java
new file mode 100644
index 000000000..365ca51db
--- /dev/null
+++ b/test/java/org/apache/fop/render/pdf/PDFAConformanceTestCase.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.File;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.apps.Fop;
+import org.apache.fop.apps.FopFactory;
+import org.apache.fop.apps.MimeConstants;
+import org.apache.fop.pdf.PDFConformanceException;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests PDF/A-1 functionality.
+ */
+public class PDFAConformanceTestCase extends TestCase {
+
+ private TransformerFactory tFactory = TransformerFactory.newInstance();
+ private FopFactory fopFactory = FopFactory.newInstance();
+ private File foBaseDir = new File("test/xml/pdf-a");
+
+ /**
+ * Main constructor
+ * @param name the name of the test case
+ */
+ public PDFAConformanceTestCase(String name) {
+ super(name);
+ try {
+ fopFactory.setUserConfig(new File("test/test.xconf"));
+ } catch (Exception e) {
+ throw new RuntimeException("Configuring the FopFactory failed: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Convert the test file
+ * @param foFile the FO file
+ * @param ua the preconfigured user agent
+ * @throws Exception if the conversion fails
+ */
+ protected void convertFO(File foFile, FOUserAgent ua) throws Exception {
+ ua.getRendererOptions().put("pdf-a-mode", "PDF/A-1b");
+ File outFile = null;
+ ByteArrayOutputStream baout = new ByteArrayOutputStream();
+ Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, ua, baout);
+ Transformer transformer = tFactory.newTransformer();
+ Source src = new StreamSource(foFile);
+ SAXResult res = new SAXResult(fop.getDefaultHandler());
+ transformer.transform(src, res);
+ if (true) {
+ //Write to file for debugging
+ outFile = new File(foFile.getParentFile(), foFile.getName() + ".pdf");
+ FileUtils.writeByteArrayToFile(outFile, baout.toByteArray());
+ }
+ }
+
+ /**
+ * Test exception when PDF/A-1 is enabled and everything is as it should.
+ * @throws Exception if the test fails
+ */
+ public void testAllOk() throws Exception {
+ FOUserAgent ua = fopFactory.newFOUserAgent();
+ File foFile = new File(foBaseDir, "minimal-pdf-a.fo");
+ convertFO(foFile, ua);
+ }
+
+ /**
+ * Test exception when PDF/A-1 is enabled together with encryption.
+ * @throws Exception if the test fails
+ */
+ public void testNoEncryption() throws Exception {
+ FOUserAgent ua = fopFactory.newFOUserAgent();
+ ua.getRendererOptions().put("owner-password", "mypassword"); //To enabled encryption
+ File foFile = new File(foBaseDir, "minimal-pdf-a.fo");
+ try {
+ convertFO(foFile, ua);
+ fail("Expected PDFConformanceException. PDF/A-1 and PDF encryption don't go together.");
+ } catch (PDFConformanceException e) {
+ //Good!
+ }
+ }
+
+ /**
+ * Test exception when PDF/A-1 is enabled and a font is used which is not embedded.
+ * @throws Exception if the test fails
+ */
+ public void testFontNotEmbedded() throws Exception {
+ FOUserAgent ua = fopFactory.newFOUserAgent();
+ File foFile = new File(foBaseDir, "base14-font.fo");
+ try {
+ convertFO(foFile, ua);
+ fail("Expected PDFConformanceException. PDF/A-1 wants all fonts embedded.");
+ } catch (PDFConformanceException e) {
+ //Good!
+ }
+ }
+
+ /**
+ * Test exception when PDF/A-1 is enabled and an EPS is used.
+ * @throws Exception if the test fails
+ */
+ public void testEPSUsage() throws Exception {
+ FOUserAgent ua = fopFactory.newFOUserAgent();
+ File foFile = new File(foBaseDir, "with-eps.fo");
+ try {
+ convertFO(foFile, ua);
+ fail("Expected PDFConformanceException. PDF/A-1 does not allow PostScript XObjects.");
+ } catch (PDFConformanceException e) {
+ //Good!
+ }
+ }
+
+ /**
+ * Test exception when PDF/A-1 is enabled and images.
+ * @throws Exception if the test fails
+ */
+ public void testImages() throws Exception {
+ FOUserAgent ua = fopFactory.newFOUserAgent();
+ File foFile = new File(foBaseDir, "with-rgb-images.fo");
+ convertFO(foFile, ua);
+
+ foFile = new File(foBaseDir, "with-cmyk-images.fo");
+ try {
+ convertFO(foFile, ua);
+ fail("Expected PDFConformanceException. PDF/A-1 does not allow PostScript XObjects.");
+ } catch (PDFConformanceException e) {
+ //Good!
+ }
+ }
+
+}
diff --git a/test/resources/fonts/glb12.README.txt b/test/resources/fonts/glb12.README.txt
new file mode 100644
index 000000000..100046ad7
--- /dev/null
+++ b/test/resources/fonts/glb12.README.txt
@@ -0,0 +1,9 @@
+This Gladiator Bold font has been copied from Apache Batik. Origin:
+http://svn.apache.org/repos/asf/xmlgraphics/batik/trunk/samples/tests/resources/ttf/glb12.ttf
+
+It was added to that repository in July 2003:
+http://mail-archives.apache.org/mod_mbox/xmlgraphics-batik-dev/200307.mbox/%3c20030715155519.37236.qmail@icarus.apache.org%3e
+
+More information on that contribution can be found here:
+http://svn.apache.org/repos/asf/xmlgraphics/batik/trunk/contrib/fonts/gladiator/
+http://mail-archives.apache.org/mod_mbox/xmlgraphics-batik-dev/200306.mbox/ajax/%3c3EE07AA6.5080507@sun.com%3e \ No newline at end of file
diff --git a/test/resources/fonts/glb12.ttf b/test/resources/fonts/glb12.ttf
new file mode 100755
index 000000000..77ff2b490
--- /dev/null
+++ b/test/resources/fonts/glb12.ttf
Binary files differ
diff --git a/test/resources/fonts/glb12.ttf.ansi.xml b/test/resources/fonts/glb12.ttf.ansi.xml
new file mode 100644
index 000000000..18cd2650e
--- /dev/null
+++ b/test/resources/fonts/glb12.ttf.ansi.xml
@@ -0,0 +1,282 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<font-metrics type="TRUETYPE">
+ <font-name>Gladiator,Bold</font-name>
+ <embed/>
+ <cap-height>691</cap-height>
+ <x-height>429</x-height>
+ <ascender>765</ascender>
+ <descender>-234</descender>
+ <bbox>
+ <left>-157</left>
+ <bottom>-250</bottom>
+ <right>1181</right>
+ <top>1071</top>
+ </bbox>
+ <flags>33</flags>
+ <stemv>0</stemv>
+ <italicangle>0</italicangle>
+ <subtype>TRUETYPE</subtype>
+ <singlebyte-extras>
+ <encoding>WinAnsiEncoding</encoding>
+ <first-char>0</first-char>
+ <last-char>255</last-char>
+ <widths>
+ <char idx="0" wdt="432"/>
+ <char idx="1" wdt="432"/>
+ <char idx="2" wdt="432"/>
+ <char idx="3" wdt="432"/>
+ <char idx="4" wdt="432"/>
+ <char idx="5" wdt="432"/>
+ <char idx="6" wdt="432"/>
+ <char idx="7" wdt="432"/>
+ <char idx="8" wdt="432"/>
+ <char idx="9" wdt="432"/>
+ <char idx="10" wdt="432"/>
+ <char idx="11" wdt="432"/>
+ <char idx="12" wdt="432"/>
+ <char idx="13" wdt="432"/>
+ <char idx="14" wdt="432"/>
+ <char idx="15" wdt="432"/>
+ <char idx="16" wdt="432"/>
+ <char idx="17" wdt="432"/>
+ <char idx="18" wdt="432"/>
+ <char idx="19" wdt="432"/>
+ <char idx="20" wdt="432"/>
+ <char idx="21" wdt="432"/>
+ <char idx="22" wdt="432"/>
+ <char idx="23" wdt="432"/>
+ <char idx="24" wdt="432"/>
+ <char idx="25" wdt="432"/>
+ <char idx="26" wdt="432"/>
+ <char idx="27" wdt="432"/>
+ <char idx="28" wdt="432"/>
+ <char idx="29" wdt="432"/>
+ <char idx="30" wdt="432"/>
+ <char idx="31" wdt="432"/>
+ <char idx="32" wdt="332"/>
+ <char idx="33" wdt="376"/>
+ <char idx="34" wdt="525"/>
+ <char idx="35" wdt="980"/>
+ <char idx="36" wdt="625"/>
+ <char idx="37" wdt="754"/>
+ <char idx="38" wdt="886"/>
+ <char idx="39" wdt="311"/>
+ <char idx="40" wdt="398"/>
+ <char idx="41" wdt="398"/>
+ <char idx="42" wdt="601"/>
+ <char idx="43" wdt="652"/>
+ <char idx="44" wdt="311"/>
+ <char idx="45" wdt="331"/>
+ <char idx="46" wdt="311"/>
+ <char idx="47" wdt="500"/>
+ <char idx="48" wdt="541"/>
+ <char idx="49" wdt="541"/>
+ <char idx="50" wdt="541"/>
+ <char idx="51" wdt="541"/>
+ <char idx="52" wdt="541"/>
+ <char idx="53" wdt="541"/>
+ <char idx="54" wdt="541"/>
+ <char idx="55" wdt="541"/>
+ <char idx="56" wdt="541"/>
+ <char idx="57" wdt="541"/>
+ <char idx="58" wdt="311"/>
+ <char idx="59" wdt="311"/>
+ <char idx="60" wdt="500"/>
+ <char idx="61" wdt="805"/>
+ <char idx="62" wdt="500"/>
+ <char idx="63" wdt="569"/>
+ <char idx="64" wdt="805"/>
+ <char idx="65" wdt="729"/>
+ <char idx="66" wdt="708"/>
+ <char idx="67" wdt="725"/>
+ <char idx="68" wdt="748"/>
+ <char idx="69" wdt="683"/>
+ <char idx="70" wdt="665"/>
+ <char idx="71" wdt="769"/>
+ <char idx="72" wdt="808"/>
+ <char idx="73" wdt="347"/>
+ <char idx="74" wdt="347"/>
+ <char idx="75" wdt="769"/>
+ <char idx="76" wdt="644"/>
+ <char idx="77" wdt="1109"/>
+ <char idx="78" wdt="767"/>
+ <char idx="79" wdt="821"/>
+ <char idx="80" wdt="689"/>
+ <char idx="81" wdt="821"/>
+ <char idx="82" wdt="708"/>
+ <char idx="83" wdt="689"/>
+ <char idx="84" wdt="685"/>
+ <char idx="85" wdt="767"/>
+ <char idx="86" wdt="689"/>
+ <char idx="87" wdt="1181"/>
+ <char idx="88" wdt="729"/>
+ <char idx="89" wdt="729"/>
+ <char idx="90" wdt="644"/>
+ <char idx="91" wdt="542"/>
+ <char idx="92" wdt="500"/>
+ <char idx="93" wdt="542"/>
+ <char idx="94" wdt="253"/>
+ <char idx="95" wdt="432"/>
+ <char idx="96" wdt="311"/>
+ <char idx="97" wdt="515"/>
+ <char idx="98" wdt="556"/>
+ <char idx="99" wdt="492"/>
+ <char idx="100" wdt="556"/>
+ <char idx="101" wdt="517"/>
+ <char idx="102" wdt="311"/>
+ <char idx="103" wdt="556"/>
+ <char idx="104" wdt="575"/>
+ <char idx="105" wdt="311"/>
+ <char idx="106" wdt="311"/>
+ <char idx="107" wdt="556"/>
+ <char idx="108" wdt="311"/>
+ <char idx="109" wdt="839"/>
+ <char idx="110" wdt="575"/>
+ <char idx="111" wdt="547"/>
+ <char idx="112" wdt="556"/>
+ <char idx="113" wdt="556"/>
+ <char idx="114" wdt="440"/>
+ <char idx="115" wdt="492"/>
+ <char idx="116" wdt="359"/>
+ <char idx="117" wdt="575"/>
+ <char idx="118" wdt="476"/>
+ <char idx="119" wdt="711"/>
+ <char idx="120" wdt="496"/>
+ <char idx="121" wdt="476"/>
+ <char idx="122" wdt="496"/>
+ <char idx="123" wdt="432"/>
+ <char idx="124" wdt="311"/>
+ <char idx="125" wdt="432"/>
+ <char idx="126" wdt="253"/>
+ <char idx="127" wdt="432"/>
+ <char idx="128" wdt="432"/>
+ <char idx="129" wdt="432"/>
+ <char idx="130" wdt="432"/>
+ <char idx="131" wdt="432"/>
+ <char idx="132" wdt="432"/>
+ <char idx="133" wdt="432"/>
+ <char idx="134" wdt="432"/>
+ <char idx="135" wdt="432"/>
+ <char idx="136" wdt="253"/>
+ <char idx="137" wdt="432"/>
+ <char idx="138" wdt="0"/>
+ <char idx="139" wdt="432"/>
+ <char idx="140" wdt="0"/>
+ <char idx="141" wdt="432"/>
+ <char idx="142" wdt="0"/>
+ <char idx="143" wdt="432"/>
+ <char idx="144" wdt="432"/>
+ <char idx="145" wdt="311"/>
+ <char idx="146" wdt="311"/>
+ <char idx="147" wdt="525"/>
+ <char idx="148" wdt="525"/>
+ <char idx="149" wdt="432"/>
+ <char idx="150" wdt="855"/>
+ <char idx="151" wdt="1109"/>
+ <char idx="152" wdt="253"/>
+ <char idx="153" wdt="432"/>
+ <char idx="154" wdt="0"/>
+ <char idx="155" wdt="432"/>
+ <char idx="156" wdt="0"/>
+ <char idx="157" wdt="432"/>
+ <char idx="158" wdt="0"/>
+ <char idx="159" wdt="0"/>
+ <char idx="160" wdt="332"/>
+ <char idx="161" wdt="376"/>
+ <char idx="162" wdt="432"/>
+ <char idx="163" wdt="0"/>
+ <char idx="164" wdt="432"/>
+ <char idx="165" wdt="432"/>
+ <char idx="166" wdt="432"/>
+ <char idx="167" wdt="0"/>
+ <char idx="168" wdt="395"/>
+ <char idx="169" wdt="432"/>
+ <char idx="170" wdt="432"/>
+ <char idx="171" wdt="657"/>
+ <char idx="172" wdt="432"/>
+ <char idx="173" wdt="432"/>
+ <char idx="174" wdt="432"/>
+ <char idx="175" wdt="253"/>
+ <char idx="176" wdt="432"/>
+ <char idx="177" wdt="432"/>
+ <char idx="178" wdt="432"/>
+ <char idx="179" wdt="432"/>
+ <char idx="180" wdt="304"/>
+ <char idx="181" wdt="432"/>
+ <char idx="182" wdt="432"/>
+ <char idx="183" wdt="432"/>
+ <char idx="184" wdt="151"/>
+ <char idx="185" wdt="432"/>
+ <char idx="186" wdt="432"/>
+ <char idx="187" wdt="657"/>
+ <char idx="188" wdt="432"/>
+ <char idx="189" wdt="432"/>
+ <char idx="190" wdt="432"/>
+ <char idx="191" wdt="569"/>
+ <char idx="192" wdt="547"/>
+ <char idx="193" wdt="729"/>
+ <char idx="194" wdt="729"/>
+ <char idx="195" wdt="729"/>
+ <char idx="196" wdt="729"/>
+ <char idx="197" wdt="729"/>
+ <char idx="198" wdt="432"/>
+ <char idx="199" wdt="725"/>
+ <char idx="200" wdt="683"/>
+ <char idx="201" wdt="683"/>
+ <char idx="202" wdt="683"/>
+ <char idx="203" wdt="683"/>
+ <char idx="204" wdt="347"/>
+ <char idx="205" wdt="347"/>
+ <char idx="206" wdt="347"/>
+ <char idx="207" wdt="347"/>
+ <char idx="208" wdt="0"/>
+ <char idx="209" wdt="767"/>
+ <char idx="210" wdt="821"/>
+ <char idx="211" wdt="821"/>
+ <char idx="212" wdt="821"/>
+ <char idx="213" wdt="821"/>
+ <char idx="214" wdt="821"/>
+ <char idx="215" wdt="432"/>
+ <char idx="216" wdt="0"/>
+ <char idx="217" wdt="767"/>
+ <char idx="218" wdt="767"/>
+ <char idx="219" wdt="767"/>
+ <char idx="220" wdt="767"/>
+ <char idx="221" wdt="729"/>
+ <char idx="222" wdt="0"/>
+ <char idx="223" wdt="432"/>
+ <char idx="224" wdt="515"/>
+ <char idx="225" wdt="515"/>
+ <char idx="226" wdt="515"/>
+ <char idx="227" wdt="515"/>
+ <char idx="228" wdt="515"/>
+ <char idx="229" wdt="515"/>
+ <char idx="230" wdt="432"/>
+ <char idx="231" wdt="492"/>
+ <char idx="232" wdt="517"/>
+ <char idx="233" wdt="517"/>
+ <char idx="234" wdt="517"/>
+ <char idx="235" wdt="517"/>
+ <char idx="236" wdt="311"/>
+ <char idx="237" wdt="311"/>
+ <char idx="238" wdt="311"/>
+ <char idx="239" wdt="311"/>
+ <char idx="240" wdt="0"/>
+ <char idx="241" wdt="575"/>
+ <char idx="242" wdt="547"/>
+ <char idx="243" wdt="547"/>
+ <char idx="244" wdt="547"/>
+ <char idx="245" wdt="547"/>
+ <char idx="246" wdt="547"/>
+ <char idx="247" wdt="432"/>
+ <char idx="248" wdt="0"/>
+ <char idx="249" wdt="575"/>
+ <char idx="250" wdt="575"/>
+ <char idx="251" wdt="575"/>
+ <char idx="252" wdt="575"/>
+ <char idx="253" wdt="476"/>
+ <char idx="254" wdt="0"/>
+ <char idx="255" wdt="476"/>
+ </widths>
+ </singlebyte-extras>
+</font-metrics>
diff --git a/test/resources/fonts/glb12.ttf.xml b/test/resources/fonts/glb12.ttf.xml
new file mode 100644
index 000000000..b4dff29c2
--- /dev/null
+++ b/test/resources/fonts/glb12.ttf.xml
@@ -0,0 +1,397 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2006 The Apache Software Foundation
+
+ Licensed 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.
+-->
+<!--
+
+Generated from glb12.ttf by Apache FOP's TTFReader
+
+-->
+<font-metrics type="TYPE0">
+ <font-name>Gladiator,Bold</font-name>
+ <embed/>
+ <cap-height>691</cap-height>
+ <x-height>0</x-height>
+ <ascender>765</ascender>
+ <descender>-234</descender>
+ <bbox>
+ <left>-157</left>
+ <bottom>-250</bottom>
+ <right>1181</right>
+ <top>1071</top>
+ </bbox>
+ <flags>33</flags>
+ <stemv>0</stemv>
+ <italicangle>0</italicangle>
+ <subtype>TYPE0</subtype>
+ <multibyte-extras>
+ <cid-type>CIDFontType2</cid-type>
+ <default-width>0</default-width>
+ <bfranges>
+ <bf gi="33" ue="33" us="32"/>
+ <bf gi="6" ue="34" us="34"/>
+ <bf gi="36" ue="38" us="35"/>
+ <bf gi="5" ue="39" us="39"/>
+ <bf gi="41" ue="91" us="40"/>
+ <bf gi="4" ue="92" us="92"/>
+ <bf gi="94" ue="93" us="93"/>
+ <bf gi="11" ue="94" us="94"/>
+ <bf gi="21" ue="96" us="96"/>
+ <bf gi="98" ue="122" us="97"/>
+ <bf gi="12" ue="124" us="124"/>
+ <bf gi="29" ue="126" us="126"/>
+ <bf gi="9" ue="161" us="161"/>
+ <bf gi="185" ue="163" us="163"/>
+ <bf gi="158" ue="167" us="167"/>
+ <bf gi="128" ue="168" us="168"/>
+ <bf gi="93" ue="171" us="171"/>
+ <bf gi="25" ue="175" us="175"/>
+ <bf gi="22" ue="180" us="180"/>
+ <bf gi="27" ue="184" us="184"/>
+ <bf gi="35" ue="187" us="187"/>
+ <bf gi="10" ue="191" us="191"/>
+ <bf gi="186" ue="197" us="192"/>
+ <bf gi="192" ue="214" us="199"/>
+ <bf gi="209" ue="222" us="216"/>
+ <bf gi="216" ue="229" us="224"/>
+ <bf gi="222" ue="246" us="231"/>
+ <bf gi="239" ue="255" us="248"/>
+ <bf gi="129" ue="258" us="258"/>
+ <bf gi="159" ue="259" us="259"/>
+ <bf gi="130" ue="260" us="260"/>
+ <bf gi="160" ue="261" us="261"/>
+ <bf gi="131" ue="262" us="262"/>
+ <bf gi="161" ue="263" us="263"/>
+ <bf gi="132" ue="268" us="268"/>
+ <bf gi="162" ue="269" us="269"/>
+ <bf gi="133" ue="270" us="270"/>
+ <bf gi="163" ue="271" us="271"/>
+ <bf gi="157" ue="273" us="273"/>
+ <bf gi="135" ue="280" us="280"/>
+ <bf gi="165" ue="281" us="281"/>
+ <bf gi="134" ue="282" us="282"/>
+ <bf gi="164" ue="283" us="283"/>
+ <bf gi="136" ue="286" us="286"/>
+ <bf gi="166" ue="287" us="287"/>
+ <bf gi="156" ue="304" us="304"/>
+ <bf gi="19" ue="305" us="305"/>
+ <bf gi="32" ue="307" us="307"/>
+ <bf gi="137" ue="313" us="313"/>
+ <bf gi="167" ue="314" us="314"/>
+ <bf gi="138" ue="317" us="317"/>
+ <bf gi="168" ue="318" us="318"/>
+ <bf gi="139" ue="321" us="321"/>
+ <bf gi="169" ue="322" us="322"/>
+ <bf gi="140" ue="323" us="323"/>
+ <bf gi="170" ue="324" us="324"/>
+ <bf gi="141" ue="327" us="327"/>
+ <bf gi="171" ue="328" us="328"/>
+ <bf gi="142" ue="336" us="336"/>
+ <bf gi="172" ue="337" us="337"/>
+ <bf gi="208" ue="338" us="338"/>
+ <bf gi="238" ue="339" us="339"/>
+ <bf gi="143" ue="340" us="340"/>
+ <bf gi="173" ue="341" us="341"/>
+ <bf gi="144" ue="344" us="344"/>
+ <bf gi="174" ue="345" us="345"/>
+ <bf gi="145" ue="346" us="346"/>
+ <bf gi="175" ue="347" us="347"/>
+ <bf gi="147" ue="350" us="350"/>
+ <bf gi="177" ue="351" us="351"/>
+ <bf gi="146" ue="352" us="352"/>
+ <bf gi="176" ue="353" us="353"/>
+ <bf gi="149" ue="354" us="354"/>
+ <bf gi="179" ue="355" us="355"/>
+ <bf gi="148" ue="356" us="356"/>
+ <bf gi="151" ue="366" us="366"/>
+ <bf gi="181" ue="367" us="367"/>
+ <bf gi="150" ue="368" us="368"/>
+ <bf gi="180" ue="369" us="369"/>
+ <bf gi="152" ue="377" us="376"/>
+ <bf gi="182" ue="378" us="378"/>
+ <bf gi="155" ue="379" us="379"/>
+ <bf gi="184" ue="380" us="380"/>
+ <bf gi="154" ue="381" us="381"/>
+ <bf gi="183" ue="382" us="382"/>
+ <bf gi="95" ue="710" us="710"/>
+ <bf gi="23" ue="711" us="711"/>
+ <bf gi="24" ue="728" us="728"/>
+ <bf gi="96" ue="729" us="729"/>
+ <bf gi="26" ue="730" us="730"/>
+ <bf gi="30" ue="731" us="731"/>
+ <bf gi="127" ue="732" us="732"/>
+ <bf gi="126" ue="733" us="733"/>
+ <bf gi="28" ue="823" us="823"/>
+ <bf gi="3" ue="915" us="915"/>
+ <bf gi="124" ue="8212" us="8211"/>
+ <bf gi="97" ue="8216" us="8216"/>
+ <bf gi="40" ue="8217" us="8217"/>
+ <bf gi="8" ue="8220" us="8220"/>
+ <bf gi="7" ue="8221" us="8221"/>
+ <bf gi="20" ue="63166" us="63166"/>
+ <bf gi="14" ue="64260" us="64256"/>
+ <bf gi="0" ue="65535" us="65535"/>
+ </bfranges>
+ <cid-widths start-index="0">
+ <wx w="432"/>
+ <wx w="0"/>
+ <wx w="333"/>
+ <wx w="665"/>
+ <wx w="500"/>
+ <wx w="311"/>
+ <wx w="525"/>
+ <wx w="525"/>
+ <wx w="525"/>
+ <wx w="376"/>
+ <wx w="569"/>
+ <wx w="253"/>
+ <wx w="311"/>
+ <wx w="0"/>
+ <wx w="623"/>
+ <wx w="623"/>
+ <wx w="623"/>
+ <wx w="934"/>
+ <wx w="934"/>
+ <wx w="311"/>
+ <wx w="311"/>
+ <wx w="304"/>
+ <wx w="304"/>
+ <wx w="253"/>
+ <wx w="253"/>
+ <wx w="253"/>
+ <wx w="151"/>
+ <wx w="151"/>
+ <wx w="235"/>
+ <wx w="253"/>
+ <wx w="151"/>
+ <wx w="623"/>
+ <wx w="575"/>
+ <wx w="332"/>
+ <wx w="376"/>
+ <wx w="657"/>
+ <wx w="980"/>
+ <wx w="625"/>
+ <wx w="754"/>
+ <wx w="886"/>
+ <wx w="311"/>
+ <wx w="398"/>
+ <wx w="398"/>
+ <wx w="601"/>
+ <wx w="652"/>
+ <wx w="311"/>
+ <wx w="331"/>
+ <wx w="311"/>
+ <wx w="500"/>
+ <wx w="541"/>
+ <wx w="541"/>
+ <wx w="541"/>
+ <wx w="541"/>
+ <wx w="541"/>
+ <wx w="541"/>
+ <wx w="541"/>
+ <wx w="541"/>
+ <wx w="541"/>
+ <wx w="541"/>
+ <wx w="311"/>
+ <wx w="311"/>
+ <wx w="500"/>
+ <wx w="805"/>
+ <wx w="500"/>
+ <wx w="569"/>
+ <wx w="805"/>
+ <wx w="729"/>
+ <wx w="708"/>
+ <wx w="725"/>
+ <wx w="748"/>
+ <wx w="683"/>
+ <wx w="665"/>
+ <wx w="769"/>
+ <wx w="808"/>
+ <wx w="347"/>
+ <wx w="347"/>
+ <wx w="769"/>
+ <wx w="644"/>
+ <wx w="1109"/>
+ <wx w="767"/>
+ <wx w="821"/>
+ <wx w="689"/>
+ <wx w="821"/>
+ <wx w="708"/>
+ <wx w="689"/>
+ <wx w="685"/>
+ <wx w="767"/>
+ <wx w="689"/>
+ <wx w="1181"/>
+ <wx w="729"/>
+ <wx w="729"/>
+ <wx w="644"/>
+ <wx w="542"/>
+ <wx w="657"/>
+ <wx w="542"/>
+ <wx w="253"/>
+ <wx w="115"/>
+ <wx w="311"/>
+ <wx w="515"/>
+ <wx w="556"/>
+ <wx w="492"/>
+ <wx w="556"/>
+ <wx w="517"/>
+ <wx w="311"/>
+ <wx w="556"/>
+ <wx w="575"/>
+ <wx w="311"/>
+ <wx w="311"/>
+ <wx w="556"/>
+ <wx w="311"/>
+ <wx w="839"/>
+ <wx w="575"/>
+ <wx w="547"/>
+ <wx w="556"/>
+ <wx w="556"/>
+ <wx w="440"/>
+ <wx w="492"/>
+ <wx w="359"/>
+ <wx w="575"/>
+ <wx w="476"/>
+ <wx w="711"/>
+ <wx w="496"/>
+ <wx w="476"/>
+ <wx w="496"/>
+ <wx w="855"/>
+ <wx w="1109"/>
+ <wx w="253"/>
+ <wx w="253"/>
+ <wx w="395"/>
+ <wx w="729"/>
+ <wx w="729"/>
+ <wx w="725"/>
+ <wx w="725"/>
+ <wx w="748"/>
+ <wx w="683"/>
+ <wx w="683"/>
+ <wx w="769"/>
+ <wx w="644"/>
+ <wx w="644"/>
+ <wx w="644"/>
+ <wx w="767"/>
+ <wx w="767"/>
+ <wx w="821"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="347"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="515"/>
+ <wx w="515"/>
+ <wx w="492"/>
+ <wx w="492"/>
+ <wx w="556"/>
+ <wx w="517"/>
+ <wx w="517"/>
+ <wx w="556"/>
+ <wx w="311"/>
+ <wx w="311"/>
+ <wx w="311"/>
+ <wx w="575"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="547"/>
+ <wx w="729"/>
+ <wx w="729"/>
+ <wx w="729"/>
+ <wx w="729"/>
+ <wx w="729"/>
+ <wx w="725"/>
+ <wx w="683"/>
+ <wx w="683"/>
+ <wx w="683"/>
+ <wx w="683"/>
+ <wx w="347"/>
+ <wx w="347"/>
+ <wx w="347"/>
+ <wx w="347"/>
+ <wx w="0"/>
+ <wx w="767"/>
+ <wx w="821"/>
+ <wx w="821"/>
+ <wx w="821"/>
+ <wx w="821"/>
+ <wx w="821"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="767"/>
+ <wx w="767"/>
+ <wx w="767"/>
+ <wx w="767"/>
+ <wx w="729"/>
+ <wx w="0"/>
+ <wx w="515"/>
+ <wx w="515"/>
+ <wx w="515"/>
+ <wx w="515"/>
+ <wx w="515"/>
+ <wx w="515"/>
+ <wx w="492"/>
+ <wx w="517"/>
+ <wx w="517"/>
+ <wx w="517"/>
+ <wx w="517"/>
+ <wx w="311"/>
+ <wx w="311"/>
+ <wx w="311"/>
+ <wx w="311"/>
+ <wx w="0"/>
+ <wx w="575"/>
+ <wx w="547"/>
+ <wx w="547"/>
+ <wx w="547"/>
+ <wx w="547"/>
+ <wx w="547"/>
+ <wx w="0"/>
+ <wx w="0"/>
+ <wx w="575"/>
+ <wx w="575"/>
+ <wx w="575"/>
+ <wx w="575"/>
+ <wx w="476"/>
+ <wx w="0"/>
+ <wx w="476"/>
+ </cid-widths>
+ </multibyte-extras>
+</font-metrics>
diff --git a/test/resources/images/cmyk.jpg b/test/resources/images/cmyk.jpg
new file mode 100644
index 000000000..cfdcca1aa
--- /dev/null
+++ b/test/resources/images/cmyk.jpg
Binary files differ
diff --git a/test/test.xconf b/test/test.xconf
new file mode 100644
index 000000000..c0df5b0dd
--- /dev/null
+++ b/test/test.xconf
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<fop version="1.0">
+ <renderers>
+ <renderer mime="application/pdf">
+ <fonts>
+ <font metrics-url="test/resources/fonts/glb12.ttf.xml" embed-url="test/resources/fonts/glb12.ttf">
+ <font-triplet name="Gladiator" style="normal" weight="normal"/>
+ </font>
+ <font metrics-url="test/resources/fonts/glb12.ttf.ansi.xml" embed-url="test/resources/fonts/glb12.ttf">
+ <font-triplet name="Gladiator-Ansi" style="normal" weight="normal"/>
+ </font>
+ <font metrics-url="test/resources/fonts/glb12.ttf.ansi.xml">
+ <font-triplet name="Gladiator-Non-Embedded" style="normal" weight="normal"/>
+ </font>
+ </fonts>
+ </renderer>
+ </renderers>
+</fop>
diff --git a/test/xml/pdf-a/base14-font.fo b/test/xml/pdf-a/base14-font.fo
new file mode 100644
index 000000000..a33623ec9
--- /dev/null
+++ b/test/xml/pdf-a/base14-font.fo
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" font-family="Helvetica">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="A4" page-height="29.7cm" page-width="21cm" margin="2cm">
+ <fo:region-body/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+ <fo:page-sequence master-reference="A4">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block>Hello World!</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+</fo:root>
diff --git a/test/xml/pdf-a/minimal-pdf-a.fo b/test/xml/pdf-a/minimal-pdf-a.fo
new file mode 100644
index 000000000..0081be30b
--- /dev/null
+++ b/test/xml/pdf-a/minimal-pdf-a.fo
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" font-family="Gladiator">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="A4" page-height="29.7cm" page-width="21cm" margin="2cm">
+ <fo:region-body/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+ <fo:page-sequence master-reference="A4">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block>Hello World!</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+</fo:root>
diff --git a/test/xml/pdf-a/with-cmyk-images.fo b/test/xml/pdf-a/with-cmyk-images.fo
new file mode 100644
index 000000000..f3429d304
--- /dev/null
+++ b/test/xml/pdf-a/with-cmyk-images.fo
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" font-family="Gladiator">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="A4" page-height="29.7cm" page-width="21cm" margin="2cm">
+ <fo:region-body/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+ <fo:page-sequence master-reference="A4">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block>Hello World!</fo:block>
+ <fo:block><fo:external-graphic src="test/resources/images/cmyk.jpg"/></fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+</fo:root>
diff --git a/test/xml/pdf-a/with-eps.fo b/test/xml/pdf-a/with-eps.fo
new file mode 100644
index 000000000..0f8913f01
--- /dev/null
+++ b/test/xml/pdf-a/with-eps.fo
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" font-family="Gladiator">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="A4" page-height="29.7cm" page-width="21cm" margin="2cm">
+ <fo:region-body/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+ <fo:page-sequence master-reference="A4">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block>Hello World!</fo:block>
+ <fo:block><fo:external-graphic src="test/resources/images/barcode.eps"/></fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+</fo:root>
diff --git a/test/xml/pdf-a/with-rgb-images.fo b/test/xml/pdf-a/with-rgb-images.fo
new file mode 100644
index 000000000..952da63eb
--- /dev/null
+++ b/test/xml/pdf-a/with-rgb-images.fo
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" font-family="Gladiator">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="A4" page-height="29.7cm" page-width="21cm" margin="2cm">
+ <fo:region-body/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+ <fo:page-sequence master-reference="A4">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block>Hello World!</fo:block>
+ <fo:block><fo:external-graphic src="test/resources/images/bgimg300dpi.jpg"/></fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+</fo:root>