Skip to main content
Skip table of contents

16-bit images in PDF output


Introduction

In Mako, the IDOMImage class represents an image. Images can be loaded from a file:

CPP
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:

CPP
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"));

Maintaining 16-images in PDF output

Currently, Mako will encode 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 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.

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);
}


JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.