Без потерь в швах PDFBox очень плохо справляется со сжатием PNG.Глядя на код, кажется, что он не делает то, что говорит Javadoc (используйте LZW) [1], но я могу ошибаться.
Любые идеи о том, как передать двоичный поток PNG с exec через, например, pngquantа затем создать PDImageXObject из полученного двоичного файла?
images-001-000.png PNG 2480x3508 2480x3508+0+0 8-bit sRGB 1.261MB 0.000u 0:00.000
Сокращение пикселей, запись его в PDFBox, извлечение с помощью pdffiles и использование идентификаторов возврата
images-shrink-001-000.png PNG 874x1237 874x1237+0+0 8-bit sRGB 1.038MB 0.000u 0:00.000
Хотя количество пикселей очень многонамного меньше, изображение только немного меньше.
Используя квантование, чтобы показать максимально возможное уменьшение, я использую pngquant для сравнения,
images-quant-001-000.png PNG 874x1237 874x1237+0+0 8-bit sRGB 256c 673KB 0.000u 0:00.000
[1]
/**
* Create a PDImageXObject while making a decision whether not to
* compress, use Flate filter only, or Flate and LZW filters.
*
* @param document The document.
* @param byteArray array with data.
* @param width the image width
* @param height the image height
* @param bitsPerComponent the bits per component
* @param initColorSpace the color space
* @return the newly created PDImageXObject with the data compressed.
* @throws IOException
*/
private static PDImageXObject prepareImageXObject(PDDocument document,
byte [] byteArray, int width, int height, int bitsPerComponent,
PDColorSpace initColorSpace) throws IOException
{
//pre-size the output stream to half of the input
ByteArrayOutputStream baos = new ByteArrayOutputStream(byteArray.length/2);
Filter filter = FilterFactory.INSTANCE.getFilter(COSName.FLATE_DECODE);
filter.encode(new ByteArrayInputStream(byteArray), baos, new COSDictionary(), 0);
ByteArrayInputStream encodedByteStream = new ByteArrayInputStream(baos.toByteArray());
return new PDImageXObject(document, encodedByteStream, COSName.FLATE_DECODE,
width, height, bitsPerComponent, initColorSpace);
}