Skip to content

Commit

Permalink
Review suggestions (to be squashed)
Browse files Browse the repository at this point in the history
  • Loading branch information
kinow committed Oct 1, 2023
1 parent 9920098 commit 6af072d
Show file tree
Hide file tree
Showing 16 changed files with 319 additions and 123 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,62 +19,64 @@
import org.apache.commons.imaging.ImagingException;
import org.apache.commons.imaging.common.BinaryFunctions;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunk;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkANIM;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkANMF;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkEXIF;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkICCP;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkVP8;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkVP8L;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkVP8X;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkXMP;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkXYZW;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkAnim;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkAnmf;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkExif;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkIccp;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkVp8;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkVp8l;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkVp8x;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkXml;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkXyzw;

import java.io.IOException;

/**
* WebP chunk type.
*
* @since 1.0-alpha4
*/
public enum WebPChunkType {

/**
* @see WebPChunkVP8
* @see WebPChunkVp8
*/
VP8(WebPChunkVP8::new),
VP8(WebPChunkVp8::new),

/**
* @see WebPChunkVP8L
* @see WebPChunkVp8l
*/
VP8L(WebPChunkVP8L::new),
VP8L(WebPChunkVp8l::new),

/**
* @see WebPChunkVP8X
* @see WebPChunkVp8x
*/
VP8X(WebPChunkVP8X::new),
VP8X(WebPChunkVp8x::new),

/**
* @see WebPChunkANIM
* @see WebPChunkAnim
*/
ANIM(WebPChunkANIM::new),
ANIM(WebPChunkAnim::new),

/**
* @see WebPChunkANMF
* @see WebPChunkAnmf
*/
ANMF(WebPChunkANMF::new),
ANMF(WebPChunkAnmf::new),

/**
* @see WebPChunkICCP
* @see WebPChunkIccp
*/
ICCP(WebPChunkICCP::new),
ICCP(WebPChunkIccp::new),

/**
* @see WebPChunkEXIF
* @see WebPChunkExif
*/
EXIF(WebPChunkEXIF::new),
EXIF(WebPChunkExif::new),

/**
* @see WebPChunkXMP
* @see WebPChunkXml
*/
XMP(WebPChunkXMP::new);
XMP(WebPChunkXml::new);

private interface ChunkConstructor {
WebPChunk make(int type, int size, byte[] bytes) throws IOException, ImagingException;
Expand All @@ -95,7 +97,7 @@ static WebPChunk makeChunk(int chunkType, int size, byte[] bytes) throws IOExcep
WebPChunkType type = findType(chunkType);
return type != null
? type.constructor.make(chunkType, size, bytes)
: new WebPChunkXYZW(chunkType, size, bytes);
: new WebPChunkXyzw(chunkType, size, bytes);
}

private final ChunkConstructor constructor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import org.apache.commons.imaging.common.BinaryConstant;

/**
* Constants used for the WebP image format.
*
* @since 1.0-alpha4
*/
public final class WebPConstants {
Expand All @@ -41,7 +43,6 @@ public final class WebPConstants {
*/
public static final BinaryConstant WEBP_SIGNATURE = new BinaryConstant(new byte[]{'W', 'E', 'B', 'P'});


private WebPConstants() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,22 @@
import java.util.List;

/**
* WebP image metadata.
*
* @since 1.0-alpha4
*/
public final class WebPImageMetadata extends GenericImageMetadata {

/**
* TIFF Exif metadata.
*/
private final TiffImageMetadata exif;

/**
* Create a new WebP image metadata object.
*
* @param exif the Exif metadata.
*/
public WebPImageMetadata(TiffImageMetadata exif) {
this.exif = exif;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@
import org.apache.commons.imaging.formats.tiff.TiffImageMetadata;
import org.apache.commons.imaging.formats.tiff.TiffImageParser;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunk;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkVP8;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkVP8L;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkVP8X;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkXMP;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkVp8;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkVp8l;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkVp8x;
import org.apache.commons.imaging.formats.webp.chunks.WebPChunkXml;

import java.awt.Dimension;
import java.awt.image.BufferedImage;
Expand All @@ -46,6 +46,8 @@
import static org.apache.commons.imaging.common.BinaryFunctions.skipBytes;

/**
* WebP image parser.
*
* @since 1.0-alpha4
*/
public class WebPImageParser extends AbstractImageParser<WebPImagingParameters> implements XmpEmbeddable<WebPImagingParameters> {
Expand Down Expand Up @@ -87,16 +89,16 @@ protected ImageFormat[] getAcceptedTypes() {
private static int readFileHeader(InputStream is) throws IOException, ImagingException {
byte[] buffer = new byte[4];
if (is.read(buffer) < 4 || !WebPConstants.RIFF_SIGNATURE.equals(buffer)) {
throw new ImagingException("Not a Valid WebP File");
throw new ImagingException("Not a valid WebP file");
}

int fileSize = read4Bytes("File Size", is, "Not a Valid WebP File", ByteOrder.LITTLE_ENDIAN);
int fileSize = read4Bytes("File Size", is, "Not a valid WebP file", ByteOrder.LITTLE_ENDIAN);
if (fileSize < 0) {
throw new ImagingException("File Size is too long:" + fileSize);
throw new ImagingException("File size is too long:" + fileSize);
}

if (is.read(buffer) < 4 || !WebPConstants.WEBP_SIGNATURE.equals(buffer)) {
throw new ImagingException("Not a Valid WebP File");
throw new ImagingException("Not a valid WebP file");
}

return fileSize;
Expand All @@ -113,7 +115,7 @@ public WebPImageMetadata getMetadata(ByteSource byteSource, WebPImagingParameter
@Override
public String getXmpXml(ByteSource byteSource, XmpImagingParameters<WebPImagingParameters> params) throws ImagingException, IOException {
try (ChunksReader reader = new ChunksReader(byteSource, WebPChunkType.XMP)) {
WebPChunkXMP chunk = (WebPChunkXMP) reader.readChunk();
WebPChunkXml chunk = (WebPChunkXml) reader.readChunk();
return chunk == null ? null : chunk.getXml();
}
}
Expand All @@ -130,28 +132,28 @@ public ImageInfo getImageInfo(ByteSource byteSource, WebPImagingParameters param
ImageInfo.ColorType colorType = ImageInfo.ColorType.RGB;

WebPChunk chunk = reader.readChunk();
if (chunk instanceof WebPChunkVP8) {
if (chunk instanceof WebPChunkVp8) {
formatDetails = "WebP/Lossy";
numberOfImages = 1;

WebPChunkVP8 vp8 = (WebPChunkVP8) chunk;
WebPChunkVp8 vp8 = (WebPChunkVp8) chunk;
width = vp8.getWidth();
height = vp8.getHeight();
colorType = ImageInfo.ColorType.YCbCr;
} else if (chunk instanceof WebPChunkVP8L) {
} else if (chunk instanceof WebPChunkVp8l) {
formatDetails = "WebP/Lossless";
numberOfImages = 1;

WebPChunkVP8L vp8l = (WebPChunkVP8L) chunk;
WebPChunkVp8l vp8l = (WebPChunkVp8l) chunk;
width = vp8l.getImageWidth();
height = vp8l.getImageHeight();
} else if (chunk instanceof WebPChunkVP8X) {
WebPChunkVP8X vp8x = (WebPChunkVP8X) chunk;
} else if (chunk instanceof WebPChunkVp8x) {
WebPChunkVp8x vp8x = (WebPChunkVp8x) chunk;
width = vp8x.getCanvasWidth();
height = vp8x.getCanvasHeight();
hasAlpha = ((WebPChunkVP8X) chunk).isHasAlpha();
hasAlpha = ((WebPChunkVp8x) chunk).hasAlpha();

if (vp8x.isAnimation()) {
if (vp8x.hasAnimation()) {
formatDetails = "WebP/Animation";

numberOfImages = 0;
Expand Down Expand Up @@ -200,14 +202,14 @@ public ImageInfo getImageInfo(ByteSource byteSource, WebPImagingParameters param
public Dimension getImageSize(ByteSource byteSource, WebPImagingParameters params) throws ImagingException, IOException {
try (ChunksReader reader = new ChunksReader(byteSource)) {
WebPChunk chunk = reader.readChunk();
if (chunk instanceof WebPChunkVP8) {
WebPChunkVP8 vp8 = (WebPChunkVP8) chunk;
if (chunk instanceof WebPChunkVp8) {
WebPChunkVp8 vp8 = (WebPChunkVp8) chunk;
return new Dimension(vp8.getWidth(), vp8.getHeight());
} else if (chunk instanceof WebPChunkVP8L) {
WebPChunkVP8L vp8l = (WebPChunkVP8L) chunk;
} else if (chunk instanceof WebPChunkVp8l) {
WebPChunkVp8l vp8l = (WebPChunkVp8l) chunk;
return new Dimension(vp8l.getImageWidth(), vp8l.getImageHeight());
} else if (chunk instanceof WebPChunkVP8X) {
WebPChunkVP8X vp8x = (WebPChunkVP8X) chunk;
} else if (chunk instanceof WebPChunkVp8x) {
WebPChunkVp8x vp8x = (WebPChunkVp8x) chunk;
return new Dimension(vp8x.getCanvasWidth(), vp8x.getCanvasHeight());
} else {
throw new ImagingException("Unknown WebP chunk type: " + chunk);
Expand Down Expand Up @@ -267,7 +269,7 @@ private static final class ChunksReader implements Closeable {
}

int getOffset() {
return sizeCount + 8; // File Header
return Math.addExact(sizeCount, 8); // File Header
}

@Override
Expand All @@ -277,13 +279,14 @@ public void close() throws IOException {

WebPChunk readChunk() throws ImagingException, IOException {
while (sizeCount < fileSize) {
int type = read4Bytes("Chunk Type", is, "Not a Valid WebP File", ByteOrder.LITTLE_ENDIAN);
int payloadSize = read4Bytes("Chunk Size", is, "Not a Valid WebP File", ByteOrder.LITTLE_ENDIAN);
int type = read4Bytes("Chunk Type", is, "Not a valid WebP file", ByteOrder.LITTLE_ENDIAN);
int payloadSize = read4Bytes("Chunk Size", is, "Not a valid WebP file", ByteOrder.LITTLE_ENDIAN);
if (payloadSize < 0) {
throw new ImagingException("Chunk Payload is too long:" + payloadSize);
}
boolean padding = (payloadSize % 2) != 0;
int chunkSize = payloadSize + 8 + (padding ? 1 : 0);
int extraPadding = Math.addExact(8, (padding ? 1 : 0));
int chunkSize = Math.addExact(payloadSize, extraPadding);

if (firstChunk) {
firstChunk = false;
Expand All @@ -302,7 +305,7 @@ WebPChunk readChunk() throws ImagingException, IOException {
}
if (skip) {
skipBytes(is, payloadSize + (padding ? 1 : 0));
sizeCount += chunkSize;
sizeCount = Math.addExact(sizeCount, chunkSize);
continue;
}
}
Expand All @@ -313,7 +316,7 @@ WebPChunk readChunk() throws ImagingException, IOException {
skipBytes(is, 1);
}

sizeCount += chunkSize;
sizeCount = Math.addExact(sizeCount, chunkSize);
return chunk;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,30 +29,43 @@
* used by the parser.
*
* @see <a href="https://developers.google.com/speed/webp/docs/riff_container">WebP Container Specification</a>
*
* @since 1.0-alpha4
*/
public abstract class WebPChunk extends BinaryFileParser {
private final int type;
private final int size;
protected final byte[] bytes;

/**
* Create a new WebP chunk.
*
* @param type chunk type.
* @param size chunk size.
* @param bytes chunk data.
* @throws ImagingException if the chunk data and the size provided do not match.
*/
WebPChunk(int type, int size, byte[] bytes) throws ImagingException {
super(ByteOrder.LITTLE_ENDIAN);

if (size != bytes.length) {
throw new IllegalArgumentException("Chunk size must match bytes length");
throw new ImagingException("Chunk size must match bytes length");
}

this.type = type;
this.size = size;
this.bytes = bytes;
}

/**
* @return the chunk type.
*/
public int getType() {
return type;
}

/**
* @return the description of the chunk type.
*/
public String getTypeDescription() {
return new String(new byte[]{
(byte) (type & 0xff),
Expand All @@ -61,22 +74,41 @@ public String getTypeDescription() {
(byte) ((type >> 24) & 0xff)}, StandardCharsets.UTF_8);
}

/**
* @return the payload size.
*/
public int getPayloadSize() {
return size;
}

/**
* @return the chunk size.
*/
public int getChunkSize() {
// if chunk size is odd, a single padding byte is added
int padding = (size % 2) != 0 ? 1 : 0;

// Chunk FourCC (4 bytes) + Chunk Size (4 bytes) + Chunk Payload (n bytes) + Padding
return 4 + 4 + size + padding;
int chunkFourCCandSize = 4 + 4;
int paddedSize = Math.addExact(size, padding);
return Math.addExact(chunkFourCCandSize, paddedSize);
}

/**
* @return a copy of the chunk data as bytes.
*/
public byte[] getBytes() {
return bytes.clone();
}

/**
* Print the chunk to the given stream.
*
* @param pw a stream to write to.
* @param offset chunk offset.
* @throws ImagingException if the image is invalid.
* @throws IOException if it fails to write to the given stream.
*/
public void dump(PrintWriter pw, int offset) throws ImagingException, IOException {
pw.printf("Chunk %s at offset %s, length %d%n", getTypeDescription(), offset >= 0 ? String.valueOf(offset) : "unknown", getChunkSize());
}
Expand Down
Loading

0 comments on commit 6af072d

Please sign in to comment.