// numberOfInterleavedComponents = (cm.hasAlpha() ? 1 : 0) + cm.getNumColorComponents();
numberOfInterleavedComponents = cm.getNumComponents();
}
// set up image compression for non-alpha channel
FlateFilter flate;
try {
flate = new FlateFilter();
flate.setApplied(true);
flate.setPredictor(FlateFilter.PREDICTION_PNG_OPT);
if (numberOfInterleavedComponents < 3) {
// means palette (1) or gray (1) or gray + alpha (2)
flate.setColors(1);
} else {
// means rgb (3) or rgb + alpha (4)
flate.setColors(3);
}
flate.setColumns(image.getSize().getWidthPx());
flate.setBitsPerComponent(this.getBitsPerComponent());
} catch (PDFFilterException e) {
throw new RuntimeException("FlateFilter configuration error", e);
}
this.pdfFilter = flate;
this.disallowMultipleFilters();
// Handle transparency channel if applicable; note that for palette images the transparency is
// not TRANSLUCENT
if (cm.hasAlpha() && cm.getTransparency() == ColorModel.TRANSLUCENT) {
doc.getProfile().verifyTransparencyAllowed(image.getInfo().getOriginalURI());
// TODO: Implement code to combine image with background color if transparency is not allowed
// here we need to inflate the PNG pixel data, which includes alpha, separate the alpha channel
// and then deflate it back again
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DeflaterOutputStream dos = new DeflaterOutputStream(baos, new Deflater());
InputStream in = ((ImageRawStream) image).createInputStream();
try {
InflaterInputStream infStream = new InflaterInputStream(in, new Inflater());
DataInputStream dataStream = new DataInputStream(infStream);
// offset is the byte offset of the alpha component
int offset = numberOfInterleavedComponents - 1; // 1 for GA, 3 for RGBA
int numColumns = image.getSize().getWidthPx();
int bytesPerRow = numberOfInterleavedComponents * numColumns;
int filter;
// read line by line; the first byte holds the filter
while ((filter = dataStream.read()) != -1) {
byte[] bytes = new byte[bytesPerRow];
dataStream.readFully(bytes, 0, bytesPerRow);
dos.write((byte) filter);
for (int j = 0; j < numColumns; j++) {
dos.write(bytes, offset, 1);
offset += numberOfInterleavedComponents;
}
offset = numberOfInterleavedComponents - 1;
}
dos.close();
} catch (IOException e) {
throw new RuntimeException("Error processing transparency channel:", e);
} finally {
IOUtils.closeQuietly(in);
}
// set up alpha channel compression
FlateFilter transFlate;
try {
transFlate = new FlateFilter();
transFlate.setApplied(true);
transFlate.setPredictor(FlateFilter.PREDICTION_PNG_OPT);
transFlate.setColors(1);
transFlate.setColumns(image.getSize().getWidthPx());
transFlate.setBitsPerComponent(this.getBitsPerComponent());
} catch (PDFFilterException e) {
throw new RuntimeException("FlateFilter configuration error", e);
}
BitmapImage alphaMask = new BitmapImage("Mask:" + this.getKey(), image.getSize().getWidthPx(),
image.getSize().getHeightPx(), baos.toByteArray(), null);