mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-04 20:15:28 -04:00
Objectify Transforms
Deduplicate code for parsing predictor and color transforms. Add missing subtraction code removal on indexing transform.
This commit is contained in:
parent
7382151db8
commit
28270b4d5b
@ -32,6 +32,12 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.webp.lossless;
|
package com.twelvemonkeys.imageio.plugins.webp.lossless;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.plugins.webp.LSBBitReader;
|
import com.twelvemonkeys.imageio.plugins.webp.LSBBitReader;
|
||||||
|
import com.twelvemonkeys.imageio.plugins.webp.lossless.transform.ColorIndexingTransform;
|
||||||
|
import com.twelvemonkeys.imageio.plugins.webp.lossless.transform.ColorTransform;
|
||||||
|
import com.twelvemonkeys.imageio.plugins.webp.lossless.transform.PredictorTransform;
|
||||||
|
import com.twelvemonkeys.imageio.plugins.webp.lossless.transform.SubtractGreenTransform;
|
||||||
|
import com.twelvemonkeys.imageio.plugins.webp.lossless.transform.Transform;
|
||||||
|
import com.twelvemonkeys.imageio.plugins.webp.lossless.transform.TransformType;
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
import javax.imageio.IIOException;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
@ -40,7 +46,6 @@ import java.io.IOException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static com.twelvemonkeys.imageio.util.RasterUtils.asByteRaster;
|
|
||||||
import static java.lang.Math.*;
|
import static java.lang.Math.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,58 +102,38 @@ public final class VP8LDecoder {
|
|||||||
// TODO: Each transform type can only be present once in the stream.
|
// TODO: Each transform type can only be present once in the stream.
|
||||||
|
|
||||||
switch (transformType) {
|
switch (transformType) {
|
||||||
case TransformType.PREDICTOR_TRANSFORM: {
|
case TransformType.PREDICTOR_TRANSFORM:
|
||||||
System.err.println("transformType: PREDICTOR_TRANSFORM");
|
System.err.println("transformType: PREDICTOR_TRANSFORM");
|
||||||
// int sizeBits = (int) readBits(3) + 2;
|
//Intentional Fallthrough
|
||||||
int sizeBits = (int) lsbBitReader.readBits(3) + 2;
|
|
||||||
int size = 1 << sizeBits;
|
|
||||||
|
|
||||||
int blockWidth = size;
|
|
||||||
int blockHeight = size;
|
|
||||||
|
|
||||||
// int blockSize = divRoundUp(width, size);
|
|
||||||
int blockSize = divRoundUp(xSize, size);
|
|
||||||
|
|
||||||
for (int y = 0; y < ySize; y++) {
|
|
||||||
for (int x = 0; x < xSize; x++) {
|
|
||||||
int blockIndex = (y >> sizeBits) * blockSize + (x >> sizeBits);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special rules:
|
|
||||||
// Top-left pixel of image is predicted BLACK
|
|
||||||
// Rest of top pixels is predicted L
|
|
||||||
// Rest of leftmost pixels are predicted T
|
|
||||||
// Rightmost pixels using TR, uses LEFTMOST pixel on SAME ROW (same distance as TR in memory!)
|
|
||||||
|
|
||||||
// WritableRaster data = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, blockWidth, blockHeight, blockWidth, 1, new int[] {0}, null);
|
|
||||||
// readVP8Lossless(data, false);
|
|
||||||
//
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TransformType.COLOR_TRANSFORM: {
|
case TransformType.COLOR_TRANSFORM: {
|
||||||
// The two first transforms contains the exact same data, can be combined
|
// The two first transforms contains the exact same data, can be combined
|
||||||
|
if (transformType == TransformType.COLOR_TRANSFORM) {
|
||||||
System.err.println("transformType: COLOR_TRANSFORM");
|
System.err.println("transformType: COLOR_TRANSFORM");
|
||||||
|
}
|
||||||
|
|
||||||
int sizeBits = (int) lsbBitReader.readBits(3) + 2;
|
byte sizeBits = (byte) (lsbBitReader.readBits(3) + 2);
|
||||||
// int size = 1 << sizeBits;
|
|
||||||
|
|
||||||
// TODO: Understand difference between spec divRoundUp and impl VP8LSubSampleSize
|
|
||||||
|
|
||||||
int blockWidth = subSampleSize(xSize, sizeBits);
|
int blockWidth = subSampleSize(xSize, sizeBits);
|
||||||
int blockHeight = subSampleSize(ySize, sizeBits);
|
int blockHeight = subSampleSize(ySize, sizeBits);
|
||||||
WritableRaster data = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, blockWidth, blockHeight, blockWidth, 1, new int[] {0}, null);
|
WritableRaster raster =
|
||||||
readVP8Lossless(data, false);
|
Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, blockWidth, blockHeight, 4 * blockWidth, 4,
|
||||||
|
new int[] {0, 1, 2, 3}, null);
|
||||||
|
readVP8Lossless(raster, false);
|
||||||
|
|
||||||
transforms.add(new Transform(transformType, ((DataBufferByte) data.getDataBuffer()).getData()));
|
//Keep data as raster for convenient (x,y) indexing
|
||||||
|
if (transformType == TransformType.PREDICTOR_TRANSFORM) {
|
||||||
|
transforms.add(0, new PredictorTransform(raster, sizeBits));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
transforms.add(0, new ColorTransform(raster, sizeBits));
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TransformType.SUBTRACT_GREEN: {
|
case TransformType.SUBTRACT_GREEN: {
|
||||||
System.err.println("transformType: SUBTRACT_GREEN");
|
System.err.println("transformType: SUBTRACT_GREEN");
|
||||||
// No data here
|
// No data here
|
||||||
|
transforms.add(0, new SubtractGreenTransform());
|
||||||
// addGreenToBlueAndRed();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TransformType.COLOR_INDEXING_TRANSFORM: {
|
case TransformType.COLOR_INDEXING_TRANSFORM: {
|
||||||
@ -167,41 +152,36 @@ public final class VP8LDecoder {
|
|||||||
|
|
||||||
System.err.println("safeColorTableSize: " + safeColorTableSize);
|
System.err.println("safeColorTableSize: " + safeColorTableSize);
|
||||||
|
|
||||||
int[] colorTable = new int[safeColorTableSize];
|
byte[] colorTable = new byte[safeColorTableSize * 4];
|
||||||
|
|
||||||
// The color table can be obtained by reading an image,
|
// The color table can be obtained by reading an image,
|
||||||
// without the RIFF header, image size, and transforms,
|
// without the RIFF header, image size, and transforms,
|
||||||
// assuming a height of one pixel and a width of
|
// assuming a height of one pixel and a width of
|
||||||
// color_table_size. The color table is always
|
// color_table_size. The color table is always
|
||||||
// subtraction-coded to reduce image entropy.
|
// subtraction-coded to reduce image entropy.
|
||||||
// TODO: Read *without transforms*, using SUBTRACT_GREEN only!
|
readVP8Lossless(
|
||||||
readVP8Lossless(asByteRaster(
|
Raster.createInterleavedRaster(
|
||||||
Raster.createPackedRaster(
|
new DataBufferByte(colorTable, colorTableSize * 4),
|
||||||
new DataBufferInt(colorTable, colorTableSize),
|
colorTableSize, 1, colorTableSize * 4,
|
||||||
colorTableSize, 1, colorTableSize,
|
4, new int[] {0, 1, 2, 3}, null)
|
||||||
new int[] {0}, null
|
, false);
|
||||||
)
|
|
||||||
), false);
|
|
||||||
|
|
||||||
// TODO: We may not really need this value...
|
|
||||||
// What we need is the number of pixels packed into each green sample (byte)
|
//resolve subtraction code
|
||||||
int widthBits = colorTableSize > 16 ? 0 :
|
for (int i = 4; i < colorTable.length; i++) {
|
||||||
|
colorTable[i] += colorTable[i - 4];
|
||||||
|
}
|
||||||
|
|
||||||
|
// The number of pixels packed into each green sample (byte)
|
||||||
|
byte widthBits = (byte) (colorTableSize > 16 ? 0 :
|
||||||
colorTableSize > 4 ? 1 :
|
colorTableSize > 4 ? 1 :
|
||||||
colorTableSize > 2 ? 2 : 3;
|
colorTableSize > 2 ? 2 : 3);
|
||||||
|
|
||||||
xSize = subSampleSize(xSize, widthBits);
|
xSize = subSampleSize(xSize, widthBits);
|
||||||
|
|
||||||
/*
|
// The colors components are stored in ARGB order at 4*index, 4*index + 1, 4*index + 2, 4*index + 3
|
||||||
// TODO: read ARGB
|
|
||||||
int argb = 0;
|
|
||||||
|
|
||||||
// Inverse transform
|
|
||||||
// TODO: Expand to mutliple pixels?
|
|
||||||
argb = colorTable[GREEN(argb)];
|
|
||||||
*/
|
|
||||||
|
|
||||||
// TODO: Can we use this to produce an image with IndexColorModel instead of expanding the values in-memory?
|
// TODO: Can we use this to produce an image with IndexColorModel instead of expanding the values in-memory?
|
||||||
transforms.add(new Transform(transformType, colorTable));
|
transforms.add(0, new ColorIndexingTransform(colorTable, widthBits));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.webp.lossless.transform;
|
||||||
|
|
||||||
|
import java.awt.image.*;
|
||||||
|
|
||||||
|
public class ColorIndexingTransform implements Transform {
|
||||||
|
|
||||||
|
private final byte[] colorTable;
|
||||||
|
private final byte bits;
|
||||||
|
|
||||||
|
public ColorIndexingTransform(byte[] colorTable, byte bits) {
|
||||||
|
this.colorTable = colorTable;
|
||||||
|
this.bits = bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyInverse(WritableRaster raster) {
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.webp.lossless.transform;
|
||||||
|
|
||||||
|
import java.awt.image.*;
|
||||||
|
|
||||||
|
public class ColorTransform implements Transform {
|
||||||
|
private final Raster data;
|
||||||
|
private final byte bits;
|
||||||
|
|
||||||
|
public ColorTransform(Raster raster, byte bits) {
|
||||||
|
this.data = raster;
|
||||||
|
this.bits = bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyInverse(WritableRaster raster) {
|
||||||
|
}
|
||||||
|
}
|
@ -29,7 +29,7 @@
|
|||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.webp.lossless;
|
package com.twelvemonkeys.imageio.plugins.webp.lossless.transform;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PredictorMode.
|
* PredictorMode.
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.webp.lossless.transform;
|
||||||
|
|
||||||
|
import java.awt.image.*;
|
||||||
|
|
||||||
|
public class PredictorTransform implements Transform {
|
||||||
|
private final Raster data;
|
||||||
|
private final byte bits;
|
||||||
|
|
||||||
|
public PredictorTransform(Raster raster, byte bits) {
|
||||||
|
this.data = raster;
|
||||||
|
this.bits = bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyInverse(WritableRaster raster) {
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.webp.lossless.transform;
|
||||||
|
|
||||||
|
import java.awt.image.*;
|
||||||
|
|
||||||
|
public class SubtractGreenTransform implements Transform {
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyInverse(WritableRaster raster) {
|
||||||
|
}
|
||||||
|
}
|
@ -29,27 +29,16 @@
|
|||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.webp.lossless;
|
package com.twelvemonkeys.imageio.plugins.webp.lossless.transform;
|
||||||
|
|
||||||
|
import java.awt.image.WritableRaster;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform.
|
* Transform.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
*/
|
*/
|
||||||
final class Transform {
|
public interface Transform {
|
||||||
final int type;
|
|
||||||
final Object data;
|
|
||||||
|
|
||||||
Transform(final int type, final Object data) {
|
void applyInverse(WritableRaster raster);
|
||||||
this.type = type;
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] getData() {
|
|
||||||
return (byte[]) data;
|
|
||||||
}
|
|
||||||
|
|
||||||
int[] getColorMap() {
|
|
||||||
return (int[]) data;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -29,7 +29,7 @@
|
|||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.webp.lossless;
|
package com.twelvemonkeys.imageio.plugins.webp.lossless.transform;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TransformType.
|
* TransformType.
|
||||||
@ -37,7 +37,7 @@ package com.twelvemonkeys.imageio.plugins.webp.lossless;
|
|||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
*/
|
*/
|
||||||
// Hmm.. Why doesn't SUBTRACT_GREEN follow the convention?
|
// Hmm.. Why doesn't SUBTRACT_GREEN follow the convention?
|
||||||
interface TransformType {
|
public interface TransformType {
|
||||||
int PREDICTOR_TRANSFORM = 0;
|
int PREDICTOR_TRANSFORM = 0;
|
||||||
int COLOR_TRANSFORM = 1;
|
int COLOR_TRANSFORM = 1;
|
||||||
int SUBTRACT_GREEN = 2;
|
int SUBTRACT_GREEN = 2;
|
Loading…
x
Reference in New Issue
Block a user