From 3bb312e9e1e6b391422fa32ef6b704363f00585d Mon Sep 17 00:00:00 2001 From: Harald Kuhr Date: Mon, 30 Nov 2020 22:10:54 +0100 Subject: [PATCH] WebP source subsampling. --- .../imageio/plugins/webp/WebPImageReader.java | 3 +- .../plugins/webp/lossless/VP8LDecoder.java | 7 +-- .../imageio/plugins/webp/vp8/Globals.java | 3 +- .../imageio/plugins/webp/vp8/LoopFilter.java | 55 ------------------- .../imageio/plugins/webp/vp8/SubBlock.java | 4 +- .../imageio/plugins/webp/vp8/VP8Frame.java | 14 +++-- 6 files changed, 14 insertions(+), 72 deletions(-) diff --git a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/WebPImageReader.java b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/WebPImageReader.java index a45329ae..021e2f76 100644 --- a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/WebPImageReader.java +++ b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/WebPImageReader.java @@ -428,7 +428,7 @@ final class WebPImageReader extends ImageReaderBase { } 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); } @@ -443,7 +443,6 @@ final class WebPImageReader extends ImageReaderBase { }); if (!frame.decode(raster, param)) { - // TODO: Does this make any sense? Only happens if frame type is not still (0) processWarningOccurred("Nothing to decode"); } } diff --git a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/lossless/VP8LDecoder.java b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/lossless/VP8LDecoder.java index 0f7e5f89..bbb40eac 100644 --- a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/lossless/VP8LDecoder.java +++ b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/lossless/VP8LDecoder.java @@ -41,7 +41,7 @@ import java.util.ArrayList; import java.util.List; import static com.twelvemonkeys.imageio.plugins.webp.RasterUtils.asByteRaster; -import static java.lang.Math.abs; +import static java.lang.Math.*; /** * VP8LDecoder. @@ -49,14 +49,13 @@ import static java.lang.Math.abs; * @author Harald Kuhr */ public final class VP8LDecoder { - private final ImageInputStream imageInput; private final LSBBitReader lsbBitReader; private final List transforms = new ArrayList<>(); private ColorCache colorCache; - public VP8LDecoder(final ImageInputStream imageInput) { + public VP8LDecoder(final ImageInputStream imageInput, final boolean debug) { this.imageInput = imageInput; lsbBitReader = new LSBBitReader(imageInput); } @@ -275,7 +274,7 @@ public final class VP8LDecoder { // Clamp the input value between 0 and 255. 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) { diff --git a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/Globals.java b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/Globals.java index e396655f..ab93943c 100644 --- a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/Globals.java +++ b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/Globals.java @@ -499,8 +499,7 @@ final class Globals { for (int i = 0; i < vp8DefaultCoefProbs.length; i++) for (int j = 0; j < vp8DefaultCoefProbs[0].length; j++) 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][l] = vp8DefaultCoefProbs[i][j][k][l]; + r[i][j][k] = vp8DefaultCoefProbs[i][j][k].clone(); return r; } diff --git a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/LoopFilter.java b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/LoopFilter.java index 000a0311..06f610a4 100644 --- a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/LoopFilter.java +++ b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/LoopFilter.java @@ -145,16 +145,6 @@ final class LoopFilter { 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) { if (simpleFilter) { 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) { - // System.out.println("x: "+x+" y: "+y); -// MacroBlock bmb = frame.getMacroBlock(x, y); // TODO: Same..? int loop_filter_level = cmb.getFilterLevel(); if (loop_filter_level != 0) { 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) { int loop_filter_level = cmb.getFilterLevel(); 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) { 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) { common_adjust(true, seg); // use outer taps } - else { - // TODO? - } } private static void subblock_filter(int hev_threshold, // detect high edge variance @@ -605,9 +553,6 @@ final class LoopFilter { seg.P1 = s2u(p1 + a); } } - else { - // TODO? - } } /* Convert pixel value (0 <= v <= 255) to an 8-bit signed number. */ diff --git a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/SubBlock.java b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/SubBlock.java index 4158ece7..8df51a01 100644 --- a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/SubBlock.java +++ b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/SubBlock.java @@ -236,7 +236,6 @@ final class SubBlock { } public SubBlock getAbove() { - return above; } @@ -247,6 +246,7 @@ final class SubBlock { && plane == Plane.Y1) { r = r + "\n " + Globals.getSubBlockModeAsString(mode); } + return r; } @@ -260,12 +260,10 @@ final class SubBlock { } public int[][] getDiff() { - return diff; } public SubBlock getLeft() { - return left; } diff --git a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/VP8Frame.java b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/VP8Frame.java index 48f05cca..5d56f5f5 100644 --- a/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/VP8Frame.java +++ b/imageio/imageio-webp/src/main/java/com/twelvemonkeys/imageio/plugins/webp/vp8/VP8Frame.java @@ -1060,22 +1060,24 @@ public final class VP8Frame { 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) { - // 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 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 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 x = 0; x < xEnd; x++) { + for (int y = 0; y < yEnd; y += sourceYSubsampling) { + 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[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]; + // TODO: Consider doing YCbCr -> RGB in reader instead, or pass a flag to allow readRaster reading direct YUV/YCbCr values convertYCbCr2RGB(yuv, rgb, 0); - byteRGBRaster.setDataElements(xStart + x, yStart + y, rgb); + byteRGBRaster.setDataElements((xStart + x) / sourceXSubsampling, (yStart + y) / sourceYSubsampling, rgb); } } }