Forum How do I...?

The new Control Interface

joelmeador
Is there a document detailing the control API for this thing? I tried to reverse engineer it when it was first announced from the Java client, but it was super hinky and unclear what the prince process expected and what the failure states were. So @mikeday, how do I use the new control interface when I am not using one of the pre-packaged wrapper libraries? :)
mikeday
The new Prince control protocol can be accessed by running "prince --control".

It is a synchronous bidirectional protocol that consists of a sequence of "chunks" sent via the standard input and output streams.

Each chunk contains a sequence of bytes with a length and a three letter tag. Here is an example "version" chunk to demonstrate the syntax:
ver 15
Prince 20161219

This chunk has a tag "ver" (all tags are three ASCII characters) followed by a space, then the length of the data expressed as a decimal number, then a newline character, then the data itself (15 bytes), then another newline (not part of the data).

This "version" chunk is emitted by Prince when the control protocol begins and can be used to check the Prince version and confirm that communication is functioning as expected. Prince will then wait for jobs to be submitted.

If a chunk contains no data then the length is zero and the chunk ends with the newline immediately following the length. In fact the length itself may be omitted, making this a perfectly valid chunk:
end

This "end" chunk consists of three letters and a newline character and can be used to terminate the Prince process when there are no further jobs to process.

Currently the control protocol includes the following chunk types sent by Prince:

- ver, sent at startup
- pdf, a generated PDF file
- log, the complete output log for the job including all errors and warnings
- err, errors relating to the control protocol itself

And these chunks sent by the caller:

- job, the description of a requested conversion job, expressed in JSON
- dat, a file resource needed by the job
- end, to terminate the control connection

A typical interaction looks like this:

Prince: ver
Caller: job
Caller: dat
Caller: dat
Prince: pdf
Prince: log
Caller: end

Instead of sending the final "end" chunk the caller may choose to submit another "job" chunk and continue converting documents. The protocol is synchronous so replies simply match requests in order.

The final piece of the puzzle is the format of the JSON job description, which I will post shortly. :)
mikeday
As mentioned earlier, the "job" chunk contains a description of the conversion job represented in JSON format, which can be followed by an optional sequence of "dat" chunks containing file data which is needed by the job, eg. HTML documents, style sheets, PDF attachments, or whatever.

The number of "dat" chunks is specified by the "job-resource-count" field in the job description, and these files can be accessed via a special job-resource URL scheme, eg. job-resource:0 will access the content of the first "dat" chunk, then job-resource:1, job-resource:2, etc. This allows any number of resources to be provided inline with the request and removes the need to create actual temporary files.

The JSON job description has several nested objects with fields corresponding to Prince options:
{
    "input": { <input options> },
    "pdf": { <pdf options> },
    "metadata": { <metadata options> },
    "raster": { <raster options> },
    "job-resource-count": <int>
}

The input options and job-resource-count are mandatory, the rest are optional and will default to the normal values.

The input options includes these fields:
{
    "src": <single URL or list of URLs>,
    "type": <string>,
    "base": <string>,
    "media": <string>,
    "styles": [ <list of URLs> ],
    "scripts": [ <list of URLs> ],
    "default-style": <bool>,
    "author-style": <bool>,
    "javascript": <bool>,
    "xinclude": <bool>,
    "xml-external-entities": <bool>
}

Only the src field is required, the rest can be left as defaults.

Now we can make some simple job descriptions, eg. to convert a single HTML file:
{
    "input": {
        "src": "/path/to/input.html"
    },
    "job-resource-count": 0
}

This can be sent as a single "job" chunk and Prince will respond with a "pdf" chunk if the conversion succeeded and a "log" chunk.

Or you can convert a HTML document without saving it to a temporary file:
{
    "input": {
        "src": "job-resource:0"
    },
    "job-resource-count": 1
}

This requires the "job" chunk to be followed by a "dat" chunk that contains the HTML and then Prince will respond as before.
mikeday
The pdf options object includes these fields:
{
    "color-options": "auto" | "use-true-black" | "use-rich-black",
    "embed-fonts": <bool>,
    "subset-fonts": <bool>,
    "artificial-fonts": <bool>,
    "force-identity-encoding": <bool>,
    "compress": <bool>,
    "encrypt": {
        "key-bits": 40 | 128,
        "user-password": <string>,
        "owner-password": <string>,
        "disallow-print": <bool>,
        "disallow-modify": <bool>,
        "disallow-copy": <bool>,
        "disallow-annotate": <bool>
    },
    "attach": [ <list of URLs> ],
    "pdf-profile": <string>,
    "pdf-output-intent": <URL>,
    "fallback-cmyk-profile": <URL>,
    "color-conversion": "none" | "full"
}

The metadata options object includes these fields:
{
    "title": <string>,
    "subject": <string>,
    "author": <string>,
    "keywords": <string>,
    "creator": <string>
}

The raster options object includes these fields:
{
    "dpi": <integer>
}

And that's about it! Let me know if you have further questions or if anything doesn't work. :)
joelmeador
Thanks for the explanation. Seems like I've got a lot of homework to do this holiday season. :D
nsnsolutions
Does this interface support the creation of Raster images? i see the node in the job schema above but when testing, prince writes PDF data each time. Are there additional requirements to produce raster images?
mikeday
The control interface doesn't support raster images yet, the raster properties are just to control rasterisation of SVG images included in the PDF file.
nsnsolutions
Thank You. Are there any plans to add raster support? If so, is there any timeline around such?
mikeday
No timeline yet, it requires some extensions to the protocol.
bynan
@mikeday - are there any examples of interacting with this protocol? i can use a terminal and hand type in the commands and responses, and that seems to work, but I want to do this programmatically.

for example, in python i can send "prince --control" to Popen() and then do a couple of stdout.readline() commands to get "ver 11" and "Prince 12.2". then i can send the "job xx" and "dat xx" stuff to stdin without error, but i never seem to get anything back from stdout.
mikeday
The Java wrapper includes code that demonstrates this, we don't yet have a Python wrapper for the control interface unfortunately.
bynan
@mikeday - thanks.

To anyone else that searches and finds this - my issue was solved by using .communicate() with the object returned from subprocess.Popen
bynan
@mikeday - do you know if there are any issues with the prince control protocol and the @page stuff using flow to pull elements out of the document? Now that I have the control protocol correctly converting my html to PDF, I wanted to add headers and footers that use HTML, but nothing seems to work for me.

i have

<div id="divHeader">This is the header</div>


in the body and i have

@page  {
  @top  {
    color: blue; content: flow(header)
  }
}
#divHeader { flow: static(header) }


but the header does not show up in my PDF, just the <div> as normal text

is there an option in the control protocol json i need to enable for this to work?
bynan
@mikeday - I'm sorry. It's totally working. Never mind my ramblings.