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

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;

};

CPP

This custom transform can then be used as follows:

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

CPP


Created Date: 01 Dec, 2021 13:48
Last Modifed Date: 01 Dec, 2021 13:48