mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-10-03 15:47:38 -04:00
Handle lossless JPEG with non-zero point transform (#1183)
* Handle lossless JPEG with non-zero point transform (Pt parameter) * Add unit test * Inserting a fix for last pixel not being output * Address issues from code review --------- Co-authored-by: Harald Kuhr <harald.kuhr@gmail.com>
This commit is contained in:
@@ -212,7 +212,9 @@ final class JPEGLosslessDecoder {
|
||||
|
||||
final int[] firstValue = new int[numComp];
|
||||
for (int i = 0; i < numComp; i++) {
|
||||
firstValue[i] = (1 << (precision - 1));
|
||||
// scan.approxLow is the point transformation (Pt) value
|
||||
// ref. ISO/IEC 10918-1 H.1.2.1
|
||||
firstValue[i] = (1 << (precision - scan.approxLow - 1));
|
||||
}
|
||||
|
||||
final int[] pred = new int[numComp];
|
||||
@@ -232,6 +234,11 @@ final class JPEGLosslessDecoder {
|
||||
output(pred);
|
||||
current = decode(pred, temp, index);
|
||||
}
|
||||
|
||||
if ((current == JPEG.EOI) && (xLoc == xDim - 1) && (yLoc == yDim - 1)) {
|
||||
// Output value left in pred if EOI is hit while decoding last pixel
|
||||
output(pred);
|
||||
}
|
||||
|
||||
break; //current=MARKER
|
||||
}
|
||||
@@ -268,6 +275,17 @@ final class JPEGLosslessDecoder {
|
||||
// TODO oe: 05.05.2018 Is it correct loop? Content of outputData from previous iteration is always lost.
|
||||
} while ((current != JPEG.EOI) && ((xLoc < xDim) && (yLoc < yDim)) && (scanNum == 0));
|
||||
|
||||
// Apply point transform to output. This must be done after it has finished being
|
||||
// used for predictive purposes.
|
||||
if (scan.approxLow != 0) {
|
||||
for (int componentIndex = 0; componentIndex < numComp; ++componentIndex) {
|
||||
int[] comp = outputData[componentIndex];
|
||||
for (int i = 0; i < comp.length; i++) {
|
||||
comp[i] = mask & (comp[i] << scan.approxLow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return outputData;
|
||||
}
|
||||
|
||||
@@ -329,9 +347,11 @@ final class JPEGLosslessDecoder {
|
||||
private int decodeSingle(final int[] prev, final int[] temp, final int[] index) throws IOException {
|
||||
// At the beginning of the first line and
|
||||
// at the beginning of each restart interval the prediction value of 2P – 1 is used, where P is the input precision.
|
||||
// If the point transformation parameter (see A.4) is non-zero, the prediction value at the beginning of the first lines and the
|
||||
// beginning of each restart interval is 2P – Pt – 1 , where Pt is the value of the point transformation parameter
|
||||
if (restarting) {
|
||||
restarting = false;
|
||||
prev[0] = (1 << (frame.samplePrecision - 1));
|
||||
prev[0] = (1 << (frame.samplePrecision - scan.approxLow - 1));
|
||||
}
|
||||
else {
|
||||
final int[] outputData = this.outputData[0];
|
||||
@@ -686,7 +706,7 @@ final class JPEGLosslessDecoder {
|
||||
return getPreviousY(data);
|
||||
}
|
||||
else {
|
||||
return (1 << (frame.samplePrecision - 1));
|
||||
return (1 << (frame.samplePrecision - scan.approxLow - 1));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -2033,4 +2033,65 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadLosslessJPEGGradient() throws IOException {
|
||||
JPEGImageReader reader = createReader();
|
||||
|
||||
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/jpeg-lossless/gradient_ls.jpg"))) {
|
||||
reader.setInput(stream);
|
||||
|
||||
assertEquals(256, reader.getWidth(0));
|
||||
assertEquals(256, reader.getHeight(0));
|
||||
|
||||
BufferedImage image = reader.read(0, null);
|
||||
|
||||
assertNotNull(image);
|
||||
assertEquals(256, image.getWidth());
|
||||
assertEquals(256, image.getHeight());
|
||||
assertEquals(16, image.getColorModel().getComponentSize(0));
|
||||
|
||||
for (int y = 0; y < 256; y++) {
|
||||
for (int x = 0; x < 256; x++) {
|
||||
assertEquals((y << 8) | x, image.getRaster().getSample(x, y, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
reader.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadLosslessJPEGGradientWithPointTransform() throws IOException {
|
||||
JPEGImageReader reader = createReader();
|
||||
|
||||
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/jpeg-lossless/gradient_ls_pt.jpg"))) {
|
||||
reader.setInput(stream);
|
||||
|
||||
assertEquals(256, reader.getWidth(0));
|
||||
assertEquals(256, reader.getHeight(0));
|
||||
|
||||
BufferedImage image = reader.read(0, null);
|
||||
|
||||
assertNotNull(image);
|
||||
assertEquals(256, image.getWidth());
|
||||
assertEquals(256, image.getHeight());
|
||||
assertEquals(16, image.getColorModel().getComponentSize(0));
|
||||
|
||||
for (int y = 0; y < 256; y++) {
|
||||
for (int x = 0; x < 256; x++) {
|
||||
int expected = (y << 8) | x;
|
||||
|
||||
// Simulate effect of precision loss due to point transform = 4
|
||||
expected = (expected >> 4) << 4;
|
||||
|
||||
assertEquals(expected, image.getRaster().getSample(x, y, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
reader.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
After Width: | Height: | Size: 9.2 KiB |
Reference in New Issue
Block a user