public BufferedImage getRGBImage() throws IOException {
if( image != null )
{
return image;
}
try
{
int width = getWidth();
int height = getHeight();
int bpc = getBitsPerComponent();
int predictor = getPredictor();
List filters = getPDStream().getFilters();
ColorModel cm;
byte[] array = getPDStream().getByteArray();
// Get the ColorModel right
PDColorSpace colorspace = getColorSpace();
if (colorspace == null)
{
log.error("getColorSpace() returned NULL. Predictor = " + getPredictor());
return null;
}
if (bpc == 1)
{
byte[] map = new byte[] {(byte)0x00, (byte)0xff};
cm = new IndexColorModel(1, 2, map, map, map, 1);
}
else
{
cm = colorspace.createColorModel( bpc );
}
log.info("ColorModel: " + cm.toString());
WritableRaster raster = cm.createCompatibleWritableRaster( width, height );
DataBufferByte buffer = (DataBufferByte)raster.getDataBuffer();
byte[] bufferData = buffer.getData();
/**
* PDF Spec 1.6 3.3.3 LZW and Flate predictor function
*
* Basically if predictor > 10 and LZW or Flate is being used then the
* predictor is not used.
*
* "For LZWDecode and FlateDecode, a Predictor value greater than or equal to 10
* merely indicates that a PNG predictor is in use; the specific predictor function
* used is explicitly encoded in the incoming data. The value of Predictor supplied
* by the decoding filter need not match the value used when the data was encoded
* if they are both greater than or equal to 10."
*/
if( predictor < 10 ||
filters == null || !(filters.contains( COSName.LZW_DECODE.getName()) ||
filters.contains( COSName.FLATE_DECODE.getName()) ) )
{
PredictorAlgorithm filter = PredictorAlgorithm.getFilter(predictor);
filter.setWidth(width);
filter.setHeight(height);
filter.setBpp((bpc * 3) / 8);
filter.decode(array, bufferData);
}
else
{
System.arraycopy( array, 0,bufferData, 0,
(array.length< bufferData.length?array.length: bufferData.length) );
}
image = new BufferedImage(cm, raster, false, null);
return image;
}
catch (Exception exception)
{
log.error(exception, exception);
//A NULL return is caught in pagedrawer.Invoke.process() so don't re-throw.
//Returning the NULL falls through to Phlip Koch's TODO section.
return null;
}
}
|