mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-04 03:55:28 -04:00
WebP source subsampling.
This commit is contained in:
parent
4dedf76ebc
commit
3bb312e9e1
@ -428,7 +428,7 @@ final class WebPImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void readVP8Lossless(final WritableRaster raster, final ImageReadParam param) throws IOException {
|
private void readVP8Lossless(final WritableRaster raster, final ImageReadParam param) throws IOException {
|
||||||
VP8LDecoder decoder = new VP8LDecoder(imageInput);
|
VP8LDecoder decoder = new VP8LDecoder(imageInput, DEBUG);
|
||||||
decoder.readVP8Lossless(raster, true);
|
decoder.readVP8Lossless(raster, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -443,7 +443,6 @@ final class WebPImageReader extends ImageReaderBase {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!frame.decode(raster, param)) {
|
if (!frame.decode(raster, param)) {
|
||||||
// TODO: Does this make any sense? Only happens if frame type is not still (0)
|
|
||||||
processWarningOccurred("Nothing to decode");
|
processWarningOccurred("Nothing to decode");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static com.twelvemonkeys.imageio.plugins.webp.RasterUtils.asByteRaster;
|
import static com.twelvemonkeys.imageio.plugins.webp.RasterUtils.asByteRaster;
|
||||||
import static java.lang.Math.abs;
|
import static java.lang.Math.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* VP8LDecoder.
|
* VP8LDecoder.
|
||||||
@ -49,14 +49,13 @@ import static java.lang.Math.abs;
|
|||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
*/
|
*/
|
||||||
public final class VP8LDecoder {
|
public final class VP8LDecoder {
|
||||||
|
|
||||||
private final ImageInputStream imageInput;
|
private final ImageInputStream imageInput;
|
||||||
private final LSBBitReader lsbBitReader;
|
private final LSBBitReader lsbBitReader;
|
||||||
|
|
||||||
private final List<Transform> transforms = new ArrayList<>();
|
private final List<Transform> transforms = new ArrayList<>();
|
||||||
private ColorCache colorCache;
|
private ColorCache colorCache;
|
||||||
|
|
||||||
public VP8LDecoder(final ImageInputStream imageInput) {
|
public VP8LDecoder(final ImageInputStream imageInput, final boolean debug) {
|
||||||
this.imageInput = imageInput;
|
this.imageInput = imageInput;
|
||||||
lsbBitReader = new LSBBitReader(imageInput);
|
lsbBitReader = new LSBBitReader(imageInput);
|
||||||
}
|
}
|
||||||
@ -275,7 +274,7 @@ public final class VP8LDecoder {
|
|||||||
|
|
||||||
// Clamp the input value between 0 and 255.
|
// Clamp the input value between 0 and 255.
|
||||||
private static int clamp(final int a) {
|
private static int clamp(final int a) {
|
||||||
return a < 0 ? 0 : a > 255 ? 255 : a;
|
return max(0, min(a, 255));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int clampAddSubtractFull(final int a, final int b, final int c) {
|
private static int clampAddSubtractFull(final int a, final int b, final int c) {
|
||||||
|
@ -499,8 +499,7 @@ final class Globals {
|
|||||||
for (int i = 0; i < vp8DefaultCoefProbs.length; i++)
|
for (int i = 0; i < vp8DefaultCoefProbs.length; i++)
|
||||||
for (int j = 0; j < vp8DefaultCoefProbs[0].length; j++)
|
for (int j = 0; j < vp8DefaultCoefProbs[0].length; j++)
|
||||||
for (int k = 0; k < vp8DefaultCoefProbs[0][0].length; k++)
|
for (int k = 0; k < vp8DefaultCoefProbs[0][0].length; k++)
|
||||||
for (int l = 0; l < vp8DefaultCoefProbs[0][0][0].length; l++)
|
r[i][j][k] = vp8DefaultCoefProbs[i][j][k].clone();
|
||||||
r[i][j][k][l] = vp8DefaultCoefProbs[i][j][k][l];
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,16 +145,6 @@ final class LoopFilter {
|
|||||||
return abs(p1 - p0) > threshold || abs(q1 - q0) > threshold;
|
return abs(p1 - p0) > threshold || abs(q1 - q0) > threshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
// public static void loopFilter(VP8Frame frame) {
|
|
||||||
// if (frame.getFilterType() == 2) {
|
|
||||||
// loopFilterUV(frame);
|
|
||||||
// loopFilterY(frame);
|
|
||||||
// }
|
|
||||||
// else if (frame.getFilterType() == 1) {
|
|
||||||
// loopFilterSimple(frame);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
static void loopFilterBlock(final MacroBlock cmb, final MacroBlock lmb, final MacroBlock tmb, int frameType, boolean simpleFilter, int sharpness) {
|
static void loopFilterBlock(final MacroBlock cmb, final MacroBlock lmb, final MacroBlock tmb, int frameType, boolean simpleFilter, int sharpness) {
|
||||||
if (simpleFilter) {
|
if (simpleFilter) {
|
||||||
loopFilterSimpleBlock(cmb, lmb, tmb, sharpness);
|
loopFilterSimpleBlock(cmb, lmb, tmb, sharpness);
|
||||||
@ -165,23 +155,7 @@ final class LoopFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void loopFilterSimple(VP8Frame frame) {
|
|
||||||
for (int y = 0; y < frame.getMacroBlockRows(); y++) {
|
|
||||||
// frame.fireLFProgressUpdate((100.0f * ((float) (y + 1) / (float) (frame
|
|
||||||
// .getMacroBlockRows()))));
|
|
||||||
for (int x = 0; x < frame.getMacroBlockCols(); x++) {
|
|
||||||
loopFilterSimpleBlock(frame.getMacroBlock(x, y),
|
|
||||||
x > 0 ? frame.getMacroBlock(x - 1, y) : null,
|
|
||||||
y > 0 ? frame.getMacroBlock(x, y - 1) : null,
|
|
||||||
frame.getSharpnessLevel());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void loopFilterSimpleBlock(final MacroBlock cmb, final MacroBlock lmb, final MacroBlock tmb, final int sharpnessLevel) {
|
static void loopFilterSimpleBlock(final MacroBlock cmb, final MacroBlock lmb, final MacroBlock tmb, final int sharpnessLevel) {
|
||||||
// System.out.println("x: "+x+" y: "+y);
|
|
||||||
// MacroBlock bmb = frame.getMacroBlock(x, y); // TODO: Same..?
|
|
||||||
int loop_filter_level = cmb.getFilterLevel();
|
int loop_filter_level = cmb.getFilterLevel();
|
||||||
if (loop_filter_level != 0) {
|
if (loop_filter_level != 0) {
|
||||||
int interior_limit = cmb.getFilterLevel();
|
int interior_limit = cmb.getFilterLevel();
|
||||||
@ -277,18 +251,6 @@ final class LoopFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void loopFilterUV(VP8Frame frame) {
|
|
||||||
for (int y = 0; y < frame.getMacroBlockRows(); y++) {
|
|
||||||
for (int x = 0; x < frame.getMacroBlockCols(); x++) {
|
|
||||||
loopFilterUVBlock(frame.getMacroBlock(x, y),
|
|
||||||
x > 0 ? frame.getMacroBlock(x - 1, y) : null,
|
|
||||||
y > 0 ? frame.getMacroBlock(x, y - 1) : null,
|
|
||||||
frame.getSharpnessLevel(), frame.getFrameType()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void loopFilterUVBlock(final MacroBlock cmb, final MacroBlock lmb, final MacroBlock tmb, final int sharpnessLevel, final int frameType) {
|
static void loopFilterUVBlock(final MacroBlock cmb, final MacroBlock lmb, final MacroBlock tmb, final int sharpnessLevel, final int frameType) {
|
||||||
int loop_filter_level = cmb.getFilterLevel();
|
int loop_filter_level = cmb.getFilterLevel();
|
||||||
if (loop_filter_level != 0) {
|
if (loop_filter_level != 0) {
|
||||||
@ -407,17 +369,6 @@ final class LoopFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void loopFilterY(VP8Frame frame) {
|
|
||||||
for (int y = 0; y < frame.getMacroBlockRows(); y++) {
|
|
||||||
for (int x = 0; x < frame.getMacroBlockCols(); x++) {
|
|
||||||
loopFilterYBlock(frame.getMacroBlock(x, y),
|
|
||||||
x > 0 ? frame.getMacroBlock(x - 1, y) : null,
|
|
||||||
y > 0 ? frame.getMacroBlock(x, y - 1) : null,
|
|
||||||
frame.getSharpnessLevel(), frame.getFrameType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void loopFilterYBlock(final MacroBlock cmb, final MacroBlock lmb, final MacroBlock tmb, final int sharpnessLevel, final int frameType) {
|
static void loopFilterYBlock(final MacroBlock cmb, final MacroBlock lmb, final MacroBlock tmb, final int sharpnessLevel, final int frameType) {
|
||||||
int loop_filter_level = cmb.getFilterLevel();
|
int loop_filter_level = cmb.getFilterLevel();
|
||||||
|
|
||||||
@ -587,9 +538,6 @@ final class LoopFilter {
|
|||||||
if ((abs(seg.P0 - seg.Q0) * 2 + abs(seg.P1 - seg.Q1) / 2) <= edge_limit) {
|
if ((abs(seg.P0 - seg.Q0) * 2 + abs(seg.P1 - seg.Q1) / 2) <= edge_limit) {
|
||||||
common_adjust(true, seg); // use outer taps
|
common_adjust(true, seg); // use outer taps
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// TODO?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void subblock_filter(int hev_threshold, // detect high edge variance
|
private static void subblock_filter(int hev_threshold, // detect high edge variance
|
||||||
@ -605,9 +553,6 @@ final class LoopFilter {
|
|||||||
seg.P1 = s2u(p1 + a);
|
seg.P1 = s2u(p1 + a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// TODO?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert pixel value (0 <= v <= 255) to an 8-bit signed number. */
|
/* Convert pixel value (0 <= v <= 255) to an 8-bit signed number. */
|
||||||
|
@ -236,7 +236,6 @@ final class SubBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SubBlock getAbove() {
|
public SubBlock getAbove() {
|
||||||
|
|
||||||
return above;
|
return above;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,6 +246,7 @@ final class SubBlock {
|
|||||||
&& plane == Plane.Y1) {
|
&& plane == Plane.Y1) {
|
||||||
r = r + "\n " + Globals.getSubBlockModeAsString(mode);
|
r = r + "\n " + Globals.getSubBlockModeAsString(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,12 +260,10 @@ final class SubBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int[][] getDiff() {
|
public int[][] getDiff() {
|
||||||
|
|
||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubBlock getLeft() {
|
public SubBlock getLeft() {
|
||||||
|
|
||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1060,22 +1060,24 @@ public final class VP8Frame {
|
|||||||
private final byte[] rgb = new byte[4]; // Allow decoding into RGBA, leaving the alpha out.
|
private final byte[] rgb = new byte[4]; // Allow decoding into RGBA, leaving the alpha out.
|
||||||
|
|
||||||
private void copyBlock(final MacroBlock macroBlock, final WritableRaster byteRGBRaster, final ImageReadParam param) {
|
private void copyBlock(final MacroBlock macroBlock, final WritableRaster byteRGBRaster, final ImageReadParam param) {
|
||||||
// TODO: Consider doing YCbCr -> RGB in reader instead, or pass a flag to allow readRaster reading direct YUV/YCbCr values
|
int sourceYSubsampling = param != null ? param.getSourceYSubsampling() : 1;
|
||||||
|
int sourceXSubsampling = param != null ? param.getSourceXSubsampling() : 1;
|
||||||
|
|
||||||
// We might be copying into a smaller raster
|
// We might be copying into a smaller raster
|
||||||
int yStart = macroBlock.getY() * 16;
|
int yStart = macroBlock.getY() * 16;
|
||||||
int yEnd = Math.min(16, byteRGBRaster.getHeight() - yStart);
|
int yEnd = Math.min(16, byteRGBRaster.getHeight() * sourceYSubsampling - yStart);
|
||||||
int xStart = macroBlock.getX() * 16;
|
int xStart = macroBlock.getX() * 16;
|
||||||
int xEnd = Math.min(16, byteRGBRaster.getWidth() - xStart);
|
int xEnd = Math.min(16, byteRGBRaster.getWidth() * sourceXSubsampling - xStart);
|
||||||
|
|
||||||
for (int y = 0; y < yEnd; y++) {
|
for (int y = 0; y < yEnd; y += sourceYSubsampling) {
|
||||||
for (int x = 0; x < xEnd; x++) {
|
for (int x = 0; x < xEnd; x += sourceXSubsampling) {
|
||||||
yuv[0] = (byte) macroBlock.getSubBlock(SubBlock.Plane.Y1, x / 4, y / 4).getDest()[x % 4][y % 4];
|
yuv[0] = (byte) macroBlock.getSubBlock(SubBlock.Plane.Y1, x / 4, y / 4).getDest()[x % 4][y % 4];
|
||||||
yuv[1] = (byte) macroBlock.getSubBlock(SubBlock.Plane.U, (x / 2) / 4, (y / 2) / 4).getDest()[(x / 2) % 4][(y / 2) % 4];
|
yuv[1] = (byte) macroBlock.getSubBlock(SubBlock.Plane.U, (x / 2) / 4, (y / 2) / 4).getDest()[(x / 2) % 4][(y / 2) % 4];
|
||||||
yuv[2] = (byte) macroBlock.getSubBlock(SubBlock.Plane.V, (x / 2) / 4, (y / 2) / 4).getDest()[(x / 2) % 4][(y / 2) % 4];
|
yuv[2] = (byte) macroBlock.getSubBlock(SubBlock.Plane.V, (x / 2) / 4, (y / 2) / 4).getDest()[(x / 2) % 4][(y / 2) % 4];
|
||||||
|
|
||||||
|
// TODO: Consider doing YCbCr -> RGB in reader instead, or pass a flag to allow readRaster reading direct YUV/YCbCr values
|
||||||
convertYCbCr2RGB(yuv, rgb, 0);
|
convertYCbCr2RGB(yuv, rgb, 0);
|
||||||
byteRGBRaster.setDataElements(xStart + x, yStart + y, rgb);
|
byteRGBRaster.setDataElements((xStart + x) / sourceXSubsampling, (yStart + y) / sourceYSubsampling, rgb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user