Fix source region reading in VP8Frame.

This commit is contained in:
Harald Kuhr 2020-12-09 09:24:19 +01:00
parent 6bac13eb84
commit c1d4e474f0
2 changed files with 33 additions and 23 deletions

View File

@ -304,7 +304,7 @@ final class WebPImageReader extends ImageReaderBase {
}
@Override
public BufferedImage read(int imageIndex, ImageReadParam param) throws IOException {
public BufferedImage read(final int imageIndex, final ImageReadParam param) throws IOException {
int width = getWidth(imageIndex);
int height = getHeight(imageIndex);
BufferedImage destination = getDestination(param, getImageTypes(imageIndex), width, height);

View File

@ -35,6 +35,7 @@ import javax.imageio.IIOException;
import javax.imageio.ImageReadParam;
import javax.imageio.event.IIOReadProgressListener;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.IOException;
@ -328,25 +329,24 @@ public final class VP8Frame {
}
int ibc = 0;
int num_part = 1 << multiTokenPartition;
int parts = 1 << multiTokenPartition;
// final boolean filter = getFilterType() > 0 && getFilterLevel() != 0;
Rectangle region = param != null && param.getSourceRegion() != null ? param.getSourceRegion() : raster.getBounds();
int sourceXSubsampling = param != null ? param.getSourceXSubsampling() : 1;
int sourceYSubsampling = param != null ? param.getSourceYSubsampling() : 1;
for (int row = 0; row < macroBlockRows; row++) {
if (num_part > 1) {
if (parts > 1) {
tokenBoolDecoder = tokenBoolDecoders.get(ibc);
tokenBoolDecoder.seek();
decodeMacroBlockRow(row, raster, param);
ibc++;
if (ibc == num_part) {
if (ibc == parts) {
ibc = 0;
}
}
else {
decodeMacroBlockRow(row, raster, param);
}
decodeMacroBlockRow(row, raster, region, sourceXSubsampling, sourceYSubsampling);
fireProgressUpdate(row);
}
@ -354,7 +354,8 @@ public final class VP8Frame {
return true;
}
private void decodeMacroBlockRow(final int mbRow, final WritableRaster raster, final ImageReadParam param) throws IOException {
private void decodeMacroBlockRow(final int mbRow, final WritableRaster raster, final Rectangle region,
final int xSubsampling, final int ySubsampling) throws IOException {
final boolean filter = filterLevel != 0;
MacroBlock left = null;
@ -372,7 +373,7 @@ public final class VP8Frame {
LoopFilter.loopFilterBlock(mb, left, top, frameType, simpleFilter, sharpnessLevel);
}
copyBlock(mb, raster, param);
copyBlock(mb, raster, region, xSubsampling, ySubsampling);
left = mb;
}
@ -1059,25 +1060,34 @@ public final class VP8Frame {
private final byte[] yuv = new byte[3];
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) {
int sourceYSubsampling = param != null ? param.getSourceYSubsampling() : 1;
int sourceXSubsampling = param != null ? param.getSourceXSubsampling() : 1;
private void copyBlock(final MacroBlock macroBlock, final WritableRaster byteRGBRaster,
final Rectangle region, final int xSubsampling, final int ySubsampling) {
// We might be copying into a smaller raster
int yStart = macroBlock.getY() * 16;
int yEnd = Math.min(16, byteRGBRaster.getHeight() * sourceYSubsampling - yStart);
int xStart = macroBlock.getX() * 16;
int xEnd = Math.min(16, byteRGBRaster.getWidth() * sourceXSubsampling - xStart);
int yStart = macroBlock.getY() * 16 - region.y;
int yEnd = Math.min(16, byteRGBRaster.getHeight() * ySubsampling - yStart);
int xStart = macroBlock.getX() * 16 - region.x;
int xEnd = Math.min(16, byteRGBRaster.getWidth() * xSubsampling - xStart);
for (int y = 0; y < yEnd; y += ySubsampling) {
int dstY = (yStart + y) / ySubsampling;
if (dstY < 0) {
continue;
}
for (int x = 0; x < xEnd; x += xSubsampling) {
int dstX = (xStart + x) / xSubsampling;
if (dstX < 0) {
continue;
}
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) / sourceXSubsampling, (yStart + y) / sourceYSubsampling, rgb);
byteRGBRaster.setDataElements(dstX, dstY, rgb);
// byteRGBRaster.setDataElements(dstX, dstY, yuv);
}
}
}