diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java index 00dc22ea162ba..31abf9223e98e 100644 --- a/graphics/java/android/graphics/ImageDecoder.java +++ b/graphics/java/android/graphics/ImageDecoder.java @@ -59,23 +59,131 @@ import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicBoolean; /** - * Class for decoding images as {@link Bitmap}s or {@link Drawable}s. + *

A class for converting encoded images (like {@code PNG}, {@code JPEG}, + * {@code WEBP}, {@code GIF}, or {@code HEIF}) into {@link Drawable} or + * {@link Bitmap} objects. + * + *

To use it, first create a {@link Source Source} using one of the + * {@code createSource} overloads. For example, to decode from a {@link File}, call + * {@link #createSource(File)} and pass the result to {@link #decodeDrawable(Source)} + * or {@link #decodeBitmap(Source)}: + * + *

+ *  File file = new File(...);
+ *  ImageDecoder.Source source = ImageDecoder.createSource(file);
+ *  Drawable drawable = ImageDecoder.decodeDrawable(source);
+ *  
+ * + *

To change the default settings, pass the {@link Source Source} and an + * {@link OnHeaderDecodedListener OnHeaderDecodedListener} to + * {@link #decodeDrawable(Source, OnHeaderDecodedListener)} or + * {@link #decodeBitmap(Source, OnHeaderDecodedListener)}. For example, to + * create a sampled image with half the width and height of the original image, + * call {@link #setTargetSampleSize setTargetSampleSize(2)} inside + * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}: + * + *

+ *  OnHeaderDecodedListener listener = new OnHeaderDecodedListener() {
+ *      public void onHeaderDecoded(ImageDecoder decoder, ImageInfo info, Source source) {
+ *          decoder.setTargetSampleSize(2);
+ *      }
+ *  };
+ *  Drawable drawable = ImageDecoder.decodeDrawable(source, listener);
+ *  
+ * + *

The {@link ImageInfo ImageInfo} contains information about the encoded image, like + * its width and height, and the {@link Source Source} can be used to match to a particular + * {@link Source Source} if a single {@link OnHeaderDecodedListener OnHeaderDecodedListener} + * is used with multiple {@link Source Source} objects. + * + *

The {@link OnHeaderDecodedListener OnHeaderDecodedListener} can also be implemented + * as a lambda: + * + *

+ *  Drawable drawable = ImageDecoder.decodeDrawable(source, (decoder, info, src) -> {
+ *      decoder.setTargetSampleSize(2);
+ *  });
+ *  
+ * + *

If the encoded image is an animated {@code GIF} or {@code WEBP}, + * {@link #decodeDrawable decodeDrawable} will return an {@link AnimatedImageDrawable}. To + * start its animation, call {@link AnimatedImageDrawable#start AnimatedImageDrawable.start()}: + * + *

+ *  Drawable drawable = ImageDecoder.decodeDrawable(source);
+ *  if (drawable instanceof AnimatedImageDrawable) {
+ *      ((AnimatedImageDrawable) drawable).start();
+ *  }
+ *  
+ * + *

By default, a {@link Bitmap} created by {@link ImageDecoder} (including + * one that is inside a {@link Drawable}) will be immutable (i.e. + * {@link Bitmap#isMutable Bitmap.isMutable()} returns {@code false}), and it + * will typically have {@code Config} {@link Bitmap.Config#HARDWARE}. Although + * these properties can be changed with {@link #setMutableRequired setMutableRequired(true)} + * (which is only compatible with {@link #decodeBitmap(Source)} and + * {@link #decodeBitmap(Source, OnHeaderDecodedListener)}) and {@link #setAllocator}, + * it is also possible to apply custom effects regardless of the mutability of + * the final returned object by passing a {@link PostProcessor} to + * {@link #setPostProcessor setPostProcessor}. A {@link PostProcessor} can also be a lambda: + * + *

+ *  Drawable drawable = ImageDecoder.decodeDrawable(source, (decoder, info, src) -> {
+ *      decoder.setPostProcessor((canvas) -> {
+ *              // This will create rounded corners.
+ *              Path path = new Path();
+ *              path.setFillType(Path.FillType.INVERSE_EVEN_ODD);
+ *              int width = canvas.getWidth();
+ *              int height = canvas.getHeight();
+ *              path.addRoundRect(0, 0, width, height, 20, 20, Path.Direction.CW);
+ *              Paint paint = new Paint();
+ *              paint.setAntiAlias(true);
+ *              paint.setColor(Color.TRANSPARENT);
+ *              paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
+ *              canvas.drawPath(path, paint);
+ *              return PixelFormat.TRANSLUCENT;
+ *      });
+ *  });
+ *  
+ * + *

If the encoded image is incomplete or contains an error, or if an + * {@link Exception} occurs during decoding, a {@link DecodeException DecodeException} + * will be thrown. In some cases, the {@link ImageDecoder} may have decoded part of + * the image. In order to display the partial image, an + * {@link OnPartialImageListener OnPartialImageListener} must be passed to + * {@link #setOnPartialImageListener setOnPartialImageListener}. For example: + * + *

+ *  Drawable drawable = ImageDecoder.decodeDrawable(source, (decoder, info, src) -> {
+ *      decoder.setOnPartialImageListener((DecodeException e) -> {
+ *              // Returning true indicates to create a Drawable or Bitmap even
+ *              // if the whole image could not be decoded. Any remaining lines
+ *              // will be blank.
+ *              return true;
+ *      });
+ *  });
+ *  
*/ public final class ImageDecoder implements AutoCloseable { /** @hide **/ public static int sApiLevel; /** - * Source of the encoded image data. + * Source of encoded image data. * - *

This object references the data that will be used to decode a - * Drawable or Bitmap in {@link #decodeDrawable} or {@link #decodeBitmap}. - * Constructing a {@code Source} (with one of the overloads of - * {@code createSource}) can be done on any thread because the construction - * simply captures values. The real work is done in decodeDrawable or - * decodeBitmap.

+ *

References the data that will be used to decode a {@link Drawable} + * or {@link Bitmap} in {@link #decodeDrawable decodeDrawable} or + * {@link #decodeBitmap decodeBitmap}. Constructing a {@code Source} (with + * one of the overloads of {@code createSource}) can be done on any thread + * because the construction simply captures values. The real work is done + * in {@link #decodeDrawable decodeDrawable} or {@link #decodeBitmap decodeBitmap}. * - *

Further, a Source object can be reused with different settings, or + *

A {@code Source} object can be reused to create multiple versions of the + * same image. For example, to decode a full size image and its thumbnail, + * the same {@code Source} can be used once with no + * {@link OnHeaderDecodedListener OnHeaderDecodedListener} and once with an + * implementation of {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded} + * that calls {@link #setTargetSize} with smaller dimensions. One {@code Source} * even used simultaneously in multiple threads.

*/ public static abstract class Source { @@ -418,7 +526,7 @@ public final class ImageDecoder implements AutoCloseable { } /** - * Contains information about the encoded image. + * Information about an encoded image. */ public static class ImageInfo { private final Size mSize; @@ -448,8 +556,8 @@ public final class ImageDecoder implements AutoCloseable { /** * Whether the image is animated. * - *

Calling {@link #decodeDrawable} will return an - * {@link AnimatedImageDrawable}.

+ *

If {@code true}, {@link #decodeDrawable decodeDrawable} will + * return an {@link AnimatedImageDrawable}.

*/ public boolean isAnimated() { return mDecoder.mAnimated; @@ -475,19 +583,25 @@ public final class ImageDecoder implements AutoCloseable { public static class IncompleteException extends IOException {}; /** - * Optional listener supplied to {@link #decodeDrawable} or - * {@link #decodeBitmap}. + * Interface for changing the default settings of a decode. * - *

This is necessary in order to change the default settings of the - * decode.

+ *

Supply an instance to + * {@link #decodeDrawable(Source, OnHeaderDecodedListener) decodeDrawable} + * or {@link #decodeBitmap(Source, OnHeaderDecodedListener) decodeBitmap}, + * which will call {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded} + * (in the same thread) once the size is known. The implementation of + * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded} can then + * change the decode settings as desired. */ public static interface OnHeaderDecodedListener { /** - * Called when the header is decoded and the size is known. + * Called by {@link ImageDecoder} when the header has been decoded and + * the image size is known. * - * @param decoder allows changing the default settings of the decode. - * @param info Information about the encoded image. - * @param source that created the decoder. + * @param decoder the object performing the decode, for changing + * its default settings. + * @param info information about the encoded image. + * @param source object that created {@code decoder}. */ public void onHeaderDecoded(@NonNull ImageDecoder decoder, @NonNull ImageInfo info, @NonNull Source source); @@ -570,7 +684,7 @@ public final class ImageDecoder implements AutoCloseable { } /** - * Retrieve the {@link Source} that was interrupted. + * Retrieve the {@link Source Source} that was interrupted. * *

This can be used for equality checking to find the Source which * failed to completely decode.

@@ -595,25 +709,36 @@ public final class ImageDecoder implements AutoCloseable { } /** - * Optional listener supplied to the ImageDecoder. + * Interface for inspecting a {@link DecodeException DecodeException} + * and potentially preventing it from being thrown. * - * Without this listener, errors will throw {@link java.io.IOException}. + *

If an instance is passed to + * {@link #setOnPartialImageListener setOnPartialImageListener}, a + * {@link DecodeException DecodeException} that would otherwise have been + * thrown can be inspected inside + * {@link OnPartialImageListener#onPartialImage onPartialImage}. + * If {@link OnPartialImageListener#onPartialImage onPartialImage} returns + * {@code true}, a partial image will be created. */ public static interface OnPartialImageListener { /** - * Called when there is only a partial image to display. + * Called by {@link ImageDecoder} when there is only a partial image to + * display. * - * If decoding is interrupted after having decoded a partial image, - * this listener lets the client know that and allows them to - * optionally finish the rest of the decode/creation process to create - * a partial {@link Drawable}/{@link Bitmap}. + *

If decoding is interrupted after having decoded a partial image, + * this method will be called. The implementation can inspect the + * {@link DecodeException DecodeException} and optionally finish the + * rest of the decode creation process to create a partial {@link Drawable} + * or {@link Bitmap}. * - * @param e containing information about the decode interruption. - * @return True to create and return a {@link Drawable}/{@link Bitmap} - * with partial data. False (which is the default) to abort the - * decode and throw {@code e}. + * @param exception exception containing information about the + * decode interruption. + * @return {@code true} to create and return a {@link Drawable} or + * {@link Bitmap} with partial data. {@code false} (which is the + * default) to abort the decode and throw {@code e}. Any undecoded + * lines in the image will be blank. */ - boolean onPartialImage(@NonNull DecodeException e); + boolean onPartialImage(@NonNull DecodeException exception); }; // Fields @@ -679,12 +804,13 @@ public final class ImageDecoder implements AutoCloseable { } /** - * Create a new {@link Source} from a resource. + * Create a new {@link Source Source} from a resource. * * @param res the {@link Resources} object containing the image data. * @param resId resource ID of the image data. * @return a new Source object, which can be passed to - * {@link #decodeDrawable} or {@link #decodeBitmap}. + * {@link #decodeDrawable decodeDrawable} or + * {@link #decodeBitmap decodeBitmap}. */ @AnyThread @NonNull @@ -694,12 +820,20 @@ public final class ImageDecoder implements AutoCloseable { } /** - * Create a new {@link Source} from a {@link android.net.Uri}. + * Create a new {@link Source Source} from a {@link android.net.Uri}. + * + *

Accepts the following URI schemes:
+ * * * @param cr to retrieve from. * @param uri of the image file. * @return a new Source object, which can be passed to - * {@link #decodeDrawable} or {@link #decodeBitmap}. + * {@link #decodeDrawable decodeDrawable} or + * {@link #decodeBitmap decodeBitmap}. */ @AnyThread @NonNull @@ -721,7 +855,7 @@ public final class ImageDecoder implements AutoCloseable { } /** - * Create a new {@link Source} from a file in the "assets" directory. + * Create a new {@link Source Source} from a file in the "assets" directory. */ @AnyThread @NonNull @@ -730,12 +864,15 @@ public final class ImageDecoder implements AutoCloseable { } /** - * Create a new {@link Source} from a byte array. + * Create a new {@link Source Source} from a byte array. * * @param data byte array of compressed image data. * @param offset offset into data for where the decoder should begin * parsing. * @param length number of bytes, beginning at offset, to parse. + * @return a new Source object, which can be passed to + * {@link #decodeDrawable decodeDrawable} or + * {@link #decodeBitmap decodeBitmap}. * @throws NullPointerException if data is null. * @throws ArrayIndexOutOfBoundsException if offset and length are * not within data. @@ -767,16 +904,20 @@ public final class ImageDecoder implements AutoCloseable { } /** - * Create a new {@link Source} from a {@link java.nio.ByteBuffer}. + * Create a new {@link Source Source} from a {@link java.nio.ByteBuffer}. * - *

Decoding will start from {@link java.nio.ByteBuffer#position()}. The - * position of {@code buffer} will not be affected.

+ *

Decoding will start from {@link java.nio.ByteBuffer#position() buffer.position()}. + * The position of {@code buffer} will not be affected.

* - *

Note: If this {@code Source} is passed to {@link #decodeDrawable}, and - * the encoded image is animated, the returned {@link AnimatedImageDrawable} + *

Note: If this {@code Source} is passed to {@link #decodeDrawable decodeDrawable}, + * and the encoded image is animated, the returned {@link AnimatedImageDrawable} * will continue reading from the {@code buffer}, so its contents must not * be modified, even after the {@code AnimatedImageDrawable} is returned. * {@code buffer}'s contents should never be modified during decode.

+ * + * @return a new Source object, which can be passed to + * {@link #decodeDrawable decodeDrawable} or + * {@link #decodeBitmap decodeBitmap}. */ @AnyThread @NonNull @@ -812,7 +953,11 @@ public final class ImageDecoder implements AutoCloseable { } /** - * Create a new {@link Source} from a {@link java.io.File}. + * Create a new {@link Source Source} from a {@link java.io.File}. + * + * @return a new Source object, which can be passed to + * {@link #decodeDrawable decodeDrawable} or + * {@link #decodeBitmap decodeBitmap}. */ @AnyThread @NonNull @@ -863,14 +1008,17 @@ public final class ImageDecoder implements AutoCloseable { * Specify the size of the output {@link Drawable} or {@link Bitmap}. * *

By default, the output size will match the size of the encoded - * image, which can be retrieved from the {@link ImageInfo} in - * {@link OnHeaderDecodedListener#onHeaderDecoded}.

+ * image, which can be retrieved from the {@link ImageInfo ImageInfo} in + * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.

+ * + *

This will sample or scale the output to an arbitrary size that may + * be smaller or larger than the encoded size.

* *

Only the last call to this or {@link #setTargetSampleSize} is * respected.

* *

Like all setters on ImageDecoder, this must be called inside - * {@link OnHeaderDecodedListener#onHeaderDecoded}.

+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.

* * @param width must be greater than 0. * @param height must be greater than 0. @@ -924,13 +1072,13 @@ public final class ImageDecoder implements AutoCloseable { * Set the target size with a sampleSize. * *

By default, the output size will match the size of the encoded - * image, which can be retrieved from the {@link ImageInfo} in - * {@link OnHeaderDecodedListener#onHeaderDecoded}.

+ * image, which can be retrieved from the {@link ImageInfo ImageInfo} in + * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.

* *

Requests the decoder to subsample the original image, returning a - * smaller image to save memory. The sample size is the number of pixels + * smaller image to save memory. The {@code sampleSize} is the number of pixels * in either dimension that correspond to a single pixel in the output. - * For example, sampleSize == 4 returns an image that is 1/4 the + * For example, {@code sampleSize == 4} returns an image that is 1/4 the * width/height of the original, and 1/16 the number of pixels.

* *

Must be greater than or equal to 1.

@@ -938,7 +1086,7 @@ public final class ImageDecoder implements AutoCloseable { *

Only the last call to this or {@link #setTargetSize} is respected.

* *

Like all setters on ImageDecoder, this must be called inside - * {@link OnHeaderDecodedListener#onHeaderDecoded}.

+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.

* * @param sampleSize Sampling rate of the encoded image. */ @@ -960,7 +1108,8 @@ public final class ImageDecoder implements AutoCloseable { * Will typically result in a {@link Bitmap.Config#HARDWARE} * allocation, but may be software for small images. In addition, this will * switch to software when HARDWARE is incompatible, e.g. - * {@link #setMutableRequired}, {@link #setDecodeAsAlphaMaskEnabled}. + * {@link #setMutableRequired setMutableRequired(true)} or + * {@link #setDecodeAsAlphaMaskEnabled setDecodeAsAlphaMaskEnabled(true)}. */ public static final int ALLOCATOR_DEFAULT = 0; @@ -983,9 +1132,10 @@ public final class ImageDecoder implements AutoCloseable { * Require a {@link Bitmap.Config#HARDWARE} {@link Bitmap}. * * When this is combined with incompatible options, like - * {@link #setMutableRequired} or {@link #setDecodeAsAlphaMaskEnabled}, - * {@link #decodeDrawable} / {@link #decodeBitmap} will throw an - * {@link java.lang.IllegalStateException}. + * {@link #setMutableRequired setMutableRequired(true)} or + * {@link #setDecodeAsAlphaMaskEnabled setDecodeAsAlphaMaskEnabled(true)}, + * {@link #decodeDrawable decodeDrawable} or {@link #decodeBitmap decodeBitmap} + * will throw an {@link java.lang.IllegalStateException}. */ public static final int ALLOCATOR_HARDWARE = 3; @@ -1002,7 +1152,7 @@ public final class ImageDecoder implements AutoCloseable { *

This is ignored for animated drawables.

* *

Like all setters on ImageDecoder, this must be called inside - * {@link OnHeaderDecodedListener#onHeaderDecoded}.

+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.

* * @param allocator Type of allocator to use. */ @@ -1029,13 +1179,13 @@ public final class ImageDecoder implements AutoCloseable { * {@link android.view.View} system (i.e. to a {@link Canvas}). Calling * this method with a value of {@code true} will result in * {@link #decodeBitmap} returning a {@link Bitmap} with unpremultiplied - * pixels. See {@link Bitmap#isPremultiplied}. This is incompatible with - * {@link #decodeDrawable}; attempting to decode an unpremultiplied - * {@link Drawable} will throw an {@link java.lang.IllegalStateException}. - *

+ * pixels. See {@link Bitmap#isPremultiplied Bitmap.isPremultiplied()}. + * This is incompatible with {@link #decodeDrawable decodeDrawable}; + * attempting to decode an unpremultiplied {@link Drawable} will throw an + * {@link java.lang.IllegalStateException}.

* *

Like all setters on ImageDecoder, this must be called inside - * {@link OnHeaderDecodedListener#onHeaderDecoded}.

+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.

*/ public void setUnpremultipliedRequired(boolean unpremultipliedRequired) { mUnpremultipliedRequired = unpremultipliedRequired; @@ -1072,6 +1222,9 @@ public final class ImageDecoder implements AutoCloseable { * {@link Bitmap}. For a {@code Drawable} or an immutable {@code Bitmap}, * this is the only way to process the image after decoding.

* + *

If combined with {@link #setTargetSize} and/or {@link #setCrop}, + * {@link PostProcessor#onPostProcess} occurs last.

+ * *

If set on a nine-patch image, the nine-patch data is ignored.

* *

For an animated image, the drawing commands drawn on the @@ -1079,11 +1232,11 @@ public final class ImageDecoder implements AutoCloseable { * frame.

* *

Like all setters on ImageDecoder, this must be called inside - * {@link OnHeaderDecodedListener#onHeaderDecoded}.

+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.

* */ - public void setPostProcessor(@Nullable PostProcessor p) { - mPostProcessor = p; + public void setPostProcessor(@Nullable PostProcessor postProcessor) { + mPostProcessor = postProcessor; } /** @@ -1098,18 +1251,18 @@ public final class ImageDecoder implements AutoCloseable { * Set (replace) the {@link OnPartialImageListener} on this object. * *

Will be called if there is an error in the input. Without one, an - * error will result in an Exception being thrown.

+ * error will result in an {@code Exception} being thrown.

* *

Like all setters on ImageDecoder, this must be called inside - * {@link OnHeaderDecodedListener#onHeaderDecoded}.

+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.

* */ - public void setOnPartialImageListener(@Nullable OnPartialImageListener l) { - mOnPartialImageListener = l; + public void setOnPartialImageListener(@Nullable OnPartialImageListener listener) { + mOnPartialImageListener = listener; } /** - * Return the {@link OnPartialImageListener} currently set. + * Return the {@link OnPartialImageListener OnPartialImageListener} currently set. */ @Nullable public OnPartialImageListener getOnPartialImageListener() { @@ -1122,14 +1275,14 @@ public final class ImageDecoder implements AutoCloseable { *

{@code subset} must be contained within the size set by * {@link #setTargetSize} or the bounds of the image if setTargetSize was * not called. Otherwise an {@link IllegalStateException} will be thrown by - * {@link #decodeDrawable}/{@link #decodeBitmap}.

+ * {@link #decodeDrawable decodeDrawable}/{@link #decodeBitmap decodeBitmap}.

* *

NOT intended as a replacement for - * {@link BitmapRegionDecoder#decodeRegion}. This supports all formats, - * but merely crops the output.

+ * {@link BitmapRegionDecoder#decodeRegion BitmapRegionDecoder.decodeRegion()}. + * This supports all formats, but merely crops the output.

* *

Like all setters on ImageDecoder, this must be called inside - * {@link OnHeaderDecodedListener#onHeaderDecoded}.

+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.

* */ public void setCrop(@Nullable Rect subset) { @@ -1151,7 +1304,7 @@ public final class ImageDecoder implements AutoCloseable { * rectangle during decode. Otherwise it will not be modified. * *

Like all setters on ImageDecoder, this must be called inside - * {@link OnHeaderDecodedListener#onHeaderDecoded}.

+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.

* * @hide */ @@ -1162,21 +1315,22 @@ public final class ImageDecoder implements AutoCloseable { /** * Specify whether the {@link Bitmap} should be mutable. * - *

By default, a {@link Bitmap} created will be immutable, but that can - * be changed with this call.

+ *

By default, a {@link Bitmap} created by {@link #decodeBitmap decodeBitmap} + * will be immutable i.e. {@link Bitmap#isMutable() Bitmap.isMutable()} returns + * {@code false}. This can be changed with {@code setMutableRequired(true)}. * *

Mutable Bitmaps are incompatible with {@link #ALLOCATOR_HARDWARE}, * because {@link Bitmap.Config#HARDWARE} Bitmaps cannot be mutable. * Attempting to combine them will throw an * {@link java.lang.IllegalStateException}.

* - *

Mutable Bitmaps are also incompatible with {@link #decodeDrawable}, + *

Mutable Bitmaps are also incompatible with {@link #decodeDrawable decodeDrawable}, * which would require retrieving the Bitmap from the returned Drawable in * order to modify. Attempting to decode a mutable {@link Drawable} will * throw an {@link java.lang.IllegalStateException}.

* *

Like all setters on ImageDecoder, this must be called inside - * {@link OnHeaderDecodedListener#onHeaderDecoded}.

+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.

*/ public void setMutableRequired(boolean mutable) { mMutable = mutable; @@ -1192,7 +1346,7 @@ public final class ImageDecoder implements AutoCloseable { } /** - * Return whether the {@link Bitmap} will be mutable. + * Return whether the decoded {@link Bitmap} will be mutable. */ public boolean isMutableRequired() { return mMutable; @@ -1219,7 +1373,7 @@ public final class ImageDecoder implements AutoCloseable { * the memory used.

* *

Like all setters on ImageDecoder, this must be called inside - * {@link OnHeaderDecodedListener#onHeaderDecoded}.

+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.

*/ public void setConserveMemory(boolean conserveMemory) { mConserveMemory = conserveMemory; @@ -1244,12 +1398,12 @@ public final class ImageDecoder implements AutoCloseable { * no effect.

* *

This is incompatible with {@link #ALLOCATOR_HARDWARE}. Trying to - * combine them will result in {@link #decodeDrawable}/ - * {@link #decodeBitmap} throwing an + * combine them will result in {@link #decodeDrawable decodeDrawable}/ + * {@link #decodeBitmap decodeBitmap} throwing an * {@link java.lang.IllegalStateException}.

* *

Like all setters on ImageDecoder, this must be called inside - * {@link OnHeaderDecodedListener#onHeaderDecoded}.

+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.

*/ public void setDecodeAsAlphaMaskEnabled(boolean enabled) { mDecodeAsAlphaMask = enabled; @@ -1304,21 +1458,22 @@ public final class ImageDecoder implements AutoCloseable { /** * Specify the desired {@link ColorSpace} for the output. * - *

If non-null, the decoder will try to decode into this - * color space. If it is null, which is the default, or the request cannot - * be met, the decoder will pick either the color space embedded in the - * image or the color space best suited for the requested image - * configuration (for instance {@link ColorSpace.Named#SRGB sRGB} for - * the {@link Bitmap.Config#ARGB_8888} configuration).

+ *

If non-null, the decoder will try to decode into {@code colorSpace}. + * If it is null, which is the default, or the request cannot be met, the + * decoder will pick either the color space embedded in the image or the + * {@link ColorSpace} best suited for the requested image configuration + * (for instance {@link ColorSpace.Named#SRGB sRGB} for the + * {@link Bitmap.Config#ARGB_8888} configuration).

* *

{@link Bitmap.Config#RGBA_F16} always uses the - * {@link ColorSpace.Named#LINEAR_EXTENDED_SRGB scRGB} color space). + * {@link ColorSpace.Named#LINEAR_EXTENDED_SRGB scRGB} color space. * Bitmaps in other configurations without an embedded color space are * assumed to be in the {@link ColorSpace.Named#SRGB sRGB} color space.

* *

Only {@link ColorSpace.Model#RGB} color spaces are * currently supported. An IllegalArgumentException will - * be thrown by the decode methods when setting a non-RGB color space + * be thrown by {@link #decodeDrawable decodeDrawable}/ + * {@link #decodeBitmap decodeBitmap} when setting a non-RGB color space * such as {@link ColorSpace.Named#CIE_LAB Lab}.

* *

The specified color space's transfer function must be @@ -1328,12 +1483,20 @@ public final class ImageDecoder implements AutoCloseable { * specified color space returns null.

* *

Like all setters on ImageDecoder, this must be called inside - * {@link OnHeaderDecodedListener#onHeaderDecoded}.

+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.

*/ public void setTargetColorSpace(ColorSpace colorSpace) { mDesiredColorSpace = colorSpace; } + /** + * Closes this resource, relinquishing any underlying resources. This method + * is invoked automatically on objects managed by the try-with-resources + * statement. + * + *

This is an implementation detail of {@link ImageDecoder}, and should + * never be called manually.

+ */ @Override public void close() { mCloseGuard.close(); @@ -1421,7 +1584,7 @@ public final class ImageDecoder implements AutoCloseable { * Create a {@link Drawable} from a {@code Source}. * * @param src representing the encoded image. - * @param listener for learning the {@link ImageInfo} and changing any + * @param listener for learning the {@link ImageInfo ImageInfo} and changing any * default settings on the {@code ImageDecoder}. This will be called on * the same thread as {@code decodeDrawable} before that method returns. * This is required in order to change any of the default settings. @@ -1503,8 +1666,8 @@ public final class ImageDecoder implements AutoCloseable { /** * Create a {@link Drawable} from a {@code Source}. * - *

Since there is no {@link OnHeaderDecodedListener}, the default - * settings will be used. In order to change any settings, call + *

Since there is no {@link OnHeaderDecodedListener OnHeaderDecodedListener}, + * the default settings will be used. In order to change any settings, call * {@link #decodeDrawable(Source, OnHeaderDecodedListener)} instead.

* * @param src representing the encoded image. @@ -1523,7 +1686,7 @@ public final class ImageDecoder implements AutoCloseable { * Create a {@link Bitmap} from a {@code Source}. * * @param src representing the encoded image. - * @param listener for learning the {@link ImageInfo} and changing any + * @param listener for learning the {@link ImageInfo ImageInfo} and changing any * default settings on the {@code ImageDecoder}. This will be called on * the same thread as {@code decodeBitmap} before that method returns. * This is required in order to change any of the default settings. @@ -1616,8 +1779,8 @@ public final class ImageDecoder implements AutoCloseable { /** * Create a {@link Bitmap} from a {@code Source}. * - *

Since there is no {@link OnHeaderDecodedListener}, the default - * settings will be used. In order to change any settings, call + *

Since there is no {@link OnHeaderDecodedListener OnHeaderDecodedListener}, + * the default settings will be used. In order to change any settings, call * {@link #decodeBitmap(Source, OnHeaderDecodedListener)} instead.

* * @param src representing the encoded image. diff --git a/graphics/java/android/graphics/PostProcessor.java b/graphics/java/android/graphics/PostProcessor.java index b1712e92e2fe0..6fed39b9975d6 100644 --- a/graphics/java/android/graphics/PostProcessor.java +++ b/graphics/java/android/graphics/PostProcessor.java @@ -16,25 +16,26 @@ package android.graphics; -import android.annotation.IntDef; import android.annotation.NonNull; +import android.graphics.drawable.AnimatedImageDrawable; import android.graphics.drawable.Drawable; /** * Helper interface for adding custom processing to an image. * - *

The image being processed may be a {@link Drawable}, {@link Bitmap} or frame - * of an animated image produced by {@link ImageDecoder}. This is called before - * the requested object is returned.

+ *

The image being processed may be a {@link Drawable}, a {@link Bitmap}, or + * a frame of an {@link AnimatedImageDrawable} produced by {@link ImageDecoder}. + * This is called before the requested object is returned.

* - *

This custom processing also applies to image types that are otherwise - * immutable, such as {@link Bitmap.Config#HARDWARE}.

+ *

This custom processing can even be applied to images that will be returned + * as immutable objects, such as a {@link Bitmap} with {@code Config} + * {@link Bitmap.Config#HARDWARE} returned by {@link ImageDecoder}.

* - *

On an animated image, the callback will only be called once, but the drawing - * commands will be applied to each frame, as if the {@code Canvas} had been - * returned by {@link Picture#beginRecording}.

+ *

On an {@link AnimatedImageDrawable}, the callback will only be called once, + * but the drawing commands will be applied to each frame, as if the {@link Canvas} + * had been returned by {@link Picture#beginRecording Picture.beginRecording}.

* - *

Supplied to ImageDecoder via {@link ImageDecoder#setPostProcessor}.

+ *

Supplied to ImageDecoder via {@link ImageDecoder#setPostProcessor setPostProcessor}.

*/ public interface PostProcessor { /** @@ -43,43 +44,44 @@ public interface PostProcessor { *

Drawing to the {@link Canvas} will behave as if the initial processing * (e.g. decoding) already exists in the Canvas. An implementation can draw * effects on top of this, or it can even draw behind it using - * {@link PorterDuff.Mode#DST_OVER}. A common effect is to add transparency - * to the corners to achieve rounded corners. That can be done with the - * following code:

+ * {@link PorterDuff.Mode#DST_OVER PorterDuff.Mode.DST_OVER}. A common + * effect is to add transparency to the corners to achieve rounded corners. + * That can be done with the following code:

* - * - * Path path = new Path(); - * path.setFillType(Path.FillType.INVERSE_EVEN_ODD); - * int width = canvas.getWidth(); - * int height = canvas.getHeight(); - * path.addRoundRect(0, 0, width, height, 20, 20, Path.Direction.CW); - * Paint paint = new Paint(); - * paint.setAntiAlias(true); - * paint.setColor(Color.TRANSPARENT); - * paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); - * canvas.drawPath(path, paint); - * return PixelFormat.TRANSLUCENT; - * + *
+     *  Path path = new Path();
+     *  path.setFillType(Path.FillType.INVERSE_EVEN_ODD);
+     *  int width = canvas.getWidth();
+     *  int height = canvas.getHeight();
+     *  path.addRoundRect(0, 0, width, height, 20, 20, Path.Direction.CW);
+     *  Paint paint = new Paint();
+     *  paint.setAntiAlias(true);
+     *  paint.setColor(Color.TRANSPARENT);
+     *  paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
+     *  canvas.drawPath(path, paint);
+     *  return PixelFormat.TRANSLUCENT;
+     *  
* * * @param canvas The {@link Canvas} to draw to. * @return Opacity of the result after drawing. - * {@link PixelFormat#UNKNOWN} means that the implementation did not - * change whether the image has alpha. Return this unless you added - * transparency (e.g. with the code above, in which case you should - * return {@code PixelFormat.TRANSLUCENT}) or you forced the image to - * be opaque (e.g. by drawing everywhere with an opaque color and - * {@code PorterDuff.Mode.DST_OVER}, in which case you should return - * {@code PixelFormat.OPAQUE}). - * {@link PixelFormat#TRANSLUCENT} means that the implementation added - * transparency. This is safe to return even if the image already had - * transparency. This is also safe to return if the result is opaque, - * though it may draw more slowly. - * {@link PixelFormat#OPAQUE} means that the implementation forced the - * image to be opaque. This is safe to return even if the image was - * already opaque. - * {@link PixelFormat#TRANSPARENT} (or any other integer) is not - * allowed, and will result in throwing an + * {@link PixelFormat#UNKNOWN PixelFormat.UNKNOWN} means that the + * implementation did not change whether the image has alpha. Return + * this unless you added transparency (e.g. with the code above, in + * which case you should return + * {@link PixelFormat#TRANSLUCENT PixelFormat.TRANSLUCENT}) or you + * forced the image to be opaque (e.g. by drawing everywhere with an + * opaque color and {@link PorterDuff.Mode#DST_OVER PorterDuff.Mode.DST_OVER}, + * in which case you should return {@link PixelFormat#OPAQUE PixelFormat.OPAQUE}). + * {@link PixelFormat#TRANSLUCENT PixelFormat.TRANSLUCENT} means that + * the implementation added transparency. This is safe to return even + * if the image already had transparency. This is also safe to return + * if the result is opaque, though it may draw more slowly. + * {@link PixelFormat#OPAQUE PixelFormat.OPAQUE} means that the + * implementation forced the image to be opaque. This is safe to return + * even if the image was already opaque. + * {@link PixelFormat#TRANSPARENT PixelFormat.TRANSPARENT} (or any other + * integer) is not allowed, and will result in throwing an * {@link java.lang.IllegalArgumentException}. */ @PixelFormat.Opacity