shared/java/Codec.java (171 lines of code) (raw):
package org.jetbrains.skija;
import java.lang.ref.*;
import lombok.*;
import org.jetbrains.annotations.*;
import org.jetbrains.skija.impl.*;
public class Codec extends Managed implements IHasImageInfo {
static { Library.staticLoad(); }
@ApiStatus.Internal
public ImageInfo _imageInfo = null;
@ApiStatus.Internal
public Codec(long ptr) {
super(ptr, _FinalizerHolder.PTR);
}
/**
* If this data represents an encoded image that we know how to decode,
* return an Codec that can decode it. Otherwise throws IllegalArgumentException.
*/
public static Codec makeFromData(Data data) {
try {
Stats.onNativeCall();
long ptr = _nMakeFromData(Native.getPtr(data));
if (ptr == 0)
throw new IllegalArgumentException("Unsupported format");
return new Codec(ptr);
} finally {
Reference.reachabilityFence(data);
}
}
@Override @NotNull
public ImageInfo getImageInfo() {
try {
if (_imageInfo == null) {
Stats.onNativeCall();
_imageInfo = _nGetImageInfo(_ptr);
}
return _imageInfo;
} finally {
Reference.reachabilityFence(this);
}
}
@NotNull @Contract("-> new")
public IPoint getSize() {
try {
Stats.onNativeCall();
return IPoint._makeFromLong(_nGetSize(_ptr));
} finally {
Reference.reachabilityFence(this);
}
}
@NotNull
public EncodedOrigin getEncodedOrigin() {
try {
Stats.onNativeCall();
return EncodedOrigin._values[_nGetEncodedOrigin(_ptr)];
} finally {
Reference.reachabilityFence(this);
}
}
@NotNull
public EncodedImageFormat getEncodedImageFormat() {
try {
Stats.onNativeCall();
return EncodedImageFormat._values[_nGetEncodedImageFormat(_ptr)];
} finally {
Reference.reachabilityFence(this);
}
}
/**
* <p>Decodes an image into a bitmap.</p>
*
* @return decoded bitmap
*/
@NotNull @Contract("_ -> new")
public Bitmap readPixels() {
Bitmap bitmap = new Bitmap();
bitmap.allocPixels(getImageInfo());
readPixels(bitmap);
return bitmap;
}
/**
* <p>Decodes an image into a bitmap.</p>
*
* <p>Repeated calls to this function should give the same results,
* allowing the PixelRef to be immutable.</p>
*
* <p>Bitmap specifies the description of the format (config, size)
* expected by the caller. This can simply be identical
* to the info returned by getImageInfo().</p>
*
* <p>This contract also allows the caller to specify
* different output-configs, which the implementation can
* decide to support or not.</p>
*
* <p>A size that does not match getImageInfo() implies a request
* to scale. If the generator cannot perform this scale,
* it will throw an exception.</p>
*
* <p>If the info contains a non-null ColorSpace, the codec
* will perform the appropriate color space transformation.</p>
*
* <p>If the caller passes in the ColorSpace that maps to the
* ICC profile reported by getICCProfile(), the color space
* transformation is a no-op.</p>
*
* <p>If the caller passes a null SkColorSpace, no color space
* transformation will be done.</p>
*
* @param bitmap the description of the format (config, size) expected by the caller
* @return this
*/
@NotNull @Contract("_ -> this")
public Codec readPixels(Bitmap bitmap) {
try {
Stats.onNativeCall();
_validateResult(_nReadPixels(_ptr, Native.getPtr(bitmap), 0, -1));
return this;
} finally {
Reference.reachabilityFence(bitmap);
}
}
/**
* <p>Decodes a frame in a multi-frame image into a bitmap.</p>
*
* <p>Repeated calls to this function should give the same results,
* allowing the PixelRef to be immutable.</p>
*
* <p>Bitmap specifies the description of the format (config, size)
* expected by the caller. This can simply be identical
* to the info returned by getImageInfo().</p>
*
* <p>This contract also allows the caller to specify
* different output-configs, which the implementation can
* decide to support or not.</p>
*
* <p>A size that does not match getImageInfo() implies a request
* to scale. If the generator cannot perform this scale,
* it will throw an exception.</p>
*
* <p>If the info contains a non-null ColorSpace, the codec
* will perform the appropriate color space transformation.</p>
*
* <p>If the caller passes in the ColorSpace that maps to the
* ICC profile reported by getICCProfile(), the color space
* transformation is a no-op.</p>
*
* <p>If the caller passes a null SkColorSpace, no color space
* transformation will be done.</p>
*
* @param bitmap the description of the format (config, size) expected by the caller
* @param frame index of the frame in multi-frame image to decode
* @return this
*/
@NotNull @Contract("_ -> this")
public Codec readPixels(Bitmap bitmap, int frame) {
try {
Stats.onNativeCall();
_validateResult(_nReadPixels(_ptr, Native.getPtr(bitmap), frame, -1));
return this;
} finally {
Reference.reachabilityFence(bitmap);
}
}
/**
* <p>Decodes a frame in a multi-frame image into a bitmap.</p>
*
* <p>Repeated calls to this function should give the same results,
* allowing the PixelRef to be immutable.</p>
*
* <p>Bitmap specifies the description of the format (config, size)
* expected by the caller. This can simply be identical
* to the info returned by getImageInfo().</p>
*
* <p>This contract also allows the caller to specify
* different output-configs, which the implementation can
* decide to support or not.</p>
*
* <p>A size that does not match getImageInfo() implies a request
* to scale. If the generator cannot perform this scale,
* it will throw an exception.</p>
*
* <p>If the info contains a non-null ColorSpace, the codec
* will perform the appropriate color space transformation.</p>
*
* <p>If the caller passes in the ColorSpace that maps to the
* ICC profile reported by getICCProfile(), the color space
* transformation is a no-op.</p>
*
* <p>If the caller passes a null SkColorSpace, no color space
* transformation will be done.</p>
*
* @param bitmap the description of the format (config, size) expected by the caller
* @param frame index of the frame in multi-frame image to decode
* @param priorFrame index of the frame already in bitmap, might be used to optimize retrieving current frame
* @return this
*/
@NotNull @Contract("_ -> this")
public Codec readPixels(Bitmap bitmap, int frame, int priorFrame) {
try {
Stats.onNativeCall();
_validateResult(_nReadPixels(_ptr, Native.getPtr(bitmap), frame, priorFrame));
return this;
} finally {
Reference.reachabilityFence(bitmap);
}
}
/**
* <p>Return the number of frames in the image.</p>
*
* <p>May require reading through the stream.</p>
*/
public int getFrameCount() {
try {
Stats.onNativeCall();
return _nGetFrameCount(_ptr);
} finally {
Reference.reachabilityFence(this);
}
}
/**
* <p>Return info about a single frame.</p>
*
* <p>Only supported by multi-frame images. Does not read through the stream,
* so it should be called after getFrameCount() to parse any frames that
* have not already been parsed.</p>
*/
public AnimationFrameInfo getFrameInfo(int frame) {
try {
Stats.onNativeCall();
return _nGetFrameInfo(_ptr, frame);
} finally {
Reference.reachabilityFence(this);
}
}
/**
* <p>Return info about all the frames in the image.</p>
*
* <p>May require reading through the stream to determine info about the
* frames (including the count).</p>
*
* <p>As such, future decoding calls may require a rewind.</p>
*
* <p>For still (non-animated) image codecs, this will return an empty array.</p>
*/
public AnimationFrameInfo[] getFramesInfo() {
try {
Stats.onNativeCall();
return _nGetFramesInfo(_ptr);
} finally {
Reference.reachabilityFence(this);
}
}
/**
* <p>Return the number of times to repeat, if this image is animated. This number does not
* include the first play through of each frame. For example, a repetition count of 4 means
* that each frame is played 5 times and then the animation stops.</p>
*
* <p>It can return -1, a negative number, meaning that the animation
* should loop forever.</p>
*
* <p>May require reading the stream to find the repetition count.</p>
*
* <p>As such, future decoding calls may require a rewind.</p>
*
* <p>For still (non-animated) image codecs, this will return 0.</p>
*/
public int getRepetitionCount() {
try {
Stats.onNativeCall();
return _nGetRepetitionCount(_ptr);
} finally {
Reference.reachabilityFence(this);
}
}
@ApiStatus.Internal
public static void _validateResult(int result) {
switch (result) {
case 1: // kIncompleteInput
throw new IllegalArgumentException("Incomplete input: A partial image was generated.");
case 2: // kErrorInInput
throw new IllegalArgumentException("Error in input");
case 3: // kInvalidConversion
throw new IllegalArgumentException("Invalid conversion: The generator cannot convert to match the request, ignoring dimensions");
case 4: // kInvalidScale
throw new IllegalArgumentException("Invalid scale: The generator cannot scale to requested size");
case 5: // kInvalidParameters
throw new IllegalArgumentException("Invalid parameter: Parameters (besides info) are invalid. e.g. NULL pixels, rowBytes too small, etc");
case 6: // kInvalidInput
throw new IllegalArgumentException("Invalid input: The input did not contain a valid image");
case 7: // kCouldNotRewind
throw new UnsupportedOperationException("Could not rewind: Fulfilling this request requires rewinding the input, which is not supported for this input");
case 8: // kInternalError
throw new RuntimeException("Internal error");
case 9: // kUnimplemented
throw new UnsupportedOperationException("Unimplemented: This method is not implemented by this codec");
}
}
@ApiStatus.Internal
public static class _FinalizerHolder {
public static final long PTR = _nGetFinalizer();
}
@ApiStatus.Internal public static native long _nGetFinalizer();
@ApiStatus.Internal public static native long _nMakeFromData(long dataPtr);
@ApiStatus.Internal public static native ImageInfo _nGetImageInfo(long ptr);
@ApiStatus.Internal public static native long _nGetSize(long ptr);
@ApiStatus.Internal public static native int _nGetEncodedOrigin(long ptr);
@ApiStatus.Internal public static native int _nGetEncodedImageFormat(long ptr);
@ApiStatus.Internal public static native int _nReadPixels(long ptr, long bitmapPtr, int frame, int priorFrame);
@ApiStatus.Internal public static native int _nGetFrameCount(long ptr);
@ApiStatus.Internal public static native AnimationFrameInfo _nGetFrameInfo(long ptr, int frame);
@ApiStatus.Internal public static native AnimationFrameInfo[] _nGetFramesInfo(long ptr);
@ApiStatus.Internal public static native int _nGetRepetitionCount(long ptr);
}