16-bit images in PDF output
📌 Overview
This article explains how to maintain 16-bit images in the PDF output. In Mako, the IDOMImage
class represents an image. Images can be loaded from a file:
const auto mako = IJawsMako::create();
IJawsMako::enableAllFeatures(mako);
...
U8String inputFile = "MyImage.tif";
const auto image = IDOMTIFFImage::create(mako, IInputStream::createFromFile(mako, inputFile));
Images are also created by rendering a PDF page. In this example, to a 16 bits-per-sample, CMYK image:
IJawsMakoPtr mako = IJawsMako::create();
IJawsMako::enableAllFeatures(mako);
String inputFile = "MyFile.pdf";
...
// Create an input
IPDFInputPtr input = IPDFInput::create(mako);
// Get the assembly from the input
IDocumentAssemblyPtr assembly = input->open(inputFile);
// Get the document from the assembly
IDocumentPtr document = assembly->getDocument();
// Get first page
IDOMFixedPagePtr fixedPage = document->getPage(0)->getContent();
// Render the page 16bpp, cmyk
IJawsRendererPtr renderer = IJawsRenderer::create(mako);
IDOMImage composite = renderer->render(
fixedPage,
renderResolution,
16,
IDOMColorSpaceDeviceCMYK::create(mako)
);
// Write a TIFF
IDOMTIFFImage::encode(mako, composite, IOutputStream::createToFile(mako, "render.tif"));
📗 Instructions
Currently, Mako encodes IDOMImages
to 8-bits when writing PDF output, even though the IDOMImage
may be 16-bit. This limitation can be circumvented by converting to an IDOMPDFImage
. An IDOMPDFImage
represents the native format for images in PDF. When Mako writes a page that contains such images to a PDF file, they are passed directly into the output without further processing, thereby preserving 16-bit images. This means that compression of the image must be handled when creating an IDOMPDFImage
, but this is easily achieved with a stream creator that supports compression. This function shows it in action.
🪜 Steps
Get image particulars: Get the frame, color space, width, height, bps and
rawBytes
properties.Compress the image: Use a “flate writer”, created using
IOutputStream::createToFlateCompressed()
to compress the image.Create the new image: Use
IDOMPDFImage::create()
to make the new image which will preserve 16-bit encoding.
⌨️ Sample Code
This is also available at GetAsPdfImage.cpp.
/**
* \brief Create a flate-compressed IDOMPDFImage from an IDOMImage. This allows 16-bit images to be passed to PDF output
* \param mako Pointer to Mako instance
* \param image Pointer to IDOMImage
* \return IDOMPDFImage
*/
IDOMPDFImagePtr getAsPdfImage(const IJawsMakoPtr& mako, const IDOMImagePtr& image)
{
// Get image particulars
const auto frame = image->getImageFrame(mako);
const auto colorSpace = frame->getColorSpace();
const auto width = frame->getWidth();
const auto height = frame->getHeight();
const auto bps = frame->getBPS();
const auto rawBytes = frame->getRawBytesPerRow();
// Compress the image
IRAInputStreamPtr reader;
IRAOutputStreamPtr writer;
mako->getTempStore()->createTemporaryReaderWriterPair(reader, writer);
{
const auto flateWriter = IOutputStream::createToFlateCompressed(mako, writer, 5, false);
if (!flateWriter->open())
{
throw std::runtime_error("Failed to create flate stream");
}
const uint32 actualStride = (width * colorSpace->getNumComponents() * bps + 7) / 8;
if (actualStride > rawBytes)
{
throw std::runtime_error("Failed to calculate stride correctly");
}
CEDLVector<uint8> rowBuffer(rawBytes);
for (uint32 y = 0; y < height; y++)
{
frame->readScanLine(&rowBuffer[0], rawBytes);
if (!flateWriter->completeWrite(&rowBuffer[0], static_cast<int32>(actualStride)))
{
throwEDLError(EDL_ERR_IMAGE_DECODE_FAILURE);
}
}
if (!flateWriter->flush())
{
throw std::runtime_error("Failed to flush flate stream");
}
flateWriter->close();
}
// Create the new image
return IDOMPDFImage::create(mako,
reader,
eDITFlate,
IDOMPDFImage::FlateLZWParams::create(),
colorSpace, width, height, bps);
}
☑️ Conclusion
Handling 16-bit images in PDF output with Mako involves converting IDOMImages
to IDOMPDFImages
to preserve their bit depth. By following the outlined steps, users can ensure that their images maintain their quality and integrity when included in PDF files. The provided sample code demonstrates how to achieve this using flate compression, ensuring efficient and effective image handling.
📚 Additional Resources
If you need additional help, see our API documentation for detailed information on class/method usage, or raise a support ticket via our customer portal.