Skip to main content
Skip table of contents

How to change image compression from RLE to flate in a PDF document.

There is sometimes a requirement to recompress images to a different filter, often to make the PDF smaller. This example converts all images that use the RLE filter to replace it with the flate decode filter.

It can be amended to handle other filter types.

The example uses a custom transform (see Custom transforms) which can iterate through all the images on a page and replace the RLE filter images with flate decode images.

Recompression Custom Transform

CPP
class Recompression : public ICustomTransform::IImplementation
{
public:
    Recompression(const IJawsMakoPtr& jawsMako)
    {
        this->jawsMako = jawsMako;
    };
    ~Recompression()
    {
    };

    IDOMImagePtr transformImage(IImplementation* genericImplementation, const IDOMImagePtr& image, const CTransformState& state)
    {
        auto imageType = image->getImageType();
        if (imageType == eDOMImageType::eDITRunLength)
        {
            IImageDecoderPtr decoder = image->createImageDecoder(jawsMako, image->getImageProperties());
            IImageFramePtr frame = decoder->getFrame();
            IDOMColorSpacePtr colorspace = frame->getColorSpace();
            uint32 width = frame->getWidth();
            uint32 height = frame->getHeight();
            uint32 bps = frame->getBPS();
            uint8 numComponents = colorspace->getNumComponents();
            IInputStreamPtr stream = image->getStream();

            CEDLVector<float> decodeArray;
            for (int i = 0; i < numComponents; i++)
            {
                float low = 0;
                float high = 0;
                colorspace->getComponentRange(i, low, high);
                decodeArray.append(low);
                decodeArray.append(high);
            }

            uint32 bpr = frame->getRawBytesPerRow();
            uint8* buffer2 = (uint8*)malloc((size_t)(bpr * height));
            uint32 pos = 0;
            for (int y = 0; y < height; y++)
            {
                frame->readScanLine(&buffer2[pos], bpr);
                pos += bpr;
            }

            // Use Mako's temp store to store the compressed data
            IRAInputStreamPtr reader;
            IRAOutputStreamPtr writer;
            jawsMako->getTempStore()->createTemporaryReaderWriterPair(reader, writer);

            // Create a flate compressor - maximum quality
            IOutputStreamPtr flateWriter = IOutputStream::createToFlateCompressed(jawsMako, writer, 9, false);
            if (!flateWriter->open())
            {
                // Handle error appropriately
                throw std::runtime_error("Unable to open flate writer stream?");
            }

            // Write entire buffer in one lot
            if (!flateWriter->completeWrite(&buffer2[0], bpr * height))
            {
                throw std::runtime_error("Failed to write compressed flate data for band!");
            }

            flateWriter->close();

            // Create the IDOMPDFImage which will ferry this image data to the output PDF untouched.
            IDOMImagePtr newimage = IDOMPDFImage::create(jawsMako,
                reader,
                eDITFlate,
                IDOMPDFImage::FlateLZWParams::create(),
                colorspace, width, height, bps);
            return newimage;

        }
        return image;
    };
private:
    IJawsMakoPtr jawsMako;

};

This custom transform can then be used as follows:

CPP
	Recompression recompression(jawsMako);
    auto tf = ICustomTransform::create(jawsMako, &recompression);

	for (uint8 i = 0; i < document->getNumPages(); i++)
	{
		auto newPage = document->getPage(i)->clone();
        tf->transform(newPage->getContent(), changed);
        newDocument->appendPage(newPage);
    }


JavaScript errors detected

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

If this problem persists, please contact our support.