mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-04 03:55:28 -04:00
Implement decoding of compressed alpha chunks, alpha filtering
This commit is contained in:
parent
6608f61353
commit
67b48ce1e3
@ -0,0 +1,8 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.webp;
|
||||||
|
|
||||||
|
public interface AlphaFiltering {
|
||||||
|
int NONE = 0;
|
||||||
|
int HORIZONTAL = 1;
|
||||||
|
int VERTICAL = 2;
|
||||||
|
int GRADIENT = 3;
|
||||||
|
}
|
@ -38,6 +38,7 @@ import java.awt.image.BufferedImage;
|
|||||||
import java.awt.image.ColorConvertOp;
|
import java.awt.image.ColorConvertOp;
|
||||||
import java.awt.image.ColorModel;
|
import java.awt.image.ColorModel;
|
||||||
import java.awt.image.DataBuffer;
|
import java.awt.image.DataBuffer;
|
||||||
|
import java.awt.image.Raster;
|
||||||
import java.awt.image.WritableRaster;
|
import java.awt.image.WritableRaster;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
@ -465,35 +466,7 @@ final class WebPImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
switch (nextChunk) {
|
switch (nextChunk) {
|
||||||
case WebP.CHUNK_ALPH:
|
case WebP.CHUNK_ALPH:
|
||||||
int reserved = (int) imageInput.readBits(2);
|
readAlpha(destination, param);
|
||||||
if (reserved != 0) {
|
|
||||||
// Spec says SHOULD be 0
|
|
||||||
processWarningOccurred(String.format("Unexpected 'ALPH' chunk reserved value, expected 0: %d", reserved));
|
|
||||||
}
|
|
||||||
|
|
||||||
int preProcessing = (int) imageInput.readBits(2);
|
|
||||||
int filtering = (int) imageInput.readBits(2);
|
|
||||||
int compression = (int) imageInput.readBits(2);
|
|
||||||
|
|
||||||
if (DEBUG) {
|
|
||||||
System.out.println("preProcessing: " + preProcessing);
|
|
||||||
System.out.println("filtering: " + filtering);
|
|
||||||
System.out.println("compression: " + compression);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (compression) {
|
|
||||||
case 0:
|
|
||||||
readUncompressedAlpha(destination.getAlphaRaster());
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
opaqueAlpha(destination.getAlphaRaster()); // TODO: Remove when correctly implemented!
|
|
||||||
// readVP8Lossless(destination.getAlphaRaster(), param);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
processWarningOccurred("Unknown WebP alpha compression: " + compression);
|
|
||||||
opaqueAlpha(destination.getAlphaRaster());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -527,6 +500,106 @@ final class WebPImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void readAlpha(BufferedImage destination, ImageReadParam param) throws IOException {
|
||||||
|
int reserved = (int) imageInput.readBits(2);
|
||||||
|
if (reserved != 0) {
|
||||||
|
// Spec says SHOULD be 0
|
||||||
|
processWarningOccurred(
|
||||||
|
String.format("Unexpected 'ALPH' chunk reserved value, expected 0: %d", reserved));
|
||||||
|
}
|
||||||
|
|
||||||
|
int preProcessing = (int) imageInput.readBits(2);
|
||||||
|
int filtering = (int) imageInput.readBits(2);
|
||||||
|
int compression = (int) imageInput.readBits(2);
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
System.out.println("preProcessing: " + preProcessing);
|
||||||
|
System.out.println("filtering: " + filtering);
|
||||||
|
System.out.println("compression: " + compression);
|
||||||
|
}
|
||||||
|
|
||||||
|
WritableRaster alphaRaster = destination.getAlphaRaster();
|
||||||
|
switch (compression) {
|
||||||
|
case 0:
|
||||||
|
readUncompressedAlpha(alphaRaster);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
WritableRaster tempRaster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
|
||||||
|
destination.getWidth(), destination.getHeight(), 4, null);
|
||||||
|
//Simulate header
|
||||||
|
imageInput.seek(imageInput.getStreamPosition() - 5);
|
||||||
|
readVP8Lossless(tempRaster, param);
|
||||||
|
//Copy from green (band 1) in temp to alpha in destination
|
||||||
|
alphaRaster.setRect(tempRaster.createChild(0, 0, tempRaster.getWidth(),
|
||||||
|
tempRaster.getHeight(), 0, 0, new int[] {1}));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
processWarningOccurred("Unknown WebP alpha compression: " + compression);
|
||||||
|
opaqueAlpha(alphaRaster);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filtering != AlphaFiltering.NONE) {
|
||||||
|
for (int y = 0; y < destination.getHeight(); y++) {
|
||||||
|
for (int x = 0; x < destination.getWidth(); x++) {
|
||||||
|
int predictorAlpha = getPredictorAlpha(alphaRaster, filtering, y, x);
|
||||||
|
alphaRaster.setSample(x, y, 0, alphaRaster.getSample(x, y, 0) + predictorAlpha % 256);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getPredictorAlpha(WritableRaster alphaRaster, int filtering, int y, int x) {
|
||||||
|
switch (filtering) {
|
||||||
|
case AlphaFiltering.NONE:
|
||||||
|
return 0;
|
||||||
|
case AlphaFiltering.HORIZONTAL:
|
||||||
|
if (x == 0) {
|
||||||
|
if (y == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return alphaRaster.getSample(0, y - 1, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return alphaRaster.getSample(x - 1, y, 0);
|
||||||
|
}
|
||||||
|
case AlphaFiltering.VERTICAL:
|
||||||
|
if (y == 0) {
|
||||||
|
if (x == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return alphaRaster.getSample(x - 1, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return alphaRaster.getSample(x, y - 1, 0);
|
||||||
|
}
|
||||||
|
case AlphaFiltering.GRADIENT:
|
||||||
|
if (x == 0 && y == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (x == 0) {
|
||||||
|
return alphaRaster.getSample(0, y - 1, 0);
|
||||||
|
}
|
||||||
|
else if (y == 0) {
|
||||||
|
return alphaRaster.getSample(x - 1, 0, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int left = alphaRaster.getSample(x - 1, y, 0);
|
||||||
|
int top = alphaRaster.getSample(x, y - 1, 0);
|
||||||
|
int topLeft = alphaRaster.getSample(x - 1, y - 1, 0);
|
||||||
|
|
||||||
|
return Math.max(0, Math.min(left + top - topLeft, 255));
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
processWarningOccurred("Unknown WebP alpha filtering: " + filtering);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void applyICCProfileIfNeeded(final BufferedImage destination) {
|
private void applyICCProfileIfNeeded(final BufferedImage destination) {
|
||||||
if (iccProfile != null) {
|
if (iccProfile != null) {
|
||||||
ColorModel colorModel = destination.getColorModel();
|
ColorModel colorModel = destination.getColorModel();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user