This code replaces the image stream without having to alter COSWriter (which sounds scary), however my experience with the PDF I tried was that the encoded image was incorrect, i.e. that there is a bug in the JPEG 2000 encoder, so check your result PDFs.
public class SO57972743
{
public static void main(String[] args) throws IOException
{
System.out.println("supported formats: " + Arrays.toString(ImageIO.getReaderFormatNames()));
try (PDDocument doc = PDDocument.load(new File("test.pdf")))
{
// get 1st level images only here (there may be more in form XObjects!)
PDResources res = doc.getPage(0).getResources();
for (COSName name : res.getXObjectNames())
{
PDXObject xObject = res.getXObject(name);
if (xObject instanceof PDImageXObject)
{
replaceImageWithJPX(xObject);
}
}
doc.save("test-result.pdf");
}
}
private static void replaceImageWithJPX(PDXObject xObject) throws IOException
{
PDImageXObject img = (PDImageXObject) xObject;
BufferedImage bim = img.getOpaqueImage(); // the mask (if there) won't be touched
ByteArrayOutputStream baos = new ByteArrayOutputStream();
boolean written = ImageIO.write(bim, "JPEG2000", baos);
if (!written)
{
System.err.println("write failed");
return;
}
// replace image stream
try (OutputStream os = img.getCOSObject().createRawOutputStream())
{
os.write(baos.toByteArray());
}
img.getCOSObject().setItem(COSName.FILTER, COSName.JPX_DECODE); // replace filter
img.getCOSObject().removeItem(COSName.COLORSPACE); // use the colorspace in the image itself
}
}