2018-06-11 22:41:11 +02:00
|
|
|
package ar.com.hjg.pngj;
|
|
|
|
|
|
|
|
/**
|
2018-09-22 11:17:30 +02:00
|
|
|
* Represents an image line, integer format (one integer by sample). See
|
|
|
|
* {@link #scanline} to understand the format.
|
2018-06-11 22:41:11 +02:00
|
|
|
*/
|
|
|
|
public class ImageLineInt implements IImageLine, IImageLineArray {
|
2018-09-22 11:17:30 +02:00
|
|
|
public final ImageInfo imgInfo;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The 'scanline' is an array of integers, corresponds to an image line
|
|
|
|
* (row).
|
|
|
|
* <p>
|
|
|
|
* Each <code>int</code> is a "sample" (one for channel), (0-255 or 0-65535)
|
|
|
|
* in the corresponding PNG sequence:
|
|
|
|
* <code>R G B R G B...</code> or <code>R G B A R G B A...</tt>
|
|
|
|
* or <code>g g g ...</code> or <code>i i i</code> (palette index)
|
|
|
|
* <p>
|
|
|
|
* For bitdepth=1/2/4 the value is not scaled (hence, eg, if bitdepth=2 the
|
|
|
|
* range will be 0-4)
|
|
|
|
* <p>
|
|
|
|
* To convert a indexed line to RGB values, see
|
|
|
|
* {@link ImageLineHelper#palette2rgb(ImageLineInt, ar.com.hjg.pngj.chunks.PngChunkPLTE, int[])}
|
|
|
|
* (you can't do the
|
|
|
|
* reverse)
|
|
|
|
*/
|
|
|
|
protected final int[] scanline;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* number of elements in the scanline
|
|
|
|
*/
|
|
|
|
protected final int size;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* informational ; only filled by the reader. not meaningful for interlaced
|
|
|
|
*/
|
|
|
|
protected FilterType filterType = FilterType.FILTER_UNKNOWN;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param imgInfo
|
|
|
|
* Inmutable ImageInfo, basic parameters of the image we are
|
|
|
|
* reading or writing
|
|
|
|
*/
|
|
|
|
public ImageLineInt(final ImageInfo imgInfo) {
|
|
|
|
this(imgInfo, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param imgInfo
|
|
|
|
* Inmutable ImageInfo, basic parameters of the image we are
|
|
|
|
* reading or writing
|
|
|
|
* @param sci
|
|
|
|
* prealocated buffer (can be null)
|
|
|
|
*/
|
|
|
|
public ImageLineInt(final ImageInfo imgInfo, final int[] sci) {
|
|
|
|
this.imgInfo = imgInfo;
|
|
|
|
filterType = FilterType.FILTER_UNKNOWN;
|
|
|
|
size = imgInfo.samplesPerRow;
|
|
|
|
scanline = sci != null && sci.length >= size ? sci : new int[size];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper method, returns a default factory for this object
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public static IImageLineFactory<ImageLineInt> getFactory() {
|
|
|
|
return iminfo -> new ImageLineInt(iminfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public FilterType getFilterType() {
|
|
|
|
return filterType;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This should rarely be used by client code. Only relevant if
|
|
|
|
* FilterPreserve==true
|
|
|
|
*/
|
|
|
|
public void setFilterType(final FilterType ft) {
|
|
|
|
filterType = ft;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Basic info
|
|
|
|
*/
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return " cols=" + imgInfo.cols + " bpc=" + imgInfo.bitDepth + " size=" + scanline.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void readFromPngRaw(final byte[] raw, final int len, final int offset, final int step) {
|
|
|
|
setFilterType(FilterType.getByVal(raw[0]));
|
|
|
|
final int len1 = len - 1;
|
|
|
|
final int step1 = (step - 1) * imgInfo.channels;
|
|
|
|
if (imgInfo.bitDepth == 8) {
|
|
|
|
if (step == 1)
|
|
|
|
for (int i = 0; i < size; i++)
|
|
|
|
scanline[i] = raw[i + 1] & 0xff;
|
|
|
|
else
|
|
|
|
for (int s = 1, c = 0, i = offset * imgInfo.channels; s <= len1; s++, i++) {
|
|
|
|
scanline[i] = raw[s] & 0xff;
|
|
|
|
c++;
|
|
|
|
if (c == imgInfo.channels) {
|
|
|
|
c = 0;
|
|
|
|
i += step1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (imgInfo.bitDepth == 16) {
|
|
|
|
if (step == 1)
|
|
|
|
for (int i = 0, s = 1; i < size; i++)
|
|
|
|
scanline[i] = (raw[s++] & 0xFF) << 8 | raw[s++] & 0xFF; // 16 bitspc
|
|
|
|
else
|
|
|
|
for (int s = 1, c = 0, i = offset != 0 ? offset * imgInfo.channels : 0; s <= len1; s++, i++) {
|
|
|
|
scanline[i] = (raw[s++] & 0xFF) << 8 | raw[s] & 0xFF; // 16 bitspc
|
|
|
|
c++;
|
|
|
|
if (c == imgInfo.channels) {
|
|
|
|
c = 0;
|
|
|
|
i += step1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else { // packed formats
|
|
|
|
int mask0, mask, shi, bd;
|
|
|
|
bd = imgInfo.bitDepth;
|
|
|
|
mask0 = ImageLineHelper.getMaskForPackedFormats(bd);
|
|
|
|
for (int i = offset * imgInfo.channels, r = 1, c = 0; r < len; r++) {
|
|
|
|
mask = mask0;
|
|
|
|
shi = 8 - bd;
|
|
|
|
do {
|
|
|
|
scanline[i++] = (raw[r] & mask) >> shi;
|
|
|
|
mask >>= bd;
|
|
|
|
shi -= bd;
|
|
|
|
c++;
|
|
|
|
if (c == imgInfo.channels) {
|
|
|
|
c = 0;
|
|
|
|
i += step1;
|
|
|
|
}
|
|
|
|
} while (mask != 0 && i < size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void writeToPngRaw(final byte[] raw) {
|
|
|
|
raw[0] = (byte) filterType.val;
|
|
|
|
if (imgInfo.bitDepth == 8)
|
|
|
|
for (int i = 0; i < size; i++)
|
|
|
|
raw[i + 1] = (byte) scanline[i];
|
|
|
|
else if (imgInfo.bitDepth == 16)
|
|
|
|
for (int i = 0, s = 1; i < size; i++) {
|
|
|
|
raw[s++] = (byte) (scanline[i] >> 8);
|
|
|
|
raw[s++] = (byte) (scanline[i] & 0xff);
|
|
|
|
}
|
|
|
|
else { // packed formats
|
|
|
|
int shi, bd, v;
|
|
|
|
bd = imgInfo.bitDepth;
|
|
|
|
shi = 8 - bd;
|
|
|
|
v = 0;
|
|
|
|
for (int i = 0, r = 1; i < size; i++) {
|
|
|
|
v |= scanline[i] << shi;
|
|
|
|
shi -= bd;
|
|
|
|
if (shi < 0 || i == size - 1) {
|
|
|
|
raw[r++] = (byte) v;
|
|
|
|
shi = 8 - bd;
|
|
|
|
v = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Does nothing in this implementation
|
|
|
|
*/
|
|
|
|
@Override
|
|
|
|
public void endReadFromPngRaw() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see #size
|
|
|
|
*/
|
|
|
|
@Override
|
|
|
|
public int getSize() {
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int getElem(final int i) {
|
|
|
|
return scanline[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return see {@link #scanline}
|
|
|
|
*/
|
|
|
|
public int[] getScanline() {
|
|
|
|
return scanline;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ImageInfo getImageInfo() {
|
|
|
|
return imgInfo;
|
|
|
|
}
|
2018-06-11 22:41:11 +02:00
|
|
|
}
|