in fop-core/src/main/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java [276:395]
private AFPDataObjectInfo encodeImage(
AFPImageObjectInfo imageObjectInfo,
AFPPaintingState paintingState)
throws IOException {
RenderedImage renderedImage = imageRendered.getRenderedImage();
FunctionSet functionSet = useFS10 ? FunctionSet.FS10 : FunctionSet.FS11;
if (usePageSegments) {
assert resampledDim != null;
//Resize, optionally resample and convert image
imageObjectInfo.setCreatePageSegment(true);
float ditheringQuality = paintingState.getDitheringQuality();
if (this.resample) {
if (log.isDebugEnabled()) {
log.debug("Resample from " + intrinsicSize.getDimensionPx()
+ " to " + resampledDim);
}
renderedImage = BitmapImageUtil.convertToMonochrome(renderedImage,
resampledDim, ditheringQuality);
} else if (ditheringQuality >= 0.5f) {
renderedImage = BitmapImageUtil.convertToMonochrome(renderedImage,
intrinsicSize.getDimensionPx(), ditheringQuality);
}
}
imageObjectInfo.setUseIocaImages(paintingState.isUseIocaImages());
//TODO To reduce AFP file size, investigate using a compression scheme.
//Currently, all image data is uncompressed.
ColorModel cm = renderedImage.getColorModel();
if (log.isTraceEnabled()) {
log.trace("ColorModel: " + cm);
}
int pixelSize = cm.getPixelSize();
if (cm.hasAlpha()) {
pixelSize -= 8;
}
byte[] imageData = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
boolean allowDirectEncoding = true;
if (allowDirectEncoding && (pixelSize <= maxPixelSize)) {
//Attempt to encode without resampling the image
ImageEncodingHelper helper = new ImageEncodingHelper(renderedImage,
pixelSize == 32);
ColorModel encodedColorModel = helper.getEncodedColorModel();
boolean directEncode = true;
if (helper.getEncodedColorModel().getPixelSize() > maxPixelSize) {
directEncode = false; //pixel size needs to be reduced
}
if (BitmapImageUtil.getColorIndexSize(renderedImage) > 2) {
directEncode = false; //Lookup tables are not implemented, yet
}
if (useFS10
&& BitmapImageUtil.isMonochromeImage(renderedImage)
&& BitmapImageUtil.isZeroBlack(renderedImage)) {
directEncode = false;
//need a special method to invert the bit-stream since setting the
//subtractive mode in AFP alone doesn't seem to do the trick.
if (encodeInvertedBilevel(helper, imageObjectInfo, baos)) {
imageData = baos.toByteArray();
}
}
if (directEncode) {
log.debug("Encoding image directly...");
imageObjectInfo.setBitsPerPixel(encodedColorModel.getPixelSize());
if (pixelSize == 32) {
functionSet = FunctionSet.FS45; //IOCA FS45 required for CMYK
}
//Lossy or loss-less?
if (!paintingState.canEmbedJpeg()
&& paintingState.getBitmapEncodingQuality() < 1.0f) {
try {
if (log.isDebugEnabled()) {
log.debug("Encoding using baseline DCT (JPEG, q="
+ paintingState.getBitmapEncodingQuality() + ")...");
}
encodeToBaselineDCT(renderedImage,
paintingState.getBitmapEncodingQuality(),
paintingState.getResolution(),
baos);
imageObjectInfo.setCompression(ImageContent.COMPID_JPEG);
if (!paintingState.isUseIocaImages()) {
imageObjectInfo.setMimeType("image/jpeg");
}
} catch (IOException ioe) {
//Some JPEG codecs cannot encode CMYK
helper.encode(baos);
}
} else {
helper.encode(baos);
}
imageData = baos.toByteArray();
}
}
if (imageData == null) {
log.debug("Encoding image via RGB...");
imageData = encodeViaRGB(renderedImage, imageObjectInfo, paintingState, baos);
}
// Should image be FS45?
if (paintingState.getFS45()) {
functionSet = FunctionSet.FS45;
}
//Wrapping 300+ resolution FS11 IOCA in a page segment is apparently necessary(?)
imageObjectInfo.setCreatePageSegment(
(functionSet.equals(FunctionSet.FS11) || functionSet.equals(FunctionSet.FS45))
&& paintingState.getWrapPSeg()
);
if (imageObjectInfo.getMimeType() == null) {
imageObjectInfo.setMimeType(functionSet.getMimeType());
}
imageObjectInfo.setData(imageData);
return imageObjectInfo;
}