PDF to Image Custom Encoding
UniPDF decodes most image filters itself, but not JPEG2000. core.JPXEncoder is a
stub: every method returns core.ErrNoJPXDecode, so a page whose images use
JPXDecode cannot be rasterized until you supply a decoder. RegisterCustomStreamEncoder
is the hook for that, and it works for any filter name, not just JPX.
Despite the page title, the custom encoder affects the input side. The rendered output is still written by the image device, as PNG or JPEG.
Doing it
core.RegisterCustomStreamEncoder(core.StreamEncodingFilterNameJPX, jpeg2k.NewCustomJPXEncoder())
device := render.NewImageDevice()
if err := device.RenderToPath(page, "page.png"); err != nil {
return err
}Registration is global and keyed by filter name, so one call before you start
reading covers every stream in every document. NewEncoderFromStream checks the
registry before its own switch statement, which means a registered encoder also
overrides a filter UniPDF does support, Flate included. Register only the filters
you mean to take over.
The value you pass has to implement core.StreamEncoder: GetFilterName,
MakeDecodeParams, MakeStreamDict, UpdateParams, EncodeBytes, DecodeBytes
and DecodeStream. Decoding only needs DecodeStream and DecodeBytes to work;
the example’s EncodeBytes returns an error, which is fine because rendering never
encodes.
DecodeStream receives the whole stream object, not just its bytes, and that
matters for JPX. A JPEG2000 codestream carries its own color space, but when the
image dictionary has a /ColorSpace entry, the PDF spec says the dictionary wins.
The example reads that entry first and uses it to decide how to interpret the
samples, then delegates to DecodeBytes.
What comes back is raw samples, not a file. The example returns one, three or four
components per pixel at the image’s bit depth, row by row, with no header,
matching the /ColorSpace and /BitsPerComponent the image dictionary already
declares.
Limitations
The example decoder wraps ImageMagick through gopkg.in/gographics/imagick.v2, so
it needs cgo and an ImageMagick installation. That is why the filename ends in
_cgo. It handles gray, RGB, sRGB and CMYK at 8 or 16 bits per component and
returns an error for any other color space or bit depth. An indexed PDF color
space is special-cased: the image is converted to gray and negated before the
samples are read out.
Registration is process-wide and there is no call to remove an entry. In a program that reads documents of mixed provenance, whatever you register applies to all of them.
Run the example
pdf_image_render_custom_encoder_cgo.go registers jpeg2k.NewCustomJPXEncoder
and then renders exactly like the plain example. The interesting file is
jpeg2k/lib_jpeg2k_encoder.go, which holds the CustomJPXEncoder implementation.
git clone https://github.com/unidoc/unipdf-examples.git
cd unipdf-examples/render
go run pdf_image_render_custom_encoder_cgo.go OUTPUT_DIR INPUT.pdfIf this is your first time using UniPDF, follow the getting started guide to create an API key and set up your development environment.