mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-05 12:35:29 -04:00
#432: Alternate fix + more tests + better alpha handling for TIFF
This commit is contained in:
parent
6f9c83a0a9
commit
f71bcc5125
@ -9,6 +9,8 @@ import java.awt.image.ComponentSampleModel;
|
|||||||
import java.awt.image.SampleModel;
|
import java.awt.image.SampleModel;
|
||||||
import java.awt.image.WritableRaster;
|
import java.awt.image.WritableRaster;
|
||||||
|
|
||||||
|
import static java.awt.image.DataBuffer.getDataTypeSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ExtraSamplesColorModel.
|
* ExtraSamplesColorModel.
|
||||||
*
|
*
|
||||||
@ -22,10 +24,22 @@ final class ExtraSamplesColorModel extends ComponentColorModel {
|
|||||||
// still thinks it has numComponents == cs.getNumComponents() + 1 for most operations
|
// still thinks it has numComponents == cs.getNumComponents() + 1 for most operations
|
||||||
private final int numComponents;
|
private final int numComponents;
|
||||||
|
|
||||||
ExtraSamplesColorModel(ColorSpace cs, boolean isAlphaPremultiplied, int dataType, int extraComponents) {
|
ExtraSamplesColorModel(ColorSpace cs, boolean hasAlpha, boolean isAlphaPremultiplied, int dataType, int extraComponents) {
|
||||||
super(cs, true, isAlphaPremultiplied, Transparency.TRANSLUCENT, dataType);
|
super(cs, bitsArrayHelper(cs, dataType, extraComponents + (hasAlpha ? 1 : 0)), hasAlpha, isAlphaPremultiplied, Transparency.TRANSLUCENT, dataType);
|
||||||
Validate.isTrue(extraComponents > 0, "Extra components must be > 0");
|
Validate.isTrue(extraComponents > 0, "Extra components must be > 0");
|
||||||
this.numComponents = super.getNumComponents() + extraComponents;
|
this.numComponents = cs.getNumComponents() + (hasAlpha ? 1 : 0) + extraComponents;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int[] bitsArrayHelper(ColorSpace cs, int dataType, int extraComponents) {
|
||||||
|
int numBits = getDataTypeSize(dataType);
|
||||||
|
int numComponents = cs.getNumComponents() + extraComponents;
|
||||||
|
int[] bits = new int[numComponents];
|
||||||
|
|
||||||
|
for (int i = 0; i < numComponents; i++) {
|
||||||
|
bits[i] = numBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -45,16 +59,18 @@ final class ExtraSamplesColorModel extends ComponentColorModel {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WritableRaster getAlphaRaster(WritableRaster raster) {
|
public WritableRaster getAlphaRaster(WritableRaster raster) {
|
||||||
if (hasAlpha() == false) {
|
if (!hasAlpha()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
int x = raster.getMinX();
|
int x = raster.getMinX();
|
||||||
int y = raster.getMinY();
|
int y = raster.getMinY();
|
||||||
int[] band = new int[1];
|
int[] band = new int[] {getAlphaComponent()};
|
||||||
band[0] = super.getNumComponents() - 1;
|
|
||||||
return raster.createWritableChild(x, y, raster.getWidth(),
|
return raster.createWritableChild(x, y, raster.getWidth(), raster.getHeight(), x, y, band);
|
||||||
raster.getHeight(), x, y,
|
}
|
||||||
band);
|
|
||||||
|
private int getAlphaComponent() {
|
||||||
|
return super.getNumComponents() - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -438,18 +438,20 @@ public final class TIFFImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
int opaqueSamplesPerPixel = getOpaqueSamplesPerPixel(interpretation);
|
int opaqueSamplesPerPixel = getOpaqueSamplesPerPixel(interpretation);
|
||||||
|
|
||||||
// Spec says ExtraSamples are mandatory of extra samples, however known encoders
|
// Spec says ExtraSamples are mandatory for extra samples, however known encoders
|
||||||
// (ie. SeaShore) writes ARGB TIFFs without ExtraSamples.
|
// (ie. SeaShore) writes ARGB TIFFs without ExtraSamples.
|
||||||
long[] extraSamples = getValueAsLongArray(TIFF.TAG_EXTRA_SAMPLES, "ExtraSamples", false);
|
long[] extraSamples = getValueAsLongArray(TIFF.TAG_EXTRA_SAMPLES, "ExtraSamples", false);
|
||||||
if (extraSamples == null && samplesPerPixel > opaqueSamplesPerPixel) {
|
if (extraSamples == null && samplesPerPixel > opaqueSamplesPerPixel) {
|
||||||
// TODO: Log warning!
|
// TODO: Log warning!
|
||||||
// First extra is alpha, rest is "unspecified"
|
// First extra is alpha, rest is "unspecified" (0)
|
||||||
extraSamples = new long[samplesPerPixel - opaqueSamplesPerPixel];
|
extraSamples = new long[samplesPerPixel - opaqueSamplesPerPixel];
|
||||||
extraSamples[0] = TIFFBaseline.EXTRASAMPLE_UNASSOCIATED_ALPHA;
|
extraSamples[0] = TIFFBaseline.EXTRASAMPLE_UNASSOCIATED_ALPHA;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine alpha
|
// Determine alpha
|
||||||
boolean hasAlpha = extraSamples != null;
|
boolean hasAlpha = extraSamples != null
|
||||||
|
&& (extraSamples[0] == TIFFBaseline.EXTRASAMPLE_ASSOCIATED_ALPHA
|
||||||
|
|| extraSamples[0] == TIFFBaseline.EXTRASAMPLE_UNASSOCIATED_ALPHA);
|
||||||
boolean isAlphaPremultiplied = hasAlpha && extraSamples[0] == TIFFBaseline.EXTRASAMPLE_ASSOCIATED_ALPHA;
|
boolean isAlphaPremultiplied = hasAlpha && extraSamples[0] == TIFFBaseline.EXTRASAMPLE_ASSOCIATED_ALPHA;
|
||||||
int significantSamples = opaqueSamplesPerPixel + (hasAlpha ? 1 : 0);
|
int significantSamples = opaqueSamplesPerPixel + (hasAlpha ? 1 : 0);
|
||||||
|
|
||||||
@ -577,12 +579,12 @@ public final class TIFFImageReader extends ImageReaderBase {
|
|||||||
switch (planarConfiguration) {
|
switch (planarConfiguration) {
|
||||||
case TIFFBaseline.PLANARCONFIG_CHUNKY:
|
case TIFFBaseline.PLANARCONFIG_CHUNKY:
|
||||||
// "TYPE_4BYTE_RGBA" if cs.isCS_sRGB()
|
// "TYPE_4BYTE_RGBA" if cs.isCS_sRGB()
|
||||||
if (extraSamples != null && extraSamples.length == 1) {
|
if (hasAlpha && extraSamples.length == 1) {
|
||||||
return ImageTypeSpecifiers.createInterleaved(cs, new int[] {0, 1, 2, 3}, dataType, true, isAlphaPremultiplied);
|
return ImageTypeSpecifiers.createInterleaved(cs, new int[] {0, 1, 2, 3}, dataType, true, isAlphaPremultiplied);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return new ImageTypeSpecifier(
|
return new ImageTypeSpecifier(
|
||||||
new ExtraSamplesColorModel(cs, isAlphaPremultiplied, dataType, samplesPerPixel - significantSamples),
|
new ExtraSamplesColorModel(cs, hasAlpha, isAlphaPremultiplied, dataType, samplesPerPixel - significantSamples),
|
||||||
new PixelInterleavedSampleModel(dataType, 1, 1, samplesPerPixel, samplesPerPixel, createOffsets(samplesPerPixel))
|
new PixelInterleavedSampleModel(dataType, 1, 1, samplesPerPixel, samplesPerPixel, createOffsets(samplesPerPixel))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -614,9 +616,7 @@ public final class TIFFImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
IndexColorModel icm = createIndexColorModel(bitsPerSample, dataType, (int[]) colorMap.getValue());
|
IndexColorModel icm = createIndexColorModel(bitsPerSample, dataType, (int[]) colorMap.getValue());
|
||||||
|
|
||||||
if (extraSamples != null && extraSamples.length > 0
|
if (hasAlpha) {
|
||||||
&& (extraSamples[0] == TIFFBaseline.EXTRASAMPLE_ASSOCIATED_ALPHA
|
|
||||||
|| extraSamples[0] == TIFFBaseline.EXTRASAMPLE_UNASSOCIATED_ALPHA)) {
|
|
||||||
return ImageTypeSpecifiers.createDiscreteAlphaIndexedFromIndexColorModel(icm);
|
return ImageTypeSpecifiers.createDiscreteAlphaIndexedFromIndexColorModel(icm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1843,158 +1843,158 @@ public final class TIFFImageReader extends ImageReaderBase {
|
|||||||
case DataBuffer.TYPE_BYTE:
|
case DataBuffer.TYPE_BYTE:
|
||||||
|
|
||||||
/*for (int band = 0; band < bands; band++)*/ {
|
/*for (int band = 0; band < bands; band++)*/ {
|
||||||
int bank = banded ? ((BandedSampleModel) tileRowRaster.getSampleModel()).getBankIndices()[band] : band;
|
int bank = banded ? ((BandedSampleModel) tileRowRaster.getSampleModel()).getBankIndices()[band] : band;
|
||||||
|
|
||||||
byte[] rowDataByte = ((DataBufferByte) dataBuffer).getData(bank);
|
byte[] rowDataByte = ((DataBufferByte) dataBuffer).getData(bank);
|
||||||
WritableRaster destChannel = banded
|
WritableRaster destChannel = banded
|
||||||
? raster.createWritableChild(raster.getMinX(), raster.getMinY(), raster.getWidth(), raster.getHeight(), 0, 0, new int[] {band})
|
? raster.createWritableChild(raster.getMinX(), raster.getMinY(), raster.getWidth(), raster.getHeight(), 0, 0, new int[] {band})
|
||||||
: raster;
|
: raster;
|
||||||
Raster srcChannel = banded
|
Raster srcChannel = banded
|
||||||
? tileRowRaster.createChild(tileRowRaster.getMinX(), 0, tileRowRaster.getWidth(), 1, 0, 0, new int[] {band})
|
? tileRowRaster.createChild(tileRowRaster.getMinX(), 0, tileRowRaster.getWidth(), 1, 0, 0, new int[] {band})
|
||||||
: tileRowRaster;
|
: tileRowRaster;
|
||||||
|
|
||||||
for (int row = startRow; row < startRow + rowsInTile; row++) {
|
for (int row = startRow; row < startRow + rowsInTile; row++) {
|
||||||
if (row >= srcRegion.y + srcRegion.height) {
|
if (row >= srcRegion.y + srcRegion.height) {
|
||||||
break; // We're done with this tile
|
break; // We're done with this tile
|
||||||
}
|
|
||||||
|
|
||||||
input.readFully(rowDataByte);
|
|
||||||
|
|
||||||
if (row % ySub == 0 && row >= srcRegion.y) {
|
|
||||||
if (!banded) {
|
|
||||||
normalizeColor(interpretation, rowDataByte);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subsample horizontal
|
|
||||||
if (xSub != 1) {
|
|
||||||
for (int x = srcRegion.x / xSub * numBands; x < ((srcRegion.x + colsInTile) / xSub) * numBands; x += numBands) {
|
|
||||||
System.arraycopy(rowDataByte, x * xSub, rowDataByte, x, numBands);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
destChannel.setDataElements(startCol / xSub, (row - srcRegion.y) / ySub, srcChannel);
|
|
||||||
}
|
|
||||||
// Else skip data
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input.readFully(rowDataByte);
|
||||||
|
|
||||||
|
if (row % ySub == 0 && row >= srcRegion.y) {
|
||||||
|
if (!banded) {
|
||||||
|
normalizeColor(interpretation, rowDataByte);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subsample horizontal
|
||||||
|
if (xSub != 1) {
|
||||||
|
for (int x = srcRegion.x / xSub * numBands; x < ((srcRegion.x + colsInTile) / xSub) * numBands; x += numBands) {
|
||||||
|
System.arraycopy(rowDataByte, x * xSub, rowDataByte, x, numBands);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destChannel.setDataElements(startCol / xSub, (row - srcRegion.y) / ySub, srcChannel);
|
||||||
|
}
|
||||||
|
// Else skip data
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if (banded) {
|
// if (banded) {
|
||||||
// // TODO: Normalize colors for tile (need to know tile region and sample model)
|
// // TODO: Normalize colors for tile (need to know tile region and sample model)
|
||||||
// // Unfortunately, this will disable acceleration...
|
// // Unfortunately, this will disable acceleration...
|
||||||
// }
|
// }
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case DataBuffer.TYPE_USHORT:
|
case DataBuffer.TYPE_USHORT:
|
||||||
case DataBuffer.TYPE_SHORT:
|
case DataBuffer.TYPE_SHORT:
|
||||||
/*for (int band = 0; band < bands; band++)*/ {
|
/*for (int band = 0; band < bands; band++)*/ {
|
||||||
short[] rowDataShort = dataBuffer.getDataType() == DataBuffer.TYPE_USHORT
|
short[] rowDataShort = dataBuffer.getDataType() == DataBuffer.TYPE_USHORT
|
||||||
? ((DataBufferUShort) dataBuffer).getData(band)
|
? ((DataBufferUShort) dataBuffer).getData(band)
|
||||||
: ((DataBufferShort) dataBuffer).getData(band);
|
: ((DataBufferShort) dataBuffer).getData(band);
|
||||||
|
|
||||||
WritableRaster destChannel = banded
|
WritableRaster destChannel = banded
|
||||||
? raster.createWritableChild(raster.getMinX(), raster.getMinY(), raster.getWidth(), raster.getHeight(), 0, 0, new int[] {band})
|
? raster.createWritableChild(raster.getMinX(), raster.getMinY(), raster.getWidth(), raster.getHeight(), 0, 0, new int[] {band})
|
||||||
: raster;
|
: raster;
|
||||||
Raster srcChannel = banded
|
Raster srcChannel = banded
|
||||||
? tileRowRaster.createChild(tileRowRaster.getMinX(), 0, tileRowRaster.getWidth(), 1, 0, 0, new int[] {band})
|
? tileRowRaster.createChild(tileRowRaster.getMinX(), 0, tileRowRaster.getWidth(), 1, 0, 0, new int[] {band})
|
||||||
: tileRowRaster;
|
: tileRowRaster;
|
||||||
|
|
||||||
for (int row = startRow; row < startRow + rowsInTile; row++) {
|
for (int row = startRow; row < startRow + rowsInTile; row++) {
|
||||||
if (row >= srcRegion.y + srcRegion.height) {
|
if (row >= srcRegion.y + srcRegion.height) {
|
||||||
break; // We're done with this tile
|
break; // We're done with this tile
|
||||||
}
|
|
||||||
|
|
||||||
readFully(input, rowDataShort);
|
|
||||||
|
|
||||||
if (row >= srcRegion.y) {
|
|
||||||
normalizeColor(interpretation, rowDataShort);
|
|
||||||
|
|
||||||
// Subsample horizontal
|
|
||||||
if (xSub != 1) {
|
|
||||||
for (int x = srcRegion.x / xSub * numBands; x < ((srcRegion.x + colsInTile) / xSub) * numBands; x += numBands) {
|
|
||||||
System.arraycopy(rowDataShort, x * xSub, rowDataShort, x, numBands);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
destChannel.setDataElements(startCol / xSub, (row - srcRegion.y) / ySub, srcChannel);
|
|
||||||
// TODO: Possible speedup ~30%!:
|
|
||||||
// raster.setDataElements(startCol, row - srcRegion.y, colsInTile, 1, rowDataShort);
|
|
||||||
}
|
|
||||||
// Else skip data
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
readFully(input, rowDataShort);
|
||||||
|
|
||||||
|
if (row >= srcRegion.y) {
|
||||||
|
normalizeColor(interpretation, rowDataShort);
|
||||||
|
|
||||||
|
// Subsample horizontal
|
||||||
|
if (xSub != 1) {
|
||||||
|
for (int x = srcRegion.x / xSub * numBands; x < ((srcRegion.x + colsInTile) / xSub) * numBands; x += numBands) {
|
||||||
|
System.arraycopy(rowDataShort, x * xSub, rowDataShort, x, numBands);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destChannel.setDataElements(startCol / xSub, (row - srcRegion.y) / ySub, srcChannel);
|
||||||
|
// TODO: Possible speedup ~30%!:
|
||||||
|
// raster.setDataElements(startCol, row - srcRegion.y, colsInTile, 1, rowDataShort);
|
||||||
|
}
|
||||||
|
// Else skip data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
case DataBuffer.TYPE_INT:
|
case DataBuffer.TYPE_INT:
|
||||||
/*for (int band = 0; band < bands; band++)*/ {
|
/*for (int band = 0; band < bands; band++)*/ {
|
||||||
int[] rowDataInt = ((DataBufferInt) dataBuffer).getData(band);
|
int[] rowDataInt = ((DataBufferInt) dataBuffer).getData(band);
|
||||||
|
|
||||||
WritableRaster destChannel = banded
|
WritableRaster destChannel = banded
|
||||||
? raster.createWritableChild(raster.getMinX(), raster.getMinY(), raster.getWidth(), raster.getHeight(), 0, 0, new int[] {band})
|
? raster.createWritableChild(raster.getMinX(), raster.getMinY(), raster.getWidth(), raster.getHeight(), 0, 0, new int[] {band})
|
||||||
: raster;
|
: raster;
|
||||||
Raster srcChannel = banded
|
Raster srcChannel = banded
|
||||||
? tileRowRaster.createChild(tileRowRaster.getMinX(), 0, tileRowRaster.getWidth(), 1, 0, 0, new int[] {band})
|
? tileRowRaster.createChild(tileRowRaster.getMinX(), 0, tileRowRaster.getWidth(), 1, 0, 0, new int[] {band})
|
||||||
: tileRowRaster;
|
: tileRowRaster;
|
||||||
|
|
||||||
for (int row = startRow; row < startRow + rowsInTile; row++) {
|
for (int row = startRow; row < startRow + rowsInTile; row++) {
|
||||||
if (row >= srcRegion.y + srcRegion.height) {
|
if (row >= srcRegion.y + srcRegion.height) {
|
||||||
break; // We're done with this tile
|
break; // We're done with this tile
|
||||||
}
|
|
||||||
|
|
||||||
readFully(input, rowDataInt);
|
|
||||||
|
|
||||||
if (row >= srcRegion.y) {
|
|
||||||
normalizeColor(interpretation, rowDataInt);
|
|
||||||
|
|
||||||
// Subsample horizontal
|
|
||||||
if (xSub != 1) {
|
|
||||||
for (int x = srcRegion.x / xSub * numBands; x < ((srcRegion.x + colsInTile) / xSub) * numBands; x += numBands) {
|
|
||||||
System.arraycopy(rowDataInt, x * xSub, rowDataInt, x, numBands);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
destChannel.setDataElements(startCol / xSub, (row - srcRegion.y) / ySub, srcChannel);
|
|
||||||
}
|
|
||||||
// Else skip data
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
readFully(input, rowDataInt);
|
||||||
|
|
||||||
|
if (row >= srcRegion.y) {
|
||||||
|
normalizeColor(interpretation, rowDataInt);
|
||||||
|
|
||||||
|
// Subsample horizontal
|
||||||
|
if (xSub != 1) {
|
||||||
|
for (int x = srcRegion.x / xSub * numBands; x < ((srcRegion.x + colsInTile) / xSub) * numBands; x += numBands) {
|
||||||
|
System.arraycopy(rowDataInt, x * xSub, rowDataInt, x, numBands);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destChannel.setDataElements(startCol / xSub, (row - srcRegion.y) / ySub, srcChannel);
|
||||||
|
}
|
||||||
|
// Else skip data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case DataBuffer.TYPE_FLOAT:
|
case DataBuffer.TYPE_FLOAT:
|
||||||
/*for (int band = 0; band < bands; band++)*/ {
|
/*for (int band = 0; band < bands; band++)*/ {
|
||||||
float[] rowDataFloat = ((DataBufferFloat) tileRowRaster.getDataBuffer()).getData(band);
|
float[] rowDataFloat = ((DataBufferFloat) tileRowRaster.getDataBuffer()).getData(band);
|
||||||
|
|
||||||
WritableRaster destChannel = banded
|
WritableRaster destChannel = banded
|
||||||
? raster.createWritableChild(raster.getMinX(), raster.getMinY(), raster.getWidth(), raster.getHeight(), 0, 0, new int[] {band})
|
? raster.createWritableChild(raster.getMinX(), raster.getMinY(), raster.getWidth(), raster.getHeight(), 0, 0, new int[] {band})
|
||||||
: raster;
|
: raster;
|
||||||
Raster srcChannel = banded
|
Raster srcChannel = banded
|
||||||
? tileRowRaster.createChild(tileRowRaster.getMinX(), 0, tileRowRaster.getWidth(), 1, 0, 0, new int[] {band})
|
? tileRowRaster.createChild(tileRowRaster.getMinX(), 0, tileRowRaster.getWidth(), 1, 0, 0, new int[] {band})
|
||||||
: tileRowRaster;
|
: tileRowRaster;
|
||||||
|
|
||||||
for (int row = startRow; row < startRow + rowsInTile; row++) {
|
for (int row = startRow; row < startRow + rowsInTile; row++) {
|
||||||
if (row >= srcRegion.y + srcRegion.height) {
|
if (row >= srcRegion.y + srcRegion.height) {
|
||||||
break; // We're done with this tile
|
break; // We're done with this tile
|
||||||
}
|
|
||||||
|
|
||||||
readFully(input, rowDataFloat);
|
|
||||||
|
|
||||||
if (row >= srcRegion.y) {
|
|
||||||
normalizeColor(interpretation, rowDataFloat);
|
|
||||||
|
|
||||||
// Subsample horizontal
|
|
||||||
if (xSub != 1) {
|
|
||||||
for (int x = srcRegion.x / xSub * numBands; x < ((srcRegion.x + srcRegion.width) / xSub) * numBands; x += numBands) {
|
|
||||||
System.arraycopy(rowDataFloat, x * xSub, rowDataFloat, x, numBands);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
destChannel.setDataElements(startCol, row - srcRegion.y, srcChannel);
|
|
||||||
}
|
|
||||||
// Else skip data
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
readFully(input, rowDataFloat);
|
||||||
|
|
||||||
|
if (row >= srcRegion.y) {
|
||||||
|
normalizeColor(interpretation, rowDataFloat);
|
||||||
|
|
||||||
|
// Subsample horizontal
|
||||||
|
if (xSub != 1) {
|
||||||
|
for (int x = srcRegion.x / xSub * numBands; x < ((srcRegion.x + srcRegion.width) / xSub) * numBands; x += numBands) {
|
||||||
|
System.arraycopy(rowDataFloat, x * xSub, rowDataFloat, x, numBands);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destChannel.setDataElements(startCol, row - srcRegion.y, srcChannel);
|
||||||
|
}
|
||||||
|
// Else skip data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2287,7 +2287,7 @@ public final class TIFFImageReader extends ImageReaderBase {
|
|||||||
private InputStream createDecompressorStream(final int compression, final int width, final int bands, final InputStream stream) throws IOException {
|
private InputStream createDecompressorStream(final int compression, final int width, final int bands, final InputStream stream) throws IOException {
|
||||||
int fillOrder = getValueAsIntWithDefault(TIFF.TAG_FILL_ORDER, 1);
|
int fillOrder = getValueAsIntWithDefault(TIFF.TAG_FILL_ORDER, 1);
|
||||||
|
|
||||||
switch (compression) {
|
switch (compression) {
|
||||||
case TIFFBaseline.COMPRESSION_NONE:
|
case TIFFBaseline.COMPRESSION_NONE:
|
||||||
return stream;
|
return stream;
|
||||||
case TIFFBaseline.COMPRESSION_PACKBITS:
|
case TIFFBaseline.COMPRESSION_PACKBITS:
|
||||||
|
@ -0,0 +1,107 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.tiff;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.image.ResampleOp;
|
||||||
|
import com.twelvemonkeys.imageio.color.ColorSpaces;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.color.ColorSpace;
|
||||||
|
import java.awt.image.*;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
public class ExtraSamplesColorModelTest {
|
||||||
|
|
||||||
|
private BufferedImage createExtraSamplesImage(int w, int h, ColorSpace cs, boolean hasAlpha, int extraComponents) {
|
||||||
|
int samplesPerPixel = cs.getNumComponents() + (hasAlpha ? 1 : 0) + extraComponents;
|
||||||
|
|
||||||
|
ExtraSamplesColorModel colorModel = new ExtraSamplesColorModel(cs, hasAlpha, true, DataBuffer.TYPE_BYTE, extraComponents);
|
||||||
|
SampleModel sampleModel = new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE, w, h, samplesPerPixel, samplesPerPixel * w, createOffsets(samplesPerPixel));
|
||||||
|
|
||||||
|
WritableRaster raster = Raster.createWritableRaster(sampleModel, new Point(0, 0));
|
||||||
|
|
||||||
|
return new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), new Hashtable());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int[] createOffsets(int samplesPerPixel) {
|
||||||
|
int[] offsets = new int[samplesPerPixel];
|
||||||
|
for (int i = 0; i < samplesPerPixel; i++) {
|
||||||
|
offsets[i] = i;
|
||||||
|
}
|
||||||
|
return offsets;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testImageWithExtraSamplesCanBeResampledGray() {
|
||||||
|
for (int i = 1; i < 8; i++) {
|
||||||
|
BufferedImage bufferedImage = createExtraSamplesImage(10, 10, ColorSpaces.getColorSpace(ColorSpace.CS_GRAY), false, i);
|
||||||
|
BufferedImage resampled = new ResampleOp(5, 5, ResampleOp.FILTER_LANCZOS).filter(bufferedImage, null);
|
||||||
|
|
||||||
|
assertNotNull(resampled);
|
||||||
|
assertEquals(5, resampled.getWidth());
|
||||||
|
assertEquals(5, resampled.getHeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testImageWithExtraSamplesCanBeResampledGrayAlpha() {
|
||||||
|
for (int i = 1; i < 8; i++) {
|
||||||
|
BufferedImage bufferedImage = createExtraSamplesImage(10, 10, ColorSpaces.getColorSpace(ColorSpace.CS_GRAY), true, i);
|
||||||
|
BufferedImage resampled = new ResampleOp(5, 5, ResampleOp.FILTER_LANCZOS).filter(bufferedImage, null);
|
||||||
|
|
||||||
|
assertNotNull(resampled);
|
||||||
|
assertEquals(5, resampled.getWidth());
|
||||||
|
assertEquals(5, resampled.getHeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testImageWithExtraSamplesCanBeResampledRGB() {
|
||||||
|
for (int i = 1; i < 8; i++) {
|
||||||
|
BufferedImage bufferedImage = createExtraSamplesImage(10, 10, ColorSpaces.getColorSpace(ColorSpace.CS_sRGB), false, i);
|
||||||
|
BufferedImage resampled = new ResampleOp(5, 5, ResampleOp.FILTER_LANCZOS).filter(bufferedImage, null);
|
||||||
|
|
||||||
|
assertNotNull(resampled);
|
||||||
|
assertEquals(5, resampled.getWidth());
|
||||||
|
assertEquals(5, resampled.getHeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testImageWithExtraSamplesCanBeResampledRGBAlpha() {
|
||||||
|
for (int i = 1; i < 8; i++) {
|
||||||
|
BufferedImage bufferedImage = createExtraSamplesImage(10, 10, ColorSpaces.getColorSpace(ColorSpace.CS_sRGB), true, i);
|
||||||
|
BufferedImage resampled = new ResampleOp(5, 5, ResampleOp.FILTER_LANCZOS).filter(bufferedImage, null);
|
||||||
|
|
||||||
|
assertNotNull(resampled);
|
||||||
|
assertEquals(5, resampled.getWidth());
|
||||||
|
assertEquals(5, resampled.getHeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testImageWithExtraSamplesCanBeResampledCMYK() {
|
||||||
|
for (int i = 1; i < 8; i++) {
|
||||||
|
BufferedImage bufferedImage = createExtraSamplesImage(10, 10, ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK), false, i);
|
||||||
|
BufferedImage resampled = new ResampleOp(5, 5, ResampleOp.FILTER_LANCZOS).filter(bufferedImage, null);
|
||||||
|
|
||||||
|
assertNotNull(resampled);
|
||||||
|
assertEquals(5, resampled.getWidth());
|
||||||
|
assertEquals(5, resampled.getHeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testImageWithExtraSamplesCanBeResampledCMYKAlpha() {
|
||||||
|
for (int i = 1; i < 8; i++) {
|
||||||
|
BufferedImage bufferedImage = createExtraSamplesImage(10, 10, ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK), true, i);
|
||||||
|
BufferedImage resampled = new ResampleOp(5, 5, ResampleOp.FILTER_LANCZOS).filter(bufferedImage, null);
|
||||||
|
|
||||||
|
assertNotNull(resampled);
|
||||||
|
assertEquals(5, resampled.getWidth());
|
||||||
|
assertEquals(5, resampled.getHeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user