Skip to main content
Skip table of contents

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

📌 Overview

There is sometimes a requirement to recompress images to a different filter, often to make the PDF smaller. This article explains how to edit all images that use the RLE filter so that they use the flate decode filter instead.

📗 Instructions

The example below 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. It can also be amended to handle other filter types.

🪜 Steps

  1. Create a custom transform: Override the transformImage() method.

  2. Create a new image: generate variables for constructing a new IDOMPDFImage using the flate decode filter. Here is a code snippet from the example below:

    CPP
    IDOMPDFImage::create(jawsMako, reader, eDITFlate, IDOMPDFImage::FlateLZWParams::create(), colorspace, width, height, bps);
  3. Apply custom transform to page(s): call ICustomTransform::transform() on each page in the document.

⌨️ Sample Code

Here is an example of a custom transform and how it can be used on each page in a document.

Recompression Custom Transform
Click to expand this code sample
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);
    }

☑️ Conclusion

Changing image compression from RLE to flate in a PDF document can significantly reduce file size and improve performance. By using a custom transform to iterate through images and replace the RLE filter with the flate decode filter, users can efficiently manage image compression. This method not only optimizes the document but also provides flexibility to handle other filter types if needed.

📚 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.

JavaScript errors detected

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

If this problem persists, please contact our support.