Table of Content
Table of Contents | ||||||||
---|---|---|---|---|---|---|---|---|
|
Maven Dependencies
The CIP4 xJdfLib Java Library is based on Java. The latest stable version always is being published on the CIP4 Website on page “Technical Resources -> Downloads -> Internal Source”. Furthermore, the library is an Apache Maven project. So the latest stable version also is available in the public Central Maven Repositroy:
...
Code Block | ||
---|---|---|
| ||
<dependency> <groupId>org.cip4.lib.xjdf</groupId> <artifactId>xJdfLib</artifactId> <version>0.6-SNAPSHOT</version> </dependency> |
Components Description
XJDF Data Types
The XJDF Specification specifies several data types. At this time not all but the most significant data types already are implemented in CIP4 XJDF Java Library. The next versions of xJdfLib will complete the list step by step.
All XJDF Type classes are derived from AbstractXJdfType and provide a custom toString() method for converting a data type to a string expression. The way around is coverted by a custom constructor. Each XJDF Data Type provides at least a default and several custom constructor for initializing.
Data Type: DateTime
A DateTime object represents a specific instant of time. It must be a Coordinated Universal Time (UTC) or the time zone must be indicated by the offset to UTC. In other words, the time must be unique in all time zones around the world.
...
Code Block | ||
---|---|---|
| ||
// read DateTime DateTime dateTime = new DateTime(); dateTime.getCalendar() |
Data Type: Duration
Durations are a component of time intervals and define the amount of intervening time in a time interval. Durations are represented by the format P[n]Y[n]M[n]DT[n]H[n]M[n]S.
...
Code Block | ||
---|---|---|
| ||
// read Duration Duration duration = new Duration(0, 6); int year = duration.getYear(); int month = duration.getMonth(); int day = duration.getDay(); int hour = duration.getHour(); // 6 int minute = duration.getMinute(); int second = duration.getSecond(); |
Data Type: IntegerList
An IntegerList is an enumerated set of Integers, which is expressed as a list of space separated values.
...
Code Block | ||
---|---|---|
| ||
// read IntegerList IntegerList integerList = new IntegerList(4, 0); List<Integer> lst = integerList.getList(); |
Data Type: Matrix
Coordinate transformation matrices are widely used throughout the whole printing Process, especially in Layout Resources. They represent two dimensional transformations as defined by [PS] and [PDF1.6]. For more information, refer to the respective reference manuals, and look for "Coordinate Systems and Transformations." The "identity matrix", which is "1 0 0 1 0 0", is often used as a default throughout this specification. When another matrix is factored against a matrix with the identity matrix value, the result is that the original matrix remains unchanged. Coordinate transformation matrices are primitive data types and are encoded as a list of six numbers (as doubles), separated by whitespace: "a b c d Tx Ty". The variables Tx and Ty describe distances and are defined in points.
...
Code Block | ||
---|---|---|
| ||
// read matrix Matrix matrix = new Matrix(1, 2, 3, 4, 5, 6); double a = matrix.getA(); // 1.0 double b = matrix.getB(); // 2.0 double c = matrix.getC(); // 3.0 double d = matrix.getD(); // 4.0 double tx = matrix.getTx(); // 5.0 double ty = matrix.getTy(); // 6.0 |
Data Type: NMTokens
NMTOKENS is an enumerated set of NMTOKEN, which is expressed as a list of space separated values.
...
Code Block | ||
---|---|---|
| ||
// read NMTokens NMTokens nmTokens = new NMTokens("Val_1 Val_2 Val_3"); List<String> lst = nmTokens.getList(); |
Data Type: Rectangle
Rectangles are used to describe rectangular locations on the page, sheet or other printable surface. A rectangle is represented as an array of four numbers — llx lly urx ury — specifying the lower-left x, lowerleft y, upper-right x and upper-right y coordinates of the rectangle, in that order. This is equivalent to the ordering: Left Bottom Right Top. All numbers are defined in points.
...
Code Block | ||
---|---|---|
| ||
// read Rectangle Rectangle rectangle = new Rectangle(1, 2, 3, 4); double llx = rectangle.getLlx(); double lly = rectangle.getLly(); double urx = rectangle.getUrx(); double ury = rectangle.getUry(); |
Data Type: Shape
Shape data types are used to describe a three dimensional box. A shape is represented as an array of three (positive or zero) numbers x y z specifying the Width x, height y and depth z coordinates of the shape, in that order.
...
Code Block | ||
---|---|---|
| ||
// read Shape Shape shape = new Shape(10.5, 15.2); double x = shape.getX(); // 10.5 double y = shape.getY(); // 15.2 double z = shape.getZ(); // 0.0 |
Data Type: XYPair
XYPairs are used to describe sizes like Dimensions and StartPosition. They can also be used to describe positions on a page. All numbers that describe lengths are defined in points. XYPair Attributes are primitive data types and are encoded as a string of two numbers, separated by whitespace: "x y".
...
Code Block |
---|
// read XYPair XYPair xyPair = new XYPair(4.5, 5.0); double x = xyPair.getX(); double y = xyPair.getY(); |
XJdfNodeFactory
The XJdfNodeFactory is the factory class for creating new instances of XJDF-Node-Objects. The class provides at least one simple Creation-Method per XJDF Node defined in XJDF Specification. Moreover, the class also provides extended Creation-Methods for commonly used nodes (e. g. GeneralID, RunList etc.) which also initializes the object after creation.
...
Code Block | ||
---|---|---|
| ||
// new factory instance XJdfNodeFactory nf = new XJdfNodeFactory(); // best practice creating indivudal nodes RunList runList = nf.createRunList("http://192.168.1.113:80/10496"); runList.getFileSpec().setUserFileName("myFileName.pdf"); |
Builder Classes
Most of the XJDF-Node-Objects can easily be created using the XJdfNodeFactory as described in the chapter before. How ever, more complex nodes like the XJDF-Root-Node or the Product-Node are nodes which contain a set of subnodes in a well defined structure. This requires additional logic to organize all child nodes within the parent node. Builder classes are designed to achieve this.
...
- XJdfBuilder
Creation of XJDF Documents. Manages the dealing with Products and Parameters. - ProductBuilder
Creation of Product-Nodes. Handles all Intent nodes. - ContactBuilder
Creation of Contact-Nodes. Organize the handling with contact details.
XJDFBuilder
The XJdfBuilder is responsible for the creation and management of XJDF-Root-Nodes as well as the main structure in XJDF Documents. All child nodes can easily be appended by calling the associated "add-" methods. The logic where exactely a specific node has to be put is covered by the builder class.
...
Code Block | ||
---|---|---|
| ||
// new factory instance XJdfNodeFactory nf = new XJdfNodeFactory(); Contact contact = [...]; Product product = [...]; // create XJDF with builder XJdfBuilder xJdfBuilder = XJdfBuilder.newInstance("FA-SIG-123456"); xJdfBuilder.addParameter(nf.createRunList("test_file.pdf")); xJdfBuilder.addParameter(contact); xJdfBuilder.addProduct(product); XJDF xjdf = xJdfBuilder.build(); // build XJDF Doc XJDF xJdf = xJdfBuilder.build(); |
Partitioning of Parameter Nodes
Following a sample of a XJDF Document with a partitioned RunList. The XJDF Document references the PDF files for cover and body separately. This mechanism is called partitioning and requires an Part-Node per item.
...
Code Block | ||
---|---|---|
| ||
// new factory instance XJdfNodeFactory nf = new XJdfNodeFactory(); // create XJDF Document ProductBuilder productBuilder = new ProductBuilder(1500); Product product = productBuilder.build(); Part partCover = nf.createPart(); partCover.setRun("cover"); Part partBody = nf.createPart(); partBody.setRun("body"); XJdfBuilder xJdfBuilder = new XJdfBuilder("FA-SIG-123456", "Web2Print"); xJdfBuilder.addParameter(nf.createRunList("cover.pdf"), partCover); xJdfBuilder.addParameter(nf.createRunList("body.pdf"), partBody); xJdfBuilder.addProduct(product); XJDF xjdf = xJdfBuilder.build(); |
ProductBuilder
The Product-Node is another signification element in an XJDF Document. This node specifies the product configuration how desired by the customer. In XJDF, most product configurations are defined as Intent-Nodes. A Product-Node consists of at least itself, its attributes and a set of Intent-Node subelements. The ProductBuilder organizes the creation of a Product-Node as well as the handling of all its Intent-Nodes.
...
Code Block | ||
---|---|---|
| ||
// new factory instance XJdfNodeFactory nf = new XJdfNodeFactory(); // create product node ProductBuilder productBuilder = new ProductBuilder(1500); productBuilder.addIntent(nf.createMediaIntent("IPG_90")); productBuilder.addIntent(nf.createLayoutIntent(2, "TwoSidedHeadToHead", new Shape(297.63779528, 419.52755906))); productBuilder.addIntent(nf.createColorIntent(new IntegerList(4, 4))); Product product = productBuilder.build(); XJdfBuilder xJdfBuilder = new XJdfBuilder("FA-SIG-123456", "Web2Print"); xJdfBuilder.addProduct(product); XJDF xjdf = xJdfBuilder.build(); |
ContactBuilder
The ContactBuilder simplify the creation of Contact-Nodes. Contact-Nodes hold all the customers contact and delivery details and can be added as parameter to an XJDF Document. Usually, a contact parameter consists of the Contact-Node with at least an Address-Node, a Company-Node and a ComChannel-Node as subelements.
...
Code Block | ||
---|---|---|
| ||
// create contact node ContactBuilder contactBuilder = new ContactBuilder(); contactBuilder.addCompany("flyeralarm GmbH"); contactBuilder.addPerson("Meissner", "Stefan", null); contactBuilder.addAddress("Alfred-Nobel-Strasse 15", "97082", "Wuerzburg"); contactBuilder.addComChannel("Phone", "tel:+49.931.465840"); contactBuilder.addContactType("Delivery"); contactBuilder.addContactType("Customer"); Contact contact = contactBuilder.build(); XJdfBuilder xJdfBuilder = new XJdfBuilder("FA-SIG-123456", "Web2Print"); xJdfBuilder.addParameter(contact); XJDF xjdf = xJdfBuilder.build(); |
XJdfParser
The XJdfParser writes an XJDF Document Object Tree either to a binary stream or to a byte array and vice versa. Cases of practical use are dealing with XJDF Documents and http transmissions or working on file system. When using binary streams, internally the parser is working with the Java interfaces java.io.InputStream and java.io.OutputStream. So it doesn’t matter which kind of stream is used for reading or writing. The following is a sample of how to save an XJDF Document to a local file system.
...
Info | ||
---|---|---|
| ||
In order to analyze or extract details from an XJDF Document it is recommended to work with XPath expressions. Parsing the whole document and working with the DOM Tree Objects is no longer state of the art. This mechanism consumes time and raises code complexity. Besides, parsing an InputStream is also prone to errors because it requires fully conform documents. CIP4 xJdfLib provides an extra class XJdfNavigator for dealing with XPath expressions in XJDF Documents. XJDF is desinged for XPath so the preferred way of reading XJDF Documents is XPath. |
XJdfValidator
The XJdfValidator class validates an XJDF Binary Stream against the latest XJDF Schema. A new instance is required for each validation process. So when validating an XJDF Document, first of all a new validator object has to be created. The method isValid() runs the validation process and finally returns the result as Boolean.
...
Code Block | ||
---|---|---|
| ||
// get binary stream InputStream xJdfStream = [...] // validate XJdfValidator xJdfValidator = XJdfValidator.newInstance(xJdfStream); boolean result = xJdfValidator.isValid(); // message output List<String> messages = xJdfValidator.getMessages(); String msgText = xJdfValidator.getMessagesText(); |
XJdfNavigator
The XJdfNavigator class provides functionality for reading, modifying and analyzing XJDF Documents using XPath. XPath is a very powerful XML Technology for working with XML Documents. More details about the XPath W3C Standard can be found here: http://www.w3.org/TR/xpath/.
XJdfNavigator directly works on InputStream objects or Byte Arrays, so there is no need to parse the document before hand. This mechanism saves time, code complexity and performance. One XJdfNavigator instance is required for each XJDF Document processed. There are several methods for reading, modifying and analyzing the document.
XPath Expressions
The following is a short XPath overview of expressions which are significant to XJDF Documents. The XJDF snippet after is used for extracting these attribute values:
...
Java Constant Name | XPath Expression |
---|---|
JOB_ID | /XJDF/@JobID |
CATEGORY | /XJDF/@Category |
GENERAL_CATALOG_ID | /XJDF/GeneralID[@IDUsage='CatalogID']/@IDValue |
GENERAL_LINE_ID | /XJDF/GeneralID[@IDUsage='LineID']/@IDValue |
FILE_SPEC_URL | /XJDF/ParameterSet[@Name='RunList']/Parameter/RunList/FileSpec/@URL |
MIN_APPROVALS | /XJDF/ParameterSet[@Name='ApprovalParams']/Parameter/ApprovalParams/@MinApprovals |
CUSTOMER_ID | /XJDF/ParameterSet[@Name='CustomerInfo']/Parameter/CustomerInfo/@CustomerID |
AMOUNT | /XJDF/ProductList/Product/@Amount |
MEDIA_QUALITY | /XJDF/ProductList/Product/Intent[@Name='MediaIntent']/MediaIntent/@MediaQuality |
LAYOUT_FINISHED_DIMENSIONS | /XJDF/ProductList/Product/Intent[@Name='LayoutIntent']/LayoutIntent/@FinishedDimensions |
LAYOUT_DIMENSIONS | /XJDF/ProductList/Product/Intent[@Name='LayoutIntent']/LayoutIntent/@Dimensions |
PRODUCTION_PRINT_PROCESS | /XJDF/ProductList/Product/Intent[@Name='ProductionIntent']/ProductionIntent/@PrintProcess |
FOLDING_CATALOG | /XJDF/ProductList/Product/Intent[@Name='FoldingIntent']/FoldingIntent/@FoldingCatalog |
COLOR_NUM_COLORS | /XJDF/ProductList/Product/Intent[@Name='ColorIntent']/ColorIntent/@NumColors |
Read and Modify Attributes
All attributes in document easily can be addressed and read using the method readAttribute() and the specific XPath expression as parameter. Modifications also can be done. The method updateAttribute() accepts a XPath expression plus the (new) attribute value. When all modifications are done finally the new XJDF Document is returned as InputStream by calling the getXJdfStream() method or as Byte Array by calling the getXJdfBytes() method.
...
Code Block | ||
---|---|---|
| ||
// load XJDF as InputStream InputStream is = XJdfLibSamples.class.getResourceAsStream(RES_SIMPLE_PRODUCT); XJdfNavigator nav = new XJdfNavigator(is); // define xPath String xPath = XJdfNavigator.LAYOUT_FINISHED_DIMENSIONS; // read finished dimensions Shape attShape = (Shape) nav.readAttribute(xPath, Shape.class); // modify attribute attShape = new Shape(attShape.getX(), attShape.getY(), 2.222); // update finished dimensions nav.updateAttribute(xPath, attShape); // output byte[] bytes = nav.getXJdfBytes(); System.out.println(new String(bytes)); |
Extended XPath Functionality
Specific XPath expressions can be evaluated using the method evaluate(). The return type of this method is Object but in specific it depends on the XPath expression and the resultant return type. Both parameters must be defined when using this method. The following a table of all supported return types:
...
Code Block | ||
---|---|---|
| ||
// load XJDF as InputStream InputStream is = XJdfLibSamples.class.getResourceAsStream(RES_SIMPLE_PRODUCT); XJdfNavigator nav = new XJdfNavigator(is); // update node String xPath = "/XJDF/ProductList/Product/Intent[@Name='MediaIntent']/MediaIntent"; Node node = (Node) nav.evaluate(xPath, XPathConstants.NODE); node.getAttributes().getNamedItem("MediaQuality").setNodeValue("IPM_170"); // output byte[] bytes = nav.getXJdfBytes(); System.out.println(new String(bytes)); |
XJdfPackager
The XJdfPackager is responsible for the packaging of an XJDF Document including all its references into a ZIP Package. One instance is required for each XJDF Document processed. If necessary, the compression level can be adjusted manually using the method setCompressionLevel(). The optional parameter "docName" of method packageXJdf() defines the name of the XJDF Document file within the ZIP Package. Out of the box the documents name is the XJDFs JobID plus the extension ".xjdf". The following there is a demonstration how to use the XJdfPackager class:
Code Block | ||
---|---|---|
| ||
// path to artwork String pathArtwork = XJdfLibSamples.class.getResource(RES_PDF_ARTWORK).getFile(); // build XJDF Document XJdfNodeFactory nf = new XJdfNodeFactory(); ProductBuilder productBuilder = new ProductBuilder(1500); Product product = productBuilder.build(); XJdfBuilder xJdfBuilder = new XJdfBuilder("JOB-12345678"); xJdfBuilder.addProduct(product); xJdfBuilder.addParameter(nf.createRunList(pathArtwork)); XJDF xJdf = xJdfBuilder.build(); byte[] bytes = new XJdfParser().parseXJdf(xJdf, true); // package to temporarily file File tmp = File.createTempFile("XJdfPackage", "zip"); tmp.deleteOnExit(); OutputStream os = new FileOutputStream(tmp); XJdfPackager packager = new XJdfPackager(bytes); packager.setCompressionLevel(CompressionLevel.BEST_SPEED); packager.packageXJdf(os); os.close(); |
XJdfConstants
When working with XJDF, there are several constants which are required in some cases. So the CIP4 xJdfLib also provides a static class XJdfConstants, where most common constants are already defined. Here is a list of all items in this class:
...
Code Block | ||
---|---|---|
| ||
// get XJDF default namespace String defaultNamespace = XJdfConstants.NAMESPACE_JDF20; // get current version of XJDF String currentVersion = XJdfConstants.XJDF_CURRENT_VERSION; |
Util Classes
Util classes provide tools and other simplifications for simplifying working with XJDF. The following is a list of all utils with a short description:
Util Class | Description |
---|---|
IDGeneratorUtil | Generation of randomly created alphanumeric 8-digits IDs with or without customized prefix. |
DimensionUtil | Conversion from millimeter to dtp and the way around. |
Performance Optimizations
The CIP4 XJDF Library is based on the Java JAX-B Framework. The framework brings a lot of benefits to the CIP4 xJdfLib but unfortunately the initialization takes a few seconds. Usually this happens automatically when the first XJDF Document is being parsed. In some cases this is not acceptable, thus the library provides additional functionalty for manual initialization. The XJdfFactory class is responsible for such a manual initialization process. The init() method starts the process synchronously. By setting the parameter "initAsync", the same process starts asynchronously. A recommendation is using the asynchronous method when the application starts. By the way the manual initialization process also initializes some other components.
...