in pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/LosslessFactory.java [343:500]
PDImageXObject encode() throws IOException
{
Raster imageRaster = image.getRaster();
final int elementsInRowPerPixel;
// These variables store a row of the image each, the exact type depends
// on the image encoding. Can be a int[], short[] or byte[]
Object prevRow;
Object transferRow;
switch (imageType)
{
case BufferedImage.TYPE_CUSTOM:
switch (imageRaster.getTransferType())
{
case DataBuffer.TYPE_USHORT:
elementsInRowPerPixel = componentsPerPixel;
prevRow = new short[width * elementsInRowPerPixel];
transferRow = new short[width * elementsInRowPerPixel];
break;
case DataBuffer.TYPE_BYTE:
elementsInRowPerPixel = componentsPerPixel;
prevRow = new byte[width * elementsInRowPerPixel];
transferRow = new byte[width * elementsInRowPerPixel];
break;
default:
return null;
}
break;
case BufferedImage.TYPE_3BYTE_BGR:
case BufferedImage.TYPE_4BYTE_ABGR:
elementsInRowPerPixel = componentsPerPixel;
prevRow = new byte[width * elementsInRowPerPixel];
transferRow = new byte[width * elementsInRowPerPixel];
break;
case BufferedImage.TYPE_INT_BGR:
case BufferedImage.TYPE_INT_ARGB:
case BufferedImage.TYPE_INT_RGB:
elementsInRowPerPixel = 1;
prevRow = new int[width * elementsInRowPerPixel];
transferRow = new int[width * elementsInRowPerPixel];
break;
default:
// We can not handle this unknown format
return null;
}
final int elementsInTransferRow = width * elementsInRowPerPixel;
// pre-size the output stream to half of the maximum size
ByteArrayOutputStream stream = new ByteArrayOutputStream(
height * width * bytesPerPixel / 2);
Deflater deflater = new Deflater(Filter.getCompressionLevel());
DeflaterOutputStream zip = new DeflaterOutputStream(stream, deflater);
int alphaPtr = 0;
for (int rowNum = 0; rowNum < height; rowNum++)
{
imageRaster.getDataElements(0, rowNum, width, 1, transferRow);
// We start to write at index one, as the predictor marker is in index zero
int writerPtr = 1;
Arrays.fill(aValues, (byte) 0);
Arrays.fill(cValues, (byte) 0);
final byte[] transferRowByte;
final byte[] prevRowByte;
final int[] transferRowInt;
final int[] prevRowInt;
final short[] transferRowShort;
final short[] prevRowShort;
if (transferRow instanceof byte[])
{
transferRowByte = (byte[]) transferRow;
prevRowByte = (byte[]) prevRow;
transferRowInt = prevRowInt = null;
transferRowShort = prevRowShort = null;
}
else if (transferRow instanceof int[])
{
transferRowInt = (int[]) transferRow;
prevRowInt = (int[]) prevRow;
transferRowShort = prevRowShort = null;
transferRowByte = prevRowByte = null;
}
else
{
// This must be short[]
transferRowShort = (short[]) transferRow;
prevRowShort = (short[]) prevRow;
transferRowInt = prevRowInt = null;
transferRowByte = prevRowByte = null;
}
for (int indexInTransferRow = 0; indexInTransferRow < elementsInTransferRow;
indexInTransferRow += elementsInRowPerPixel, alphaPtr += bytesPerComponent)
{
// Copy the pixel values into the byte array
if (transferRowByte != null)
{
copyImageBytes(transferRowByte, indexInTransferRow, xValues, alphaImageData,
alphaPtr);
copyImageBytes(prevRowByte, indexInTransferRow, bValues, null, 0);
}
else if (transferRowInt != null)
{
copyIntToBytes(transferRowInt, indexInTransferRow, xValues, alphaImageData,
alphaPtr);
copyIntToBytes(prevRowInt, indexInTransferRow, bValues, null, 0);
}
else
{
// This must be short[]
copyShortsToBytes(transferRowShort, indexInTransferRow, xValues, alphaImageData, alphaPtr);
copyShortsToBytes(prevRowShort, indexInTransferRow, bValues, null, 0);
}
// Encode the pixel values in the different encodings
int length = xValues.length;
for (int bytePtr = 0; bytePtr < length; bytePtr++)
{
int x = xValues[bytePtr] & 0xFF;
int a = aValues[bytePtr] & 0xFF;
int b = bValues[bytePtr] & 0xFF;
int c = cValues[bytePtr] & 0xFF;
dataRawRowNone[writerPtr] = (byte) x;
dataRawRowSub[writerPtr] = pngFilterSub(x, a);
dataRawRowUp[writerPtr] = pngFilterUp(x, b);
dataRawRowAverage[writerPtr] = pngFilterAverage(x, a, b);
dataRawRowPaeth[writerPtr] = pngFilterPaeth(x, a, b, c);
writerPtr++;
}
// We shift the values into the prev / upper left values for the next pixel
System.arraycopy(xValues, 0, aValues, 0, bytesPerPixel);
System.arraycopy(bValues, 0, cValues, 0, bytesPerPixel);
}
byte[] rowToWrite = chooseDataRowToWrite();
// Write and compress the row as long it is hot (CPU cache wise)
zip.write(rowToWrite, 0, rowToWrite.length);
// We swap prev and transfer row, so that we have the prev row for the next row.
Object temp = prevRow;
prevRow = transferRow;
transferRow = temp;
}
zip.close();
deflater.end();
return preparePredictorPDImage(stream, bytesPerComponent * 8);
}