Skip to content

Commit

Permalink
Merge pull request #9 from umjammer/0.0.7
Browse files Browse the repository at this point in the history
0.0.7
  • Loading branch information
umjammer authored Oct 15, 2024
2 parents 94753a6 + ce7facf commit 47c364e
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 41 deletions.
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,13 @@

Java AVIF decoder and encoder<br/>
wrapped [libavif](https://github.com/AOMediaCodec/libavif) by jna<br/>
based on https://github.com/AOMediaCodec/libavif/tree/main/android_jni

<img alt="avif logo" src="https://upload.wikimedia.org/wikipedia/commons/4/45/Avif-logo-rgb.svg" width="256"/>
<sub>© <a href="https://aomedia.org/av1/">AOM</a></sub>
<img alt="avif logo" src="https://upload.wikimedia.org/wikipedia/commons/4/45/Avif-logo-rgb.svg" width="200"/><sub>© <a href="https://aomedia.org/av1/">AOM</a></sub>

## Install

* install `libavif` 1.0.3~ ... e.g. `brew intall libavif`
* https://jitpack.io/#umjammer/vavi-image-avif
* [maven](https://jitpack.io/#umjammer/vavi-image-avif)
* add `-Djna.library.path=/opt/homebrew/lib` for jvm args

## Usage
Expand All @@ -30,6 +28,7 @@ based on https://github.com/AOMediaCodec/libavif/tree/main/android_jni

## References

* [based on](https://github.com/AOMediaCodec/libavif/tree/main/android_jni)

## TODO

Expand Down
38 changes: 25 additions & 13 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<groupId>vavi</groupId>
<artifactId>vavi-image-avif</artifactId>
<version>0.0.6</version>
<version>0.0.7</version>

<name>Java AVIF Decoder</name>
<scm>
Expand All @@ -18,12 +18,11 @@

<properties>
<jnaerator.version>0.12</jnaerator.version>
<native.prefix>/usr/local</native.prefix>
</properties>

<profiles>
<profile>
<id>mac arm64</id>
<id>arm64</id>
<activation>
<os>
<family>mac</family>
Expand All @@ -34,6 +33,17 @@
<native.prefix>/opt/homebrew</native.prefix>
</properties>
</profile>
<profile>
<id>x86_64</id>
<activation>
<os>
<arch>x86_64</arch>
</os>
</activation>
<properties>
<native.prefix>/usr/local</native.prefix>
</properties>
</profile>

<profile>
<!-- mvn -P jnaerator jnaerator:generate -->
Expand Down Expand Up @@ -65,7 +75,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<version>3.12.1</version>
<configuration>
<release>17</release>
</configuration>
Expand All @@ -74,7 +84,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.2</version>
<version>3.2.5</version>
<configuration>
<argLine>
--add-opens java.logging/java.util.logging=ALL-UNNAMED
Expand All @@ -92,7 +102,7 @@
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.10.2</version>
<version>5.10.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Expand All @@ -107,15 +117,10 @@
</repositories>

<dependencies>
<dependency>
<groupId>com.github.umjammer</groupId>
<artifactId>vavi-commons</artifactId>
<version>1.1.12</version>
</dependency>
<dependency>
<groupId>com.github.umjammer</groupId>
<artifactId>vavi-image</artifactId>
<version>1.0.11</version>
<version>1.0.12</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
Expand All @@ -126,7 +131,7 @@
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
<version>3.9.6</version>
<version>3.9.9</version>
</dependency>

<dependency>
Expand All @@ -144,5 +149,12 @@
<artifactId>junit-platform-commons</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>com.github.umjammer</groupId>
<artifactId>vavi-commons</artifactId>
<version>1.1.14</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
22 changes: 13 additions & 9 deletions src/main/java/vavi/awt/image/avif/jna/Avif.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@

import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.nio.ByteBuffer;
import java.util.logging.Level;

import com.sun.jna.Native;
import com.sun.jna.NativeLong;
Expand All @@ -19,7 +20,8 @@
import vavi.awt.image.jna.avif.avifRGBImage;
import vavi.awt.image.jna.avif.avifROData;
import vavi.awt.image.jna.avif.avifRWData;
import vavi.util.Debug;

import static java.lang.System.getLogger;


/**
Expand All @@ -29,12 +31,14 @@
*/
public class Avif {

private static final Logger logger = getLogger(Avif.class.getName());

private static final Avif avif = new Avif();

// This is a utility class and cannot be instantiated.
private Avif() {
String version = AvifLibrary.INSTANCE.avifVersion();
Debug.println(Level.FINE, version);
logger.log(Level.DEBUG, "libavif version: " + version);
ComparableVersion current = new ComparableVersion(version);
ComparableVersion allowed = new ComparableVersion("1.0.3");

Expand Down Expand Up @@ -71,7 +75,7 @@ public BufferedImage getCompatibleImage(ByteBuffer encoded, int length) {
Pointer buffer = Native.getDirectBufferPointer(encoded);
avifDecoder decoder = createDecoderAndParse(buffer, length, Runtime.getRuntime().availableProcessors());
BufferedImage image = new BufferedImage(decoder.image.width, decoder.image.height, BufferedImage.TYPE_4BYTE_ABGR);
Debug.println(Level.FINER, "image depth: " + decoder.image.depth);
logger.log(Level.TRACE,"image depth: " + decoder.image.depth);
return image;
}

Expand Down Expand Up @@ -149,7 +153,7 @@ public BufferedImage decode(ByteBuffer encoded, int length, BufferedImage bitmap
if (res != AvifLibrary.avifResult.AVIF_RESULT_OK) {
throw new IllegalStateException(String.format("Failed to convert YUV Pixels to RGB. Status: %d", res));
}
// cause nativeBuffer doesn't have array()
// because nativeBuffer doesn't have array()
ByteBuffer localBuffer = ByteBuffer.allocate(nativeBuffer.capacity());
localBuffer.put(nativeBuffer);
bitmap.getRaster().setDataElements(0, 0, bitmap.getWidth(), bitmap.getHeight(), localBuffer.array());
Expand All @@ -159,7 +163,7 @@ public BufferedImage decode(ByteBuffer encoded, int length, BufferedImage bitmap

/** Encodes the java image into the AVIF image. */
public ByteBuffer encode(BufferedImage bitmap, int quality) {
Debug.println(Level.FINE, "depth: " + bitmap.getColorModel().getPixelSize() / bitmap.getColorModel().getNumComponents());
logger.log(Level.DEBUG,"depth: " + bitmap.getColorModel().getPixelSize() / bitmap.getColorModel().getNumComponents());
avifImage image = AvifLibrary.INSTANCE.avifImageCreate(bitmap.getWidth(), bitmap.getHeight(), bitmap.getColorModel().getPixelSize() / bitmap.getColorModel().getNumComponents(), AvifLibrary.avifPixelFormat.AVIF_PIXEL_FORMAT_YUV444); // these values dictate what goes into the final AVIF
if (image == null) {
throw new OutOfMemoryError("avifImageCreate");
Expand All @@ -176,7 +180,7 @@ public ByteBuffer encode(BufferedImage bitmap, int quality) {
// * transforms (transformFlags, pasp, clap, irot, imir)

// If you have RGB(A) data you want to encode, use this path
Debug.printf(Level.FINE, "Encoding from converted RGBA");
logger.log(Level.DEBUG,"Encoding from converted RGBA");

if (bitmap.getType() != BufferedImage.TYPE_4BYTE_ABGR) {
throw new IllegalStateException(String.format("Bitmap format (%d) is not supported.", bitmap.getType()));
Expand All @@ -192,7 +196,7 @@ public ByteBuffer encode(BufferedImage bitmap, int quality) {
// ByteBuffer nativeBuffer = ByteBuffer.allocateDirect(bitmap.getWidth() * bitmap.getHeight() * bytes);
// rgb.pixels = Native.getDirectBufferPointer(nativeBuffer);
// rgb.rowBytes = bitmap.getWidth() * bytes;
//Debug.printf(Level.FINE, StringUtil.paramString(rgb)); // TODO paramString doesn't work jdk16+
//logger.log(Level.DEBUG, StringUtil.paramString(rgb)); // TODO paramString doesn't work jdk16+

nativeBuffer.put(((DataBufferByte) bitmap.getRaster().getDataBuffer()).getData());

Expand Down Expand Up @@ -232,7 +236,7 @@ public ByteBuffer encode(BufferedImage bitmap, int quality) {
throw new IllegalStateException(String.format("Failed to finish encode: %s", AvifLibrary.INSTANCE.avifResultToString(finishResult)));
}

Debug.printf(Level.FINE, "Encode success: %d total bytes", avifOutput.size.longValue());
logger.log(Level.DEBUG, "Encode success: {0} total bytes", avifOutput.size.longValue());

AvifLibrary.INSTANCE.avifRGBImageFreePixels(rgb);
AvifLibrary.INSTANCE.avifEncoderDestroy(encoder);
Expand Down
16 changes: 9 additions & 7 deletions src/main/java/vavi/imageio/avif/AvifImageReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import javax.imageio.IIOException;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
Expand All @@ -25,7 +26,8 @@

import vavi.awt.image.avif.jna.Avif;
import vavi.imageio.WrappedImageInputStream;
import vavi.util.Debug;

import static java.lang.System.getLogger;


/**
Expand All @@ -36,6 +38,8 @@
*/
public class AvifImageReader extends ImageReader {

private static final Logger logger = getLogger(AvifImageReader.class.getName());

/** */
private BufferedImage image;

Expand Down Expand Up @@ -72,7 +76,7 @@ public int getHeight(int imageIndex) throws IIOException {
public BufferedImage read(int imageIndex, ImageReadParam param)
throws IIOException {

Debug.println(Level.FINE, "decode start");
logger.log(Level.DEBUG,"decode start");
long t = System.currentTimeMillis();
InputStream stream = new WrappedImageInputStream((ImageInputStream) input);

Expand All @@ -85,7 +89,7 @@ public BufferedImage read(int imageIndex, ImageReadParam param)
baos.write(b, 0, r);
}
int l = baos.size();
Debug.println(Level.FINE, "size: " + l);
logger.log(Level.DEBUG,"size: {0} bytes", l);
ByteBuffer bb = ByteBuffer.allocateDirect(l);
bb.put(baos.toByteArray(), 0, l);

Expand All @@ -96,7 +100,7 @@ public BufferedImage read(int imageIndex, ImageReadParam param)
} catch (IOException e) {
throw new IIOException(e.getMessage(), e);
} finally {
Debug.println(Level.FINE, "time: " + (System.currentTimeMillis() - t));
logger.log(Level.DEBUG,"time: {0} ms", System.currentTimeMillis() - t);
}
}

Expand All @@ -120,5 +124,3 @@ public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IIOExce
return l.iterator();
}
}

/* */
12 changes: 8 additions & 4 deletions src/main/java/vavi/imageio/avif/AvifImageReaderSpi.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,18 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.nio.ByteBuffer;
import java.util.Locale;
import java.util.Properties;
import java.util.logging.Level;
import javax.imageio.ImageReader;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.ImageInputStream;

import vavi.awt.image.avif.jna.Avif;
import vavi.util.Debug;

import static java.lang.System.getLogger;


/**
Expand All @@ -29,6 +31,8 @@
*/
public class AvifImageReaderSpi extends ImageReaderSpi {

private static final Logger logger = getLogger(AvifImageReaderSpi.class.getName());

static {
try {
try (InputStream is = AvifImageReaderSpi.class.getResourceAsStream("/META-INF/maven/vavi/vavi-image-avif/pom.properties")) {
Expand Down Expand Up @@ -99,7 +103,7 @@ public String getDescription(Locale locale) {

@Override
public boolean canDecodeInput(Object obj) throws IOException {
Debug.println(Level.FINE, "input: " + obj);
logger.log(Level.DEBUG,"input: " + obj);
if (obj instanceof ImageInputStream stream) {
stream.mark();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Expand All @@ -110,7 +114,7 @@ public boolean canDecodeInput(Object obj) throws IOException {
baos.write(b, 0, r);
}
int l = baos.size();
Debug.println(Level.FINE, "size: " + l);
logger.log(Level.DEBUG,"size: " + l);
ByteBuffer bb = ByteBuffer.allocateDirect(l);
bb.put(baos.toByteArray(), 0, l);
stream.reset();
Expand Down
10 changes: 7 additions & 3 deletions src/main/java/vavi/imageio/avif/AvifImageWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.nio.ByteBuffer;
import java.util.logging.Level;
import javax.imageio.IIOImage;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
Expand All @@ -19,7 +20,8 @@
import javax.imageio.stream.ImageOutputStream;

import vavi.awt.image.avif.jna.Avif;
import vavi.util.Debug;

import static java.lang.System.getLogger;


/**
Expand All @@ -30,6 +32,8 @@
*/
public class AvifImageWriter extends ImageWriter {

private static final Logger logger = getLogger(AvifImageWriter.class.getName());

/**
* Constructs an <code>ImageWriter</code> and sets its
* <code>originatingProvider</code> instance variable to the
Expand Down Expand Up @@ -80,7 +84,7 @@ public void write(IIOMetadata streamMetadata, IIOImage image, ImageWriteParam pa
ios.write(bb.array());
ios.flush();
} finally {
Debug.println(Level.FINE, "time: " + (System.currentTimeMillis() - t));
logger.log(Level.DEBUG,"time: " + (System.currentTimeMillis() - t));
}
}
}
3 changes: 2 additions & 1 deletion src/test/resources/logging.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level=ALL
java.util.logging.ConsoleHandler.formatter=vavi.util.logging.VaviFormatter

#vavi.util.level=FINE
vavi.awt.image.avif.level=FINE
vavi.imageio.avif.level=FINE

0 comments on commit 47c364e

Please sign in to comment.