ImageDecoder.java revision 1a69f4598faef083d0123bb9b6bfcd6acfdec4e0
10c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III/*
20c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III * Copyright (C) 2017 The Android Open Source Project
30c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III *
40c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III * Licensed under the Apache License, Version 2.0 (the "License");
50c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III * you may not use this file except in compliance with the License.
60c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III * You may obtain a copy of the License at
70c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III *
80c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III *      http://www.apache.org/licenses/LICENSE-2.0
90c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III *
100c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III * Unless required by applicable law or agreed to in writing, software
110c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III * distributed under the License is distributed on an "AS IS" BASIS,
120c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III * See the License for the specific language governing permissions and
140c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III * limitations under the License.
150c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III */
160c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
170c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins IIIpackage android.graphics;
180c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
19e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins IIIimport static android.system.OsConstants.SEEK_CUR;
20ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins IIIimport static android.system.OsConstants.SEEK_SET;
21ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III
225f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins IIIimport static java.lang.annotation.RetentionPolicy.SOURCE;
235f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III
240c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins IIIimport android.annotation.IntDef;
250c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins IIIimport android.annotation.NonNull;
26b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins IIIimport android.annotation.Nullable;
271d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins IIIimport android.annotation.TestApi;
28ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins IIIimport android.content.ContentResolver;
29ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins IIIimport android.content.res.AssetFileDescriptor;
30121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins IIIimport android.content.res.AssetManager;
31513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins IIIimport android.content.res.AssetManager.AssetInputStream;
320c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins IIIimport android.content.res.Resources;
33671cce2605ed50c9aba73ab5bd530cb7741c53cdLeon Scroggins IIIimport android.graphics.drawable.AnimatedImageDrawable;
340c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins IIIimport android.graphics.drawable.BitmapDrawable;
35a38b2135a4bf4368734567a73d2e56f1c318fee9Leon Scroggins IIIimport android.graphics.drawable.Drawable;
360c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins IIIimport android.graphics.drawable.NinePatchDrawable;
37ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins IIIimport android.net.Uri;
388290eaba47b99398fbe0bd59138f902bde558ecbLeon Scroggins IIIimport android.os.Build;
39ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins IIIimport android.system.ErrnoException;
40ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins IIIimport android.system.Os;
4166c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenbergerimport android.util.DisplayMetrics;
42a38b2135a4bf4368734567a73d2e56f1c318fee9Leon Scroggins IIIimport android.util.Size;
4366c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenbergerimport android.util.TypedValue;
44ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III
45ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins IIIimport dalvik.system.CloseGuard;
460c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
47a38b2135a4bf4368734567a73d2e56f1c318fee9Leon Scroggins IIIimport libcore.io.IoUtils;
48a38b2135a4bf4368734567a73d2e56f1c318fee9Leon Scroggins III
49e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins IIIimport java.io.File;
50ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins IIIimport java.io.FileDescriptor;
51ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins IIIimport java.io.FileInputStream;
52ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins IIIimport java.io.FileNotFoundException;
530c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins IIIimport java.io.IOException;
540c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins IIIimport java.io.InputStream;
550c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins IIIimport java.lang.annotation.Retention;
56a38b2135a4bf4368734567a73d2e56f1c318fee9Leon Scroggins IIIimport java.nio.ByteBuffer;
57ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins IIIimport java.util.concurrent.atomic.AtomicBoolean;
580c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
590c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III/**
600c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III *  Class for decoding images as {@link Bitmap}s or {@link Drawable}s.
610c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III */
62ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins IIIpublic final class ImageDecoder implements AutoCloseable {
638290eaba47b99398fbe0bd59138f902bde558ecbLeon Scroggins III    /** @hide **/
648290eaba47b99398fbe0bd59138f902bde558ecbLeon Scroggins III    public static int sApiLevel;
658290eaba47b99398fbe0bd59138f902bde558ecbLeon Scroggins III
660c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
670c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  Source of the encoded image data.
680c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
690c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    public static abstract class Source {
70e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        private Source() {}
71e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III
720c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        /* @hide */
73e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        @Nullable
740c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        Resources getResources() { return null; }
750c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
760c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        /* @hide */
7766c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        int getDensity() { return Bitmap.DENSITY_NONE; }
7866c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger
7966c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        /* @hide */
80046a99ebbb90f9ecdead7b057ef99764a1d295b9Leon Scroggins III        final int computeDstDensity() {
8166c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            Resources res = getResources();
8266c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            if (res == null) {
8366c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger                return Bitmap.getDefaultDensity();
8466c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            }
8566c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger
8666c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            return res.getDisplayMetrics().densityDpi;
8766c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        }
8866c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger
8966c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        /* @hide */
90e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        @NonNull
91ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        abstract ImageDecoder createImageDecoder() throws IOException;
920c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    };
930c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
940c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    private static class ByteArraySource extends Source {
95e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        ByteArraySource(@NonNull byte[] data, int offset, int length) {
960c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            mData = data;
970c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            mOffset = offset;
980c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            mLength = length;
990c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        };
1000c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        private final byte[] mData;
1010c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        private final int    mOffset;
1020c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        private final int    mLength;
1030c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
1040c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        @Override
105ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        public ImageDecoder createImageDecoder() throws IOException {
1061d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            return nCreate(mData, mOffset, mLength, this);
1070c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        }
1080c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
1090c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
1100c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    private static class ByteBufferSource extends Source {
111e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        ByteBufferSource(@NonNull ByteBuffer buffer) {
1120c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            mBuffer = buffer;
1130c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        }
1140c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        private final ByteBuffer mBuffer;
1150c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
1160c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        @Override
117ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        public ImageDecoder createImageDecoder() throws IOException {
1180c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            if (!mBuffer.isDirect() && mBuffer.hasArray()) {
1190c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III                int offset = mBuffer.arrayOffset() + mBuffer.position();
1200c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III                int length = mBuffer.limit() - mBuffer.position();
1211d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III                return nCreate(mBuffer.array(), offset, length, this);
1220c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            }
1231d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            return nCreate(mBuffer, mBuffer.position(), mBuffer.limit(), this);
1240c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        }
1250c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
1260c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
127ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    private static class ContentResolverSource extends Source {
128046a99ebbb90f9ecdead7b057ef99764a1d295b9Leon Scroggins III        ContentResolverSource(@NonNull ContentResolver resolver, @NonNull Uri uri,
129046a99ebbb90f9ecdead7b057ef99764a1d295b9Leon Scroggins III                @Nullable Resources res) {
130ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            mResolver = resolver;
131ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            mUri = uri;
132046a99ebbb90f9ecdead7b057ef99764a1d295b9Leon Scroggins III            mResources = res;
133ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        }
134ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III
135ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        private final ContentResolver mResolver;
136ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        private final Uri mUri;
137046a99ebbb90f9ecdead7b057ef99764a1d295b9Leon Scroggins III        private final Resources mResources;
138046a99ebbb90f9ecdead7b057ef99764a1d295b9Leon Scroggins III
139046a99ebbb90f9ecdead7b057ef99764a1d295b9Leon Scroggins III        @Nullable
140046a99ebbb90f9ecdead7b057ef99764a1d295b9Leon Scroggins III        Resources getResources() { return mResources; }
141ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III
142ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        @Override
143ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        public ImageDecoder createImageDecoder() throws IOException {
144ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            AssetFileDescriptor assetFd = null;
1450c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            try {
146ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                if (mUri.getScheme() == ContentResolver.SCHEME_CONTENT) {
147ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                    assetFd = mResolver.openTypedAssetFileDescriptor(mUri,
148ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                            "image/*", null);
149ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                } else {
150ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                    assetFd = mResolver.openAssetFileDescriptor(mUri, "r");
151ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                }
152ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            } catch (FileNotFoundException e) {
153ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                // Some images cannot be opened as AssetFileDescriptors (e.g.
154ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                // bmp, ico). Open them as InputStreams.
155ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                InputStream is = mResolver.openInputStream(mUri);
156ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                if (is == null) {
157ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                    throw new FileNotFoundException(mUri.toString());
158ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                }
159ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III
1601d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III                return createFromStream(is, true, this);
161ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            }
162ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III
163ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            final FileDescriptor fd = assetFd.getFileDescriptor();
164ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            final long offset = assetFd.getStartOffset();
165ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III
166ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            ImageDecoder decoder = null;
167ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            try {
168ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                try {
169ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                    Os.lseek(fd, offset, SEEK_SET);
1701d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III                    decoder = nCreate(fd, this);
171ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                } catch (ErrnoException e) {
1721d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III                    decoder = createFromStream(new FileInputStream(fd), true, this);
173ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                }
1740c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            } finally {
175ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                if (decoder == null) {
176ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                    IoUtils.closeQuietly(assetFd);
177ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                } else {
178ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                    decoder.mAssetFd = assetFd;
1790c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III                }
1800c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            }
181ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            return decoder;
182ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        }
183ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    }
184ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III
185e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    @NonNull
1861d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III    private static ImageDecoder createFromFile(@NonNull File file,
1871d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            @NonNull Source source) throws IOException {
188e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        FileInputStream stream = new FileInputStream(file);
189e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        FileDescriptor fd = stream.getFD();
190e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        try {
191e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III            Os.lseek(fd, 0, SEEK_CUR);
192e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        } catch (ErrnoException e) {
1931d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            return createFromStream(stream, true, source);
194e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        }
195e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III
196e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        ImageDecoder decoder = null;
197e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        try {
1981d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            decoder = nCreate(fd, source);
199e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        } finally {
200e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III            if (decoder == null) {
201e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III                IoUtils.closeQuietly(stream);
202e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III            } else {
203e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III                decoder.mInputStream = stream;
2040b49f5725cabd64d27960b1b017e5c009f701cf8Leon Scroggins III                decoder.mOwnsInputStream = true;
205e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III            }
206e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        }
207e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        return decoder;
208e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    }
209e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III
210e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    @NonNull
2110b49f5725cabd64d27960b1b017e5c009f701cf8Leon Scroggins III    private static ImageDecoder createFromStream(@NonNull InputStream is,
2121d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            boolean closeInputStream, Source source) throws IOException {
213ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        // Arbitrary size matches BitmapFactory.
214ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        byte[] storage = new byte[16 * 1024];
215ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        ImageDecoder decoder = null;
216ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        try {
2171d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            decoder = nCreate(is, storage, source);
218ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        } finally {
219ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            if (decoder == null) {
2200b49f5725cabd64d27960b1b017e5c009f701cf8Leon Scroggins III                if (closeInputStream) {
2210b49f5725cabd64d27960b1b017e5c009f701cf8Leon Scroggins III                    IoUtils.closeQuietly(is);
2220b49f5725cabd64d27960b1b017e5c009f701cf8Leon Scroggins III                }
223ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            } else {
224ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                decoder.mInputStream = is;
2250b49f5725cabd64d27960b1b017e5c009f701cf8Leon Scroggins III                decoder.mOwnsInputStream = closeInputStream;
226ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                decoder.mTempStorage = storage;
227ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            }
228ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        }
229ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III
230ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        return decoder;
231ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    }
2320c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
2330b49f5725cabd64d27960b1b017e5c009f701cf8Leon Scroggins III    /**
2340b49f5725cabd64d27960b1b017e5c009f701cf8Leon Scroggins III     * For backwards compatibility, this does *not* close the InputStream.
2350b49f5725cabd64d27960b1b017e5c009f701cf8Leon Scroggins III     */
23666c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger    private static class InputStreamSource extends Source {
23766c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        InputStreamSource(Resources res, InputStream is, int inputDensity) {
23866c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            if (is == null) {
23966c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger                throw new IllegalArgumentException("The InputStream cannot be null");
24066c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            }
24166c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            mResources = res;
24266c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            mInputStream = is;
24366c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            mInputDensity = res != null ? inputDensity : Bitmap.DENSITY_NONE;
24466c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        }
24566c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger
24666c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        final Resources mResources;
24766c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        InputStream mInputStream;
24866c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        final int mInputDensity;
24966c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger
25066c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        @Override
25166c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        public Resources getResources() { return mResources; }
25266c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger
25366c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        @Override
25466c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        public int getDensity() { return mInputDensity; }
25566c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger
25666c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        @Override
25766c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        public ImageDecoder createImageDecoder() throws IOException {
25866c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger
25966c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            synchronized (this) {
26066c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger                if (mInputStream == null) {
26166c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger                    throw new IOException("Cannot reuse InputStreamSource");
26266c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger                }
26366c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger                InputStream is = mInputStream;
26466c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger                mInputStream = null;
2651d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III                return createFromStream(is, false, this);
26666c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            }
26766c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        }
26866c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger    }
26966c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger
270513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III    /**
271513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III     * Takes ownership of the AssetInputStream.
272513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III     *
273513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III     * @hide
274513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III     */
275513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III    public static class AssetInputStreamSource extends Source {
276513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III        public AssetInputStreamSource(@NonNull AssetInputStream ais,
277513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III                @NonNull Resources res, @NonNull TypedValue value) {
278513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III            mAssetInputStream = ais;
279513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III            mResources = res;
280513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III
281513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III            if (value.density == TypedValue.DENSITY_DEFAULT) {
282513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III                mDensity = DisplayMetrics.DENSITY_DEFAULT;
283513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III            } else if (value.density != TypedValue.DENSITY_NONE) {
284513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III                mDensity = value.density;
285513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III            } else {
286513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III                mDensity = Bitmap.DENSITY_NONE;
287513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III            }
288513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III        }
289513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III
290513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III        private AssetInputStream mAssetInputStream;
291513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III        private final Resources  mResources;
292513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III        private final int        mDensity;
293513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III
294513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III        @Override
295513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III        public Resources getResources() { return mResources; }
296513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III
297513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III        @Override
298513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III        public int getDensity() {
299513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III            return mDensity;
300513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III        }
301513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III
302513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III        @Override
303513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III        public ImageDecoder createImageDecoder() throws IOException {
304513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III            synchronized (this) {
305513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III                if (mAssetInputStream == null) {
306513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III                    throw new IOException("Cannot reuse AssetInputStreamSource");
307513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III                }
308513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III                AssetInputStream ais = mAssetInputStream;
309513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III                mAssetInputStream = null;
3101d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III                return createFromAsset(ais, this);
311513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III            }
312513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III        }
313513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III    }
314513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III
315ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    private static class ResourceSource extends Source {
316e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        ResourceSource(@NonNull Resources res, int resId) {
3170c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            mResources = res;
3180c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            mResId = resId;
31966c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            mResDensity = Bitmap.DENSITY_NONE;
3200c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        }
3210c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
3220c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        final Resources mResources;
3230c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        final int       mResId;
32466c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        int             mResDensity;
3250c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
3260c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        @Override
3270c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        public Resources getResources() { return mResources; }
3280c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
3290c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        @Override
33066c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        public int getDensity() { return mResDensity; }
33166c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger
33266c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        @Override
333ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        public ImageDecoder createImageDecoder() throws IOException {
33466c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            TypedValue value = new TypedValue();
335121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III            // This is just used in order to access the underlying Asset and
336121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III            // keep it alive.
337121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III            InputStream is = mResources.openRawResource(mResId, value);
33866c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger
339121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III            if (value.density == TypedValue.DENSITY_DEFAULT) {
340121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III                mResDensity = DisplayMetrics.DENSITY_DEFAULT;
341121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III            } else if (value.density != TypedValue.DENSITY_NONE) {
342121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III                mResDensity = value.density;
343121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III            }
34466c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger
3451d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            return createFromAsset((AssetInputStream) is, this);
346121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III        }
347121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III    }
348121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III
349121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III    /**
350121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III     *  ImageDecoder will own the AssetInputStream.
351121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III     */
3521d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III    private static ImageDecoder createFromAsset(AssetInputStream ais,
3531d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            Source source) throws IOException {
354121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III        ImageDecoder decoder = null;
355121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III        try {
356121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III            long asset = ais.getNativeAsset();
3571d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            decoder = nCreate(asset, source);
358121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III        } finally {
359121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III            if (decoder == null) {
360121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III                IoUtils.closeQuietly(ais);
361121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III            } else {
362121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III                decoder.mInputStream = ais;
363121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III                decoder.mOwnsInputStream = true;
3640c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            }
365121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III        }
366121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III        return decoder;
367121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III    }
368121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III
369121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III    private static class AssetSource extends Source {
370121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III        AssetSource(@NonNull AssetManager assets, @NonNull String fileName) {
371121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III            mAssets = assets;
372121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III            mFileName = fileName;
373121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III        }
374121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III
375121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III        private final AssetManager mAssets;
376121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III        private final String mFileName;
377121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III
378121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III        @Override
379121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III        public ImageDecoder createImageDecoder() throws IOException {
380121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III            InputStream is = mAssets.open(mFileName);
3811d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            return createFromAsset((AssetInputStream) is, this);
3820c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        }
3830c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
3840c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
385e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    private static class FileSource extends Source {
386e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        FileSource(@NonNull File file) {
387e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III            mFile = file;
388e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        }
389e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III
390e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        private final File mFile;
391e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III
392e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        @Override
393e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        public ImageDecoder createImageDecoder() throws IOException {
3941d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            return createFromFile(mFile, this);
395e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        }
396e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    }
397e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III
3980c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
3990c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  Contains information about the encoded image.
4000c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
4010c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    public static class ImageInfo {
402e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        private final Size mSize;
403e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        private ImageDecoder mDecoder;
404e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III
405e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        private ImageInfo(@NonNull ImageDecoder decoder) {
406e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III            mSize = new Size(decoder.mWidth, decoder.mHeight);
407e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III            mDecoder = decoder;
408e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        }
4091fad09d4d3f43112abd842da4c94cf00fb1cb46dLeon Scroggins III
4101fad09d4d3f43112abd842da4c94cf00fb1cb46dLeon Scroggins III        /**
411e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III         * Size of the image, without scaling or cropping.
4121fad09d4d3f43112abd842da4c94cf00fb1cb46dLeon Scroggins III         */
413e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        @NonNull
414e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        public Size getSize() {
415e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III            return mSize;
4161fad09d4d3f43112abd842da4c94cf00fb1cb46dLeon Scroggins III        }
4171fad09d4d3f43112abd842da4c94cf00fb1cb46dLeon Scroggins III
4181fad09d4d3f43112abd842da4c94cf00fb1cb46dLeon Scroggins III        /**
419e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III         * The mimeType of the image.
4201fad09d4d3f43112abd842da4c94cf00fb1cb46dLeon Scroggins III         */
421e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        @NonNull
4221fad09d4d3f43112abd842da4c94cf00fb1cb46dLeon Scroggins III        public String getMimeType() {
423e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III            return mDecoder.getMimeType();
4240c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        }
425127d31a6842b6cca49885c3607e7ea35b1885b6fLeon Scroggins III
426127d31a6842b6cca49885c3607e7ea35b1885b6fLeon Scroggins III        /**
427127d31a6842b6cca49885c3607e7ea35b1885b6fLeon Scroggins III         * Whether the image is animated.
428127d31a6842b6cca49885c3607e7ea35b1885b6fLeon Scroggins III         *
429127d31a6842b6cca49885c3607e7ea35b1885b6fLeon Scroggins III         * <p>Calling {@link #decodeDrawable} will return an
430127d31a6842b6cca49885c3607e7ea35b1885b6fLeon Scroggins III         * {@link AnimatedImageDrawable}.</p>
431127d31a6842b6cca49885c3607e7ea35b1885b6fLeon Scroggins III         */
432127d31a6842b6cca49885c3607e7ea35b1885b6fLeon Scroggins III        public boolean isAnimated() {
433127d31a6842b6cca49885c3607e7ea35b1885b6fLeon Scroggins III            return mDecoder.mAnimated;
434127d31a6842b6cca49885c3607e7ea35b1885b6fLeon Scroggins III        }
4351a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III
4361a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III        /**
4371a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III         * If known, the color space the decoded bitmap will have. Note that the
4381a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III         * output color space is not guaranteed to be the color space the bitmap
4391a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III         * is encoded with. If not known (when the config is
4401a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III         * {@link Bitmap.Config#ALPHA_8} for instance), or there is an error,
4411a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III         * it is set to null.
4421a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III         */
4431a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III        @Nullable
4441a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III        public ColorSpace getColorSpace() {
4451a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III            return mDecoder.getColorSpace();
4461a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III        }
4470c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    };
4480c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
4491d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III    /** @removed
4501d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III     * @deprecated Subsumed by {@link #DecodeException}.
4510c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
4521d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III    @java.lang.Deprecated
453ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    public static class IncompleteException extends IOException {};
4540c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
4550c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
4560c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  Optional listener supplied to {@link #decodeDrawable} or
4570c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  {@link #decodeBitmap}.
4580c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
4590c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    public static interface OnHeaderDecodedListener {
4600c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        /**
4610c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III         *  Called when the header is decoded and the size is known.
4620c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III         *
4630c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III         *  @param decoder allows changing the default settings of the decode.
464e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III         *  @param info Information about the encoded image.
465e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III         *  @param source that created the decoder.
4660c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III         */
467e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        public void onHeaderDecoded(@NonNull ImageDecoder decoder,
468e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III                @NonNull ImageInfo info, @NonNull Source source);
4690c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
4700c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    };
4710c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
472cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III    /** @removed
473cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III     * @deprecated Replaced by {@link #DecodeException#SOURCE_EXCEPTION}.
474e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     */
475cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III    @java.lang.Deprecated
476e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    public static final int ERROR_SOURCE_EXCEPTION  = 1;
477e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III
478cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III    /** @removed
479cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III     * @deprecated Replaced by {@link #DecodeException#SOURCE_INCOMPLETE}.
480e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     */
481cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III    @java.lang.Deprecated
482e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    public static final int ERROR_SOURCE_INCOMPLETE = 2;
483e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III
484cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III    /** @removed
485cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III     * @deprecated Replaced by {@link #DecodeException#SOURCE_MALFORMED_DATA}.
486e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     */
487cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III    @java.lang.Deprecated
488e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    public static final int ERROR_SOURCE_ERROR      = 3;
489e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III
490e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    /**
4911d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III     *  Information about an interrupted decode.
4921d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III     */
4931d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III    public static final class DecodeException extends IOException {
494cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III        /**
495cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III         *  An Exception was thrown reading the {@link Source}.
496cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III         */
497cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III        public static final int SOURCE_EXCEPTION  = 1;
498cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III
499cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III        /**
500cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III         *  The encoded data was incomplete.
501cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III         */
502cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III        public static final int SOURCE_INCOMPLETE = 2;
503cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III
504cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III        /**
505cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III         *  The encoded data contained an error.
506cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III         */
507cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III        public static final int SOURCE_MALFORMED_DATA      = 3;
508cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III
509cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III        /** @hide **/
510cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III        @Retention(SOURCE)
511cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III        @IntDef(value = { SOURCE_EXCEPTION, SOURCE_INCOMPLETE, SOURCE_MALFORMED_DATA },
512cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III                prefix = {"SOURCE_"})
513cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III        public @interface Error {};
514cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III
5151d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        @Error final int mError;
5161d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        @NonNull final Source mSource;
5171d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III
5181d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        DecodeException(@Error int error, @Nullable Throwable cause, @NonNull Source source) {
5191d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            super(errorMessage(error, cause), cause);
5201d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            mError = error;
5211d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            mSource = source;
5221d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        }
5231d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III
5241d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        /**
5251d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III         * Private method called by JNI.
5261d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III         */
5271d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        @SuppressWarnings("unused")
5281d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        DecodeException(@Error int error, @Nullable String msg, @Nullable Throwable cause,
5291d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III                @NonNull Source source) {
5301d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            super(msg + errorMessage(error, cause), cause);
5311d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            mError = error;
5321d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            mSource = source;
5331d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        }
5341d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III
5351d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        /**
5361d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III         *  Retrieve the reason that decoding was interrupted.
5371d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III         *
538cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III         *  <p>If the error is {@link #SOURCE_EXCEPTION}, the underlying
5391d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III         *  {@link java.lang.Throwable} can be retrieved with
5401d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III         *  {@link java.lang.Throwable#getCause}.</p>
5411d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III         */
5421d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        @Error
5431d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        public int getError() {
5441d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            return mError;
5451d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        }
5461d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III
5471d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        /**
5481d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III         *  Retrieve the {@link Source} that was interrupted.
5491d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III         */
5501d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        @NonNull
5511d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        public Source getSource() {
5521d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            return mSource;
5531d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        }
5541d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III
5551d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        private static String errorMessage(@Error int error, @Nullable Throwable cause) {
5561d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            switch (error) {
557cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III                case SOURCE_EXCEPTION:
5581d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III                    return "Exception in input: " + cause;
559cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III                case SOURCE_INCOMPLETE:
5601d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III                    return "Input was incomplete.";
561cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III                case SOURCE_MALFORMED_DATA:
5621d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III                    return "Input contained an error.";
5631d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III                default:
5641d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III                    return "";
5651d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            }
5661d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        }
5671d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III    }
5681d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III
5691d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III    /**
5700c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  Optional listener supplied to the ImageDecoder.
571e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *
572e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  Without this listener, errors will throw {@link java.io.IOException}.
5730c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
574edf26d6e40f0723e70d7dcd147a2a2ce07c7c1ccLeon Scroggins III    public static interface OnPartialImageListener {
5750c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        /**
576edf26d6e40f0723e70d7dcd147a2a2ce07c7c1ccLeon Scroggins III         *  Called when there is only a partial image to display.
5770c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III         *
578e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III         *  If decoding is interrupted after having decoded a partial image,
579e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III         *  this listener lets the client know that and allows them to
580e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III         *  optionally finish the rest of the decode/creation process to create
581e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III         *  a partial {@link Drawable}/{@link Bitmap}.
582edf26d6e40f0723e70d7dcd147a2a2ce07c7c1ccLeon Scroggins III         *
5831d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III         *  @param e containing information about the decode interruption.
584e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III         *  @return True to create and return a {@link Drawable}/{@link Bitmap}
585e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III         *      with partial data. False (which is the default) to abort the
5861d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III         *      decode and throw {@code e}.
5870c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III         */
5881d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        boolean onPartialImage(@NonNull DecodeException e);
5890c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    };
5900c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
5910c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    // Fields
592671cce2605ed50c9aba73ab5bd530cb7741c53cdLeon Scroggins III    private long          mNativePtr;
593671cce2605ed50c9aba73ab5bd530cb7741c53cdLeon Scroggins III    private final int     mWidth;
594671cce2605ed50c9aba73ab5bd530cb7741c53cdLeon Scroggins III    private final int     mHeight;
595671cce2605ed50c9aba73ab5bd530cb7741c53cdLeon Scroggins III    private final boolean mAnimated;
5960c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
5971a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III    private int        mDesiredWidth;
5981a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III    private int        mDesiredHeight;
5991a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III    private int        mAllocator = ALLOCATOR_DEFAULT;
6001a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III    private boolean    mRequireUnpremultiplied = false;
6011a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III    private boolean    mMutable = false;
6021a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III    private boolean    mConserveMemory = false;
6031a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III    private boolean    mDecodeAsAlphaMask = false;
6041a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III    private ColorSpace mDesiredColorSpace = null;
6051a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III    private Rect       mCropRect;
6061a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III    private Rect       mOutPaddingRect;
6071a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III    private Source     mSource;
6080c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
609e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    private PostProcessor          mPostProcessor;
610edf26d6e40f0723e70d7dcd147a2a2ce07c7c1ccLeon Scroggins III    private OnPartialImageListener mOnPartialImageListener;
6110c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
612ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    // Objects for interacting with the input.
613ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    private InputStream         mInputStream;
6140b49f5725cabd64d27960b1b017e5c009f701cf8Leon Scroggins III    private boolean             mOwnsInputStream;
615ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    private byte[]              mTempStorage;
616ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    private AssetFileDescriptor mAssetFd;
617ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    private final AtomicBoolean mClosed = new AtomicBoolean();
618ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    private final CloseGuard    mCloseGuard = CloseGuard.get();
6190c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
6200c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
621ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III     * Private constructor called by JNI. {@link #close} must be
6220c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     * called after decoding to delete native resources.
6230c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
6240c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    @SuppressWarnings("unused")
625671cce2605ed50c9aba73ab5bd530cb7741c53cdLeon Scroggins III    private ImageDecoder(long nativePtr, int width, int height,
626671cce2605ed50c9aba73ab5bd530cb7741c53cdLeon Scroggins III            boolean animated) {
6270c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        mNativePtr = nativePtr;
6280c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        mWidth = width;
6290c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        mHeight = height;
6300c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        mDesiredWidth = width;
6310c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        mDesiredHeight = height;
632671cce2605ed50c9aba73ab5bd530cb7741c53cdLeon Scroggins III        mAnimated = animated;
633ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        mCloseGuard.open("close");
634ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    }
635ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III
636ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    @Override
637ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    protected void finalize() throws Throwable {
638ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        try {
639ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            if (mCloseGuard != null) {
640ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                mCloseGuard.warnIfOpen();
641ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            }
642ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III
643127d31a6842b6cca49885c3607e7ea35b1885b6fLeon Scroggins III            // Avoid closing these in finalizer.
644127d31a6842b6cca49885c3607e7ea35b1885b6fLeon Scroggins III            mInputStream = null;
645127d31a6842b6cca49885c3607e7ea35b1885b6fLeon Scroggins III            mAssetFd = null;
646127d31a6842b6cca49885c3607e7ea35b1885b6fLeon Scroggins III
647ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            close();
648ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        } finally {
649ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            super.finalize();
650ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        }
6510c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
6520c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
6530c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
6541eccac89c13a79671e04cfce359a9506b284d5feLeon Scroggins III     * Create a new {@link Source} from a resource.
6550c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
6560c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     * @param res the {@link Resources} object containing the image data.
6570c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     * @param resId resource ID of the image data.
6580c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     * @return a new Source object, which can be passed to
6590c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *      {@link #decodeDrawable} or {@link #decodeBitmap}.
6600c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
661ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    @NonNull
6621eccac89c13a79671e04cfce359a9506b284d5feLeon Scroggins III    public static Source createSource(@NonNull Resources res, int resId)
663ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    {
6640c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        return new ResourceSource(res, resId);
6650c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
6660c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
6670c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
668ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III     * Create a new {@link Source} from a {@link android.net.Uri}.
669ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III     *
670ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III     * @param cr to retrieve from.
671ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III     * @param uri of the image file.
672ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III     * @return a new Source object, which can be passed to
673ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III     *      {@link #decodeDrawable} or {@link #decodeBitmap}.
674ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III     */
675ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    @NonNull
676ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    public static Source createSource(@NonNull ContentResolver cr,
677ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            @NonNull Uri uri) {
678046a99ebbb90f9ecdead7b057ef99764a1d295b9Leon Scroggins III        return new ContentResolverSource(cr, uri, null);
679046a99ebbb90f9ecdead7b057ef99764a1d295b9Leon Scroggins III    }
680046a99ebbb90f9ecdead7b057ef99764a1d295b9Leon Scroggins III
681046a99ebbb90f9ecdead7b057ef99764a1d295b9Leon Scroggins III    /**
682046a99ebbb90f9ecdead7b057ef99764a1d295b9Leon Scroggins III     * Provide Resources for density scaling.
683046a99ebbb90f9ecdead7b057ef99764a1d295b9Leon Scroggins III     *
684046a99ebbb90f9ecdead7b057ef99764a1d295b9Leon Scroggins III     * @hide
685046a99ebbb90f9ecdead7b057ef99764a1d295b9Leon Scroggins III     */
686046a99ebbb90f9ecdead7b057ef99764a1d295b9Leon Scroggins III    @NonNull
687046a99ebbb90f9ecdead7b057ef99764a1d295b9Leon Scroggins III    public static Source createSource(@NonNull ContentResolver cr,
688046a99ebbb90f9ecdead7b057ef99764a1d295b9Leon Scroggins III            @NonNull Uri uri, @Nullable Resources res) {
689046a99ebbb90f9ecdead7b057ef99764a1d295b9Leon Scroggins III        return new ContentResolverSource(cr, uri, res);
690ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    }
691ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III
692ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    /**
693121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III     * Create a new {@link Source} from a file in the "assets" directory.
694121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III     */
695121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III    @NonNull
696121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III    public static Source createSource(@NonNull AssetManager assets, @NonNull String fileName) {
697121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III        return new AssetSource(assets, fileName);
698121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III    }
699121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III
700121ef98bfb0e34a2726dd0fb9112915017bfcde4Leon Scroggins III    /**
7010c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     * Create a new {@link Source} from a byte array.
702e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *
7030c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     * @param data byte array of compressed image data.
7040c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     * @param offset offset into data for where the decoder should begin
7050c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *      parsing.
7060c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     * @param length number of bytes, beginning at offset, to parse.
7070c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     * @throws NullPointerException if data is null.
7080c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     * @throws ArrayIndexOutOfBoundsException if offset and length are
7090c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *      not within data.
710e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     * @hide
7110c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
712e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    @NonNull
7130c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    public static Source createSource(@NonNull byte[] data, int offset,
7140c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            int length) throws ArrayIndexOutOfBoundsException {
7150c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        if (data == null) {
7160c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            throw new NullPointerException("null byte[] in createSource!");
7170c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        }
7180c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        if (offset < 0 || length < 0 || offset >= data.length ||
7190c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III                offset + length > data.length) {
7200c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            throw new ArrayIndexOutOfBoundsException(
7210c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III                    "invalid offset/length!");
7220c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        }
7230c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        return new ByteArraySource(data, offset, length);
7240c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
7250c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
7260c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
727b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III     * See {@link #createSource(byte[], int, int).
728e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     * @hide
729b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III     */
730e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    @NonNull
731b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III    public static Source createSource(@NonNull byte[] data) {
732b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III        return createSource(data, 0, data.length);
733b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III    }
734b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III
735b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III    /**
7360c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     * Create a new {@link Source} from a {@link java.nio.ByteBuffer}.
7370c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
7384367534058a07fd79ef1bbfec4e27f34275ab5c7Leon Scroggins III     * <p>Decoding will start from {@link java.nio.ByteBuffer#position()}. The
7394367534058a07fd79ef1bbfec4e27f34275ab5c7Leon Scroggins III     * position of {@code buffer} will not be affected.</p>
7400c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
7414367534058a07fd79ef1bbfec4e27f34275ab5c7Leon Scroggins III     * <p>Note: If this {@code Source} is passed to {@link #decodeDrawable}, and
7424367534058a07fd79ef1bbfec4e27f34275ab5c7Leon Scroggins III     * the encoded image is animated, the returned {@link AnimatedImageDrawable}
7434367534058a07fd79ef1bbfec4e27f34275ab5c7Leon Scroggins III     * will continue reading from the {@code buffer}, so its contents must not
7444367534058a07fd79ef1bbfec4e27f34275ab5c7Leon Scroggins III     * be modified, even after the {@code AnimatedImageDrawable} is returned.
7454367534058a07fd79ef1bbfec4e27f34275ab5c7Leon Scroggins III     * {@code buffer}'s contents should never be modified during decode.</p>
7460c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
747e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    @NonNull
748e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    public static Source createSource(@NonNull ByteBuffer buffer) {
7494367534058a07fd79ef1bbfec4e27f34275ab5c7Leon Scroggins III        return new ByteBufferSource(buffer.slice());
7500c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
7510c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
7520c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
75366c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger     * Internal API used to generate bitmaps for use by Drawables (i.e. BitmapDrawable)
75466c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger     * @hide
75566c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger     */
75666c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger    public static Source createSource(Resources res, InputStream is) {
75766c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        return new InputStreamSource(res, is, Bitmap.getDefaultDensity());
75866c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger    }
75966c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger
76066c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger    /**
76166c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger     * Internal API used to generate bitmaps for use by Drawables (i.e. BitmapDrawable)
76266c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger     * @hide
76366c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger     */
7641d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III    @TestApi
76566c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger    public static Source createSource(Resources res, InputStream is, int density) {
76666c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        return new InputStreamSource(res, is, density);
76766c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger    }
76866c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger
76966c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger    /**
770e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     * Create a new {@link Source} from a {@link java.io.File}.
771e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     */
772e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    @NonNull
773e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    public static Source createSource(@NonNull File file) {
774e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        return new FileSource(file);
775e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    }
776e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III
777e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    /**
7780c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  Return the width and height of a given sample size.
7790c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
780e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  <p>This takes an input that functions like
7810c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  {@link BitmapFactory.Options#inSampleSize}. It returns a width and
78264481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *  height that can be achieved by sampling the encoded image. Other widths
7830c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  and heights may be supported, but will require an additional (internal)
7840c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  scaling step. Such internal scaling is *not* supported with
785e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  {@link #setRequireUnpremultiplied} set to {@code true}.</p>
7860c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
7870c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  @param sampleSize Sampling rate of the encoded image.
788e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  @return {@link android.util.Size} of the width and height after
789e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *      sampling.
79064481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *
79164481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *  @hide
7920c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
793e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    @NonNull
794e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    public Size getSampledSize(int sampleSize) {
7950c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        if (sampleSize <= 0) {
7960c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            throw new IllegalArgumentException("sampleSize must be positive! "
7970c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III                    + "provided " + sampleSize);
7980c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        }
7990c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        if (mNativePtr == 0) {
800ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            throw new IllegalStateException("ImageDecoder is closed!");
8010c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        }
8020c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
8030c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        return nGetSampledSize(mNativePtr, sampleSize);
8040c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
8050c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
8060c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    // Modifiers
80764481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III    /** @removed
80864481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     * @deprecated Renamed to {@link #setTargetSize}.
80964481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     */
81064481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III    @java.lang.Deprecated
81164481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III    public ImageDecoder setResize(int width, int height) {
81264481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III        return this.setTargetSize(width, height);
81364481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III    }
81464481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III
8150c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
81664481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *  Specify the size of the output {@link Drawable} or {@link Bitmap}.
81764481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *
81864481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *  <p>By default, the output size will match the size of the encoded
81964481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *  image, which can be retrieved from the {@link ImageInfo} in
82064481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
82164481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *
8221a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     *  <p>Only the last call to this or {@link #setTargetSampleSize} is
8231a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     *  respected.</p>
8240c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
8250c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  @param width must be greater than 0.
8260c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  @param height must be greater than 0.
8275f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *  @return this object for chaining.
8280c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
82964481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III    public ImageDecoder setTargetSize(int width, int height) {
8300c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        if (width <= 0 || height <= 0) {
8310c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            throw new IllegalArgumentException("Dimensions must be positive! "
8320c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III                    + "provided (" + width + ", " + height + ")");
8330c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        }
8340c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
8350c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        mDesiredWidth = width;
8360c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        mDesiredHeight = height;
8375f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III        return this;
8380c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
8390c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
84064481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III    /** @removed
8411a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     * @deprecated Renamed to {@link #setTargetSampleSize}.
84264481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     */
84364481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III    @java.lang.Deprecated
84464481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III    public ImageDecoder setResize(int sampleSize) {
8451a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III        return this.setTargetSampleSize(sampleSize);
84664481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III    }
84764481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III
84864481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III    private int getTargetDimension(int original, int sampleSize, int computed) {
84964481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III        // Sampling will never result in a smaller size than 1.
85064481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III        if (sampleSize >= original) {
85164481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III            return 1;
85264481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III        }
85364481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III
85464481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III        // Use integer divide to find the desired size. If that is what
85564481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III        // getSampledSize computed, that is the size to use.
85664481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III        int target = original / sampleSize;
85764481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III        if (computed == target) {
85864481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III            return computed;
85964481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III        }
86064481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III
86164481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III        // If sampleSize does not divide evenly into original, the decoder
86264481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III        // may round in either direction. It just needs to get a result that
86364481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III        // is close.
86464481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III        int reverse = computed * sampleSize;
86564481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III        if (Math.abs(reverse - original) < sampleSize) {
86664481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III            // This is the size that can be decoded most efficiently.
86764481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III            return computed;
86864481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III        }
86964481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III
87064481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III        // The decoder could not get close (e.g. it is a DNG image).
87164481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III        return target;
87264481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III    }
87364481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III
8740c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
87564481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *  Set the target size with a sampleSize.
87664481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *
87764481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *  <p>By default, the output size will match the size of the encoded
87864481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *  image, which can be retrieved from the {@link ImageInfo} in
87964481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
8800c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
88164481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *  <p>Requests the decoder to subsample the original image, returning a
88264481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *  smaller image to save memory. The sample size is the number of pixels
88364481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *  in either dimension that correspond to a single pixel in the output.
88464481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *  For example, sampleSize == 4 returns an image that is 1/4 the
88564481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *  width/height of the original, and 1/16 the number of pixels.</p>
88664481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *
88764481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *  <p>Must be greater than or equal to 1.</p>
88864481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *
88964481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *  <p>Only the last call to this or {@link #setTargetSize} is respected.</p>
8900c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
8910c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  @param sampleSize Sampling rate of the encoded image.
8925f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *  @return this object for chaining.
8930c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
8941a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III    public ImageDecoder setTargetSampleSize(int sampleSize) {
895e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        Size size = this.getSampledSize(sampleSize);
89664481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III        int targetWidth = getTargetDimension(mWidth, sampleSize, size.getWidth());
89764481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III        int targetHeight = getTargetDimension(mHeight, sampleSize, size.getHeight());
89864481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III        return this.setTargetSize(targetWidth, targetHeight);
8990c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
9000c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
90166c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger    private boolean requestedResize() {
90266c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        return mWidth != mDesiredWidth || mHeight != mDesiredHeight;
90366c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger    }
90466c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger
9050c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    // These need to stay in sync with ImageDecoder.cpp's Allocator enum.
9060c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
9070c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  Use the default allocation for the pixel memory.
9080c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
9090c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  Will typically result in a {@link Bitmap.Config#HARDWARE}
9100c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  allocation, but may be software for small images. In addition, this will
9110c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  switch to software when HARDWARE is incompatible, e.g.
912746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     *  {@link #setMutable}, {@link #setDecodeAsAlphaMask}.
9130c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
914e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    public static final int ALLOCATOR_DEFAULT = 0;
9150c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
9160c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
9170c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  Use a software allocation for the pixel memory.
9180c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
9190c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  Useful for drawing to a software {@link Canvas} or for
9200c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  accessing the pixels on the final output.
9210c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
922e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    public static final int ALLOCATOR_SOFTWARE = 1;
9230c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
9240c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
9250c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  Use shared memory for the pixel memory.
9260c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
9270c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  Useful for sharing across processes.
9280c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
929e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    public static final int ALLOCATOR_SHARED_MEMORY = 2;
9300c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
9310c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
9320c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  Require a {@link Bitmap.Config#HARDWARE} {@link Bitmap}.
9330c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
934e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  When this is combined with incompatible options, like
935746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     *  {@link #setMutable} or {@link #setDecodeAsAlphaMask}, {@link #decodeDrawable}
936e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  / {@link #decodeBitmap} will throw an
937e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  {@link java.lang.IllegalStateException}.
9380c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
939e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    public static final int ALLOCATOR_HARDWARE = 3;
9400c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
9410c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /** @hide **/
9420c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    @Retention(SOURCE)
94362f0800ef4f41f97ddb18b755a63c01fea67b9faLeon Scroggins III    @IntDef(value = { ALLOCATOR_DEFAULT, ALLOCATOR_SOFTWARE,
94462f0800ef4f41f97ddb18b755a63c01fea67b9faLeon Scroggins III              ALLOCATOR_SHARED_MEMORY, ALLOCATOR_HARDWARE },
94562f0800ef4f41f97ddb18b755a63c01fea67b9faLeon Scroggins III              prefix = {"ALLOCATOR_"})
9460c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    public @interface Allocator {};
9470c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
9480c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
9490c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  Choose the backing for the pixel memory.
9500c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
9510c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  This is ignored for animated drawables.
9520c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
9530c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  @param allocator Type of allocator to use.
9545f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *  @return this object for chaining.
9550c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
9565f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III    public ImageDecoder setAllocator(@Allocator int allocator) {
957e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        if (allocator < ALLOCATOR_DEFAULT || allocator > ALLOCATOR_HARDWARE) {
9580c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            throw new IllegalArgumentException("invalid allocator " + allocator);
9590c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        }
9600c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        mAllocator = allocator;
9615f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III        return this;
9620c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
9630c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
9640c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
965746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     *  Return the allocator for the pixel memory.
966746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     */
967746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    @Allocator
968746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    public int getAllocator() {
969746a9fee937969af9be7e060335e26e098971615Leon Scroggins III        return mAllocator;
970746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    }
971746a9fee937969af9be7e060335e26e098971615Leon Scroggins III
972746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    /**
973e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  Specify whether the {@link Bitmap} should have unpremultiplied pixels.
9740c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
9755f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *  <p>By default, ImageDecoder will create a {@link Bitmap} with
9760c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  premultiplied pixels, which is required for drawing with the
9770c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  {@link android.view.View} system (i.e. to a {@link Canvas}). Calling
978e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  this method with a value of {@code true} will result in
979e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  {@link #decodeBitmap} returning a {@link Bitmap} with unpremultiplied
980e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  pixels. See {@link Bitmap#isPremultiplied}. This is incompatible with
9810c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  {@link #decodeDrawable}; attempting to decode an unpremultiplied
9820c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  {@link Drawable} will throw an {@link java.lang.IllegalStateException}.
9835f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *  </p>
9845f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *
9855f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *  @return this object for chaining.
9860c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
9875f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III    public ImageDecoder setRequireUnpremultiplied(boolean requireUnpremultiplied) {
988e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        mRequireUnpremultiplied = requireUnpremultiplied;
9895f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III        return this;
9900c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
9910c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
9920c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
993746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     *  Return whether the {@link Bitmap} will have unpremultiplied pixels.
994746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     */
995746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    public boolean getRequireUnpremultiplied() {
996746a9fee937969af9be7e060335e26e098971615Leon Scroggins III        return mRequireUnpremultiplied;
997746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    }
998746a9fee937969af9be7e060335e26e098971615Leon Scroggins III
999746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    /**
10000c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  Modify the image after decoding and scaling.
10010c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
1002e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  <p>This allows adding effects prior to returning a {@link Drawable} or
10030c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  {@link Bitmap}. For a {@code Drawable} or an immutable {@code Bitmap},
1004e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  this is the only way to process the image after decoding.</p>
10050c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
1006e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  <p>If set on a nine-patch image, the nine-patch data is ignored.</p>
10070c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
1008e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  <p>For an animated image, the drawing commands drawn on the
1009e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  {@link Canvas} will be recorded immediately and then applied to each
1010e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  frame.</p>
10115f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *
10125f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *  @return this object for chaining.
10130c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
10145f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III    public ImageDecoder setPostProcessor(@Nullable PostProcessor p) {
1015e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        mPostProcessor = p;
10165f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III        return this;
10170c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
10180c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
10190c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
1020746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     *  Return the {@link PostProcessor} currently set.
1021746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     */
1022746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    @Nullable
1023746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    public PostProcessor getPostProcessor() {
1024746a9fee937969af9be7e060335e26e098971615Leon Scroggins III        return mPostProcessor;
1025746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    }
1026746a9fee937969af9be7e060335e26e098971615Leon Scroggins III
1027746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    /**
1028edf26d6e40f0723e70d7dcd147a2a2ce07c7c1ccLeon Scroggins III     *  Set (replace) the {@link OnPartialImageListener} on this object.
10290c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
10305f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *  <p>Will be called if there is an error in the input. Without one, an
10315f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *  error will result in an Exception being thrown.</p>
10325f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *
10335f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *  @return this object for chaining.
10340c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
10355f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III    public ImageDecoder setOnPartialImageListener(@Nullable OnPartialImageListener l) {
1036edf26d6e40f0723e70d7dcd147a2a2ce07c7c1ccLeon Scroggins III        mOnPartialImageListener = l;
10375f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III        return this;
10380c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
10390c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
10400c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
1041746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     *  Return the {@link OnPartialImageListener} currently set.
1042746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     */
1043746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    @Nullable
1044746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    public OnPartialImageListener getOnPartialImageListener() {
1045746a9fee937969af9be7e060335e26e098971615Leon Scroggins III        return mOnPartialImageListener;
1046746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    }
1047746a9fee937969af9be7e060335e26e098971615Leon Scroggins III
1048746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    /**
10490c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  Crop the output to {@code subset} of the (possibly) scaled image.
10500c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
1051e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  <p>{@code subset} must be contained within the size set by
105264481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *  {@link #setTargetSize} or the bounds of the image if setTargetSize was
105364481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III     *  not called. Otherwise an {@link IllegalStateException} will be thrown by
1054e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  {@link #decodeDrawable}/{@link #decodeBitmap}.</p>
10550c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
1056e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  <p>NOT intended as a replacement for
10570c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *  {@link BitmapRegionDecoder#decodeRegion}. This supports all formats,
1058e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  but merely crops the output.</p>
10595f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *
10605f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *  @return this object for chaining.
10610c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
10625f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III    public ImageDecoder setCrop(@Nullable Rect subset) {
10630c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        mCropRect = subset;
10645f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III        return this;
10650c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
10660c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
10670c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
1068746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     *  Return the cropping rectangle, if set.
1069746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     */
1070746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    @Nullable
1071746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    public Rect getCrop() {
1072746a9fee937969af9be7e060335e26e098971615Leon Scroggins III        return mCropRect;
1073746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    }
1074746a9fee937969af9be7e060335e26e098971615Leon Scroggins III
1075746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    /**
10762f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III     *  Set a Rect for retrieving nine patch padding.
10772f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III     *
10782f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III     *  If the image is a nine patch, this Rect will be set to the padding
10792f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III     *  rectangle during decode. Otherwise it will not be modified.
10802f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III     *
10815f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *  @return this object for chaining.
10825f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *
10832f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III     *  @hide
10842f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III     */
10855f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III    public ImageDecoder setOutPaddingRect(@NonNull Rect outPadding) {
10862f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III        mOutPaddingRect = outPadding;
10875f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III        return this;
10882f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III    }
10892f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III
10902f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III    /**
1091e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  Specify whether the {@link Bitmap} should be mutable.
10920c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
1093e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  <p>By default, a {@link Bitmap} created will be immutable, but that can
1094e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  be changed with this call.</p>
10950c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
1096e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  <p>Mutable Bitmaps are incompatible with {@link #ALLOCATOR_HARDWARE},
1097e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  because {@link Bitmap.Config#HARDWARE} Bitmaps cannot be mutable.
1098e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  Attempting to combine them will throw an
1099e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  {@link java.lang.IllegalStateException}.</p>
11000c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
1101e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  <p>Mutable Bitmaps are also incompatible with {@link #decodeDrawable},
1102e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  which would require retrieving the Bitmap from the returned Drawable in
1103e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  order to modify. Attempting to decode a mutable {@link Drawable} will
1104e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  throw an {@link java.lang.IllegalStateException}.</p>
11055f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *
11065f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *  @return this object for chaining.
11070c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
11085f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III    public ImageDecoder setMutable(boolean mutable) {
1109e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        mMutable = mutable;
11105f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III        return this;
11110c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
11120c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
11130c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
1114746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     *  Return whether the {@link Bitmap} will be mutable.
1115746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     */
1116746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    public boolean getMutable() {
1117746a9fee937969af9be7e060335e26e098971615Leon Scroggins III        return mMutable;
1118746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    }
1119746a9fee937969af9be7e060335e26e098971615Leon Scroggins III
1120746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    /**
1121e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  Specify whether to potentially save RAM at the expense of quality.
11220c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
11235f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *  <p>Setting this to {@code true} may result in a {@link Bitmap} with a
1124a38b2135a4bf4368734567a73d2e56f1c318fee9Leon Scroggins III     *  denser {@link Bitmap.Config}, depending on the image. For example, an
1125a38b2135a4bf4368734567a73d2e56f1c318fee9Leon Scroggins III     *  opaque {@link Bitmap} with 8 bits or precision for each of its red,
1126a38b2135a4bf4368734567a73d2e56f1c318fee9Leon Scroggins III     *  green and blue components would decode to
1127a38b2135a4bf4368734567a73d2e56f1c318fee9Leon Scroggins III     *  {@link Bitmap.Config#ARGB_8888} by default, but setting this to
1128a38b2135a4bf4368734567a73d2e56f1c318fee9Leon Scroggins III     *  {@code true} will result in decoding to {@link Bitmap.Config#RGB_565}.
1129a38b2135a4bf4368734567a73d2e56f1c318fee9Leon Scroggins III     *  This necessarily lowers the quality of the output, but saves half
11305f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *  the memory used.</p>
11315f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *
11325f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *  @return this object for chaining.
11330c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
11345f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III    public ImageDecoder setConserveMemory(boolean conserveMemory) {
1135a38b2135a4bf4368734567a73d2e56f1c318fee9Leon Scroggins III        mConserveMemory = conserveMemory;
11365f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III        return this;
11370c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
11380c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
11390c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
1140746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     *  Return whether this object will try to save RAM at the expense of quality.
1141746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     *
1142746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     *  <p>This returns whether {@link #setConserveMemory} was set to {@code true}.
1143746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     *  It may still return {@code true} even if the {@code ImageDecoder} does not
1144746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     *  have a way to save RAM at the expense of quality for this image.</p>
1145746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     */
1146746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    public boolean getConserveMemory() {
1147746a9fee937969af9be7e060335e26e098971615Leon Scroggins III        return mConserveMemory;
1148746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    }
1149746a9fee937969af9be7e060335e26e098971615Leon Scroggins III
1150746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    /**
1151e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  Specify whether to potentially treat the output as an alpha mask.
11520c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
1153e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  <p>If this is set to {@code true} and the image is encoded in a format
1154e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  with only one channel, treat that channel as alpha. Otherwise this call has
1155e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  no effect.</p>
11560c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     *
1157746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     *  <p>setDecodeAsAlphaMask is incompatible with {@link #ALLOCATOR_HARDWARE}. Trying to
1158e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  combine them will result in {@link #decodeDrawable}/
1159e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  {@link #decodeBitmap} throwing an
1160e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     *  {@link java.lang.IllegalStateException}.</p>
11615f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *
11625f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III     *  @return this object for chaining.
11630c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
1164746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    public ImageDecoder setDecodeAsAlphaMask(boolean decodeAsAlphaMask) {
1165746a9fee937969af9be7e060335e26e098971615Leon Scroggins III        mDecodeAsAlphaMask = decodeAsAlphaMask;
11665f7e948ad808d3f9c84482594e0da45b4181a6e5Leon Scroggins III        return this;
11670c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
11680c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
1169746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    /** @removed
1170746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     * @deprecated Call {@link #setDecodeAsAlphaMask} instead.
1171746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     */
1172746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    @java.lang.Deprecated
1173746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    public ImageDecoder setAsAlphaMask(boolean asAlphaMask) {
1174746a9fee937969af9be7e060335e26e098971615Leon Scroggins III        return this.setDecodeAsAlphaMask(asAlphaMask);
1175746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    }
1176746a9fee937969af9be7e060335e26e098971615Leon Scroggins III
1177746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    /**
1178746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     *  Return whether to treat single channel input as alpha.
1179746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     *
1180746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     *  <p>This returns whether {@link #setDecodeAsAlphaMask} was set to {@code true}.
1181746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     *  It may still return {@code true} even if the image has more than one
1182746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     *  channel and therefore will not be treated as an alpha mask.</p>
1183746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     */
1184746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    public boolean getDecodeAsAlphaMask() {
1185746a9fee937969af9be7e060335e26e098971615Leon Scroggins III        return mDecodeAsAlphaMask;
1186746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    }
1187746a9fee937969af9be7e060335e26e098971615Leon Scroggins III
1188746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    /** @removed
1189746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     * @deprecated Call {@link #getDecodeAsAlphaMask} instead.
1190746a9fee937969af9be7e060335e26e098971615Leon Scroggins III     */
1191746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    @java.lang.Deprecated
1192746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    public boolean getAsAlphaMask() {
1193746a9fee937969af9be7e060335e26e098971615Leon Scroggins III        return this.getDecodeAsAlphaMask();
1194746a9fee937969af9be7e060335e26e098971615Leon Scroggins III    }
1195746a9fee937969af9be7e060335e26e098971615Leon Scroggins III
11961a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III    /**
11971a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     * Specify the desired {@link ColorSpace} for the output.
11981a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     *
11991a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     * <p>If non-null, the decoder will try to decode into this
12001a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     * color space. If it is null, which is the default, or the request cannot
12011a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     * be met, the decoder will pick either the color space embedded in the
12021a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     * image or the color space best suited for the requested image
12031a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     * configuration (for instance {@link ColorSpace.Named#SRGB sRGB} for
12041a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     * the {@link Bitmap.Config#ARGB_8888} configuration).</p>
12051a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     *
12061a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     * <p>{@link Bitmap.Config#RGBA_F16} always uses the
12071a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     * {@link ColorSpace.Named#LINEAR_EXTENDED_SRGB scRGB} color space).
12081a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     * Bitmaps in other configurations without an embedded color space are
12091a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     * assumed to be in the {@link ColorSpace.Named#SRGB sRGB} color space.</p>
12101a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     *
12111a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     * <p class="note">Only {@link ColorSpace.Model#RGB} color spaces are
12121a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     * currently supported. An <code>IllegalArgumentException</code> will
12131a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     * be thrown by the decode methods when setting a non-RGB color space
12141a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     * such as {@link ColorSpace.Named#CIE_LAB Lab}.</p>
12151a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     *
12161a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     * <p class="note">The specified color space's transfer function must be
12171a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     * an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}. An
12181a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     * <code>IllegalArgumentException</code> will be thrown by the decode methods
12191a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     * if calling {@link ColorSpace.Rgb#getTransferParameters()} on the
12201a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     * specified color space returns null.</p>
12211a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III     */
12221a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III    public ImageDecoder setTargetColorSpace(ColorSpace colorSpace) {
12231a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III        mDesiredColorSpace = colorSpace;
12241a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III        return this;
12251a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III    }
12261a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III
1227ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    @Override
1228ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    public void close() {
1229ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        mCloseGuard.close();
1230ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        if (!mClosed.compareAndSet(false, true)) {
12310c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            return;
12320c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        }
1233ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        nClose(mNativePtr);
12340c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        mNativePtr = 0;
1235ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III
12360b49f5725cabd64d27960b1b017e5c009f701cf8Leon Scroggins III        if (mOwnsInputStream) {
12370b49f5725cabd64d27960b1b017e5c009f701cf8Leon Scroggins III            IoUtils.closeQuietly(mInputStream);
12380b49f5725cabd64d27960b1b017e5c009f701cf8Leon Scroggins III        }
1239ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        IoUtils.closeQuietly(mAssetFd);
1240ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III
1241ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        mInputStream = null;
1242ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        mAssetFd = null;
1243ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        mTempStorage = null;
12440c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
12450c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
12460c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    private void checkState() {
12470c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        if (mNativePtr == 0) {
1248ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            throw new IllegalStateException("Cannot use closed ImageDecoder!");
12490c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        }
12500c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
12510c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        checkSubset(mDesiredWidth, mDesiredHeight, mCropRect);
12520c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
1253e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        if (mAllocator == ALLOCATOR_HARDWARE) {
12540c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            if (mMutable) {
12550c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III                throw new IllegalStateException("Cannot make mutable HARDWARE Bitmap!");
12560c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            }
1257746a9fee937969af9be7e060335e26e098971615Leon Scroggins III            if (mDecodeAsAlphaMask) {
12580c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III                throw new IllegalStateException("Cannot make HARDWARE Alpha mask Bitmap!");
12590c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            }
12600c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        }
12610c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
1262e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        if (mPostProcessor != null && mRequireUnpremultiplied) {
12630c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            throw new IllegalStateException("Cannot draw to unpremultiplied pixels!");
12640c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        }
12651a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III
12661a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III        if (mDesiredColorSpace != null) {
12671a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III            if (!(mDesiredColorSpace instanceof ColorSpace.Rgb)) {
12681a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III                throw new IllegalArgumentException("The target color space must use the "
12691a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III                            + "RGB color model - provided: " + mDesiredColorSpace);
12701a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III            }
12711a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III            if (((ColorSpace.Rgb) mDesiredColorSpace).getTransferParameters() == null) {
12721a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III                throw new IllegalArgumentException("The target color space must use an "
12731a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III                            + "ICC parametric transfer function - provided: " + mDesiredColorSpace);
12741a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III            }
12751a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III        }
12760c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
12770c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
12780c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    private static void checkSubset(int width, int height, Rect r) {
12790c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        if (r == null) {
12800c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            return;
12810c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        }
12820c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        if (r.left < 0 || r.top < 0 || r.right > width || r.bottom > height) {
12830c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            throw new IllegalStateException("Subset " + r + " not contained by "
12840c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III                    + "scaled image bounds: (" + width + " x " + height + ")");
12850c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        }
12860c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
12870c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
1288e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    @NonNull
1289c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III    private Bitmap decodeBitmapInternal() throws IOException {
12908c9d8f2aec65e449005a4a69c54f691ebd514e52Leon Scroggins III        checkState();
12911d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        return nDecodeBitmap(mNativePtr, this, mPostProcessor != null,
12921d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III                mDesiredWidth, mDesiredHeight, mCropRect,
12938c9d8f2aec65e449005a4a69c54f691ebd514e52Leon Scroggins III                mMutable, mAllocator, mRequireUnpremultiplied,
12941a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III                mConserveMemory, mDecodeAsAlphaMask, mDesiredColorSpace);
12958c9d8f2aec65e449005a4a69c54f691ebd514e52Leon Scroggins III    }
12968c9d8f2aec65e449005a4a69c54f691ebd514e52Leon Scroggins III
1297e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    private void callHeaderDecoded(@Nullable OnHeaderDecodedListener listener,
1298e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III            @NonNull Source src) {
1299e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        if (listener != null) {
1300e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III            ImageInfo info = new ImageInfo(this);
1301e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III            try {
1302e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III                listener.onHeaderDecoded(this, info, src);
1303e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III            } finally {
1304e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III                info.mDecoder = null;
1305e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III            }
1306e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III        }
1307e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    }
1308e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III
13090c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
1310b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III     *  Create a {@link Drawable} from a {@code Source}.
1311b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III     *
1312b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III     *  @param src representing the encoded image.
1313b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III     *  @param listener for learning the {@link ImageInfo} and changing any
1314c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III     *      default settings on the {@code ImageDecoder}. This will be called on
1315c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III     *      the same thread as {@code decodeDrawable} before that method returns.
1316b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III     *  @return Drawable for displaying the image.
1317ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III     *  @throws IOException if {@code src} is not found, is an unsupported
1318ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III     *      format, or cannot be decoded for any reason.
13190c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
1320ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    @NonNull
1321b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III    public static Drawable decodeDrawable(@NonNull Source src,
1322c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III            @NonNull OnHeaderDecodedListener listener) throws IOException {
1323c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III        if (listener == null) {
1324c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III            throw new IllegalArgumentException("listener cannot be null! "
1325c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III                    + "Use decodeDrawable(Source) to not have a listener");
1326c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III        }
1327c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III        return decodeDrawableImpl(src, listener);
1328c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III    }
1329c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III
1330c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III    @NonNull
1331c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III    private static Drawable decodeDrawableImpl(@NonNull Source src,
1332b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III            @Nullable OnHeaderDecodedListener listener) throws IOException {
1333ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        try (ImageDecoder decoder = src.createImageDecoder()) {
1334e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III            decoder.mSource = src;
1335e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III            decoder.callHeaderDecoded(listener, src);
13360c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
1337ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            if (decoder.mRequireUnpremultiplied) {
1338ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                // Though this could be supported (ignored) for opaque images,
1339ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                // it seems better to always report this error.
1340ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                throw new IllegalStateException("Cannot decode a Drawable " +
1341ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                                                "with unpremultiplied pixels!");
1342ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            }
13430c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
1344ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            if (decoder.mMutable) {
1345ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                throw new IllegalStateException("Cannot decode a mutable " +
1346ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III                                                "Drawable!");
1347ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III            }
13480c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
134966c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            // this call potentially manipulates the decoder so it must be performed prior to
135066c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            // decoding the bitmap and after decode set the density on the resulting bitmap
135166c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            final int srcDensity = computeDensity(src, decoder);
1352671cce2605ed50c9aba73ab5bd530cb7741c53cdLeon Scroggins III            if (decoder.mAnimated) {
1353671cce2605ed50c9aba73ab5bd530cb7741c53cdLeon Scroggins III                // AnimatedImageDrawable calls postProcessAndRelease only if
1354e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III                // mPostProcessor exists.
1355e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III                ImageDecoder postProcessPtr = decoder.mPostProcessor == null ?
1356671cce2605ed50c9aba73ab5bd530cb7741c53cdLeon Scroggins III                        null : decoder;
1357671cce2605ed50c9aba73ab5bd530cb7741c53cdLeon Scroggins III                Drawable d = new AnimatedImageDrawable(decoder.mNativePtr,
1358671cce2605ed50c9aba73ab5bd530cb7741c53cdLeon Scroggins III                        postProcessPtr, decoder.mDesiredWidth,
135966c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger                        decoder.mDesiredHeight, srcDensity,
136066c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger                        src.computeDstDensity(), decoder.mCropRect,
1361671cce2605ed50c9aba73ab5bd530cb7741c53cdLeon Scroggins III                        decoder.mInputStream, decoder.mAssetFd);
1362671cce2605ed50c9aba73ab5bd530cb7741c53cdLeon Scroggins III                // d has taken ownership of these objects.
1363671cce2605ed50c9aba73ab5bd530cb7741c53cdLeon Scroggins III                decoder.mInputStream = null;
1364671cce2605ed50c9aba73ab5bd530cb7741c53cdLeon Scroggins III                decoder.mAssetFd = null;
1365671cce2605ed50c9aba73ab5bd530cb7741c53cdLeon Scroggins III                return d;
1366671cce2605ed50c9aba73ab5bd530cb7741c53cdLeon Scroggins III            }
1367671cce2605ed50c9aba73ab5bd530cb7741c53cdLeon Scroggins III
1368c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III            Bitmap bm = decoder.decodeBitmapInternal();
136966c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            bm.setDensity(srcDensity);
13700c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
137166c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            Resources res = src.getResources();
13720c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            byte[] np = bm.getNinePatchChunk();
13730c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            if (np != null && NinePatch.isNinePatchChunk(np)) {
13740c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III                Rect opticalInsets = new Rect();
13750c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III                bm.getOpticalInsets(opticalInsets);
13762f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III                Rect padding = decoder.mOutPaddingRect;
13772f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III                if (padding == null) {
13782f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III                    padding = new Rect();
13792f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III                }
13800c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III                nGetPadding(decoder.mNativePtr, padding);
13810c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III                return new NinePatchDrawable(res, bm, np, padding,
13820c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III                        opticalInsets, null);
13830c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            }
13840c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
13850c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            return new BitmapDrawable(res, bm);
13860c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        }
13870c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
13880c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
13890c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    /**
1390b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III     * See {@link #decodeDrawable(Source, OnHeaderDecodedListener)}.
1391b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III     */
1392b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III    @NonNull
1393b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III    public static Drawable decodeDrawable(@NonNull Source src)
1394b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III            throws IOException {
1395c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III        return decodeDrawableImpl(src, null);
1396b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III    }
1397b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III
1398b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III    /**
1399b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III     *  Create a {@link Bitmap} from a {@code Source}.
1400b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III     *
1401b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III     *  @param src representing the encoded image.
1402b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III     *  @param listener for learning the {@link ImageInfo} and changing any
1403c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III     *      default settings on the {@code ImageDecoder}. This will be called on
1404c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III     *      the same thread as {@code decodeBitmap} before that method returns.
1405b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III     *  @return Bitmap containing the image.
1406ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III     *  @throws IOException if {@code src} is not found, is an unsupported
1407ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III     *      format, or cannot be decoded for any reason.
14080c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III     */
1409ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    @NonNull
1410b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III    public static Bitmap decodeBitmap(@NonNull Source src,
1411c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III            @NonNull OnHeaderDecodedListener listener) throws IOException {
1412c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III        if (listener == null) {
1413c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III            throw new IllegalArgumentException("listener cannot be null! "
1414c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III                    + "Use decodeBitmap(Source) to not have a listener");
1415c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III        }
1416c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III        return decodeBitmapImpl(src, listener);
1417c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III    }
1418c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III
1419c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III    @NonNull
1420c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III    private static Bitmap decodeBitmapImpl(@NonNull Source src,
1421b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III            @Nullable OnHeaderDecodedListener listener) throws IOException {
1422ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        try (ImageDecoder decoder = src.createImageDecoder()) {
1423e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III            decoder.mSource = src;
1424e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III            decoder.callHeaderDecoded(listener, src);
14250c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
142666c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            // this call potentially manipulates the decoder so it must be performed prior to
142766c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            // decoding the bitmap
142866c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            final int srcDensity = computeDensity(src, decoder);
1429c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III            Bitmap bm = decoder.decodeBitmapInternal();
143066c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            bm.setDensity(srcDensity);
14312f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III
14322f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III            Rect padding = decoder.mOutPaddingRect;
14332f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III            if (padding != null) {
14342f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III                byte[] np = bm.getNinePatchChunk();
14352f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III                if (np != null && NinePatch.isNinePatchChunk(np)) {
14362f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III                    nGetPadding(decoder.mNativePtr, padding);
14372f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III                }
14382f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III            }
14392f1b06b58fc3c496832afc9b6ceeb2a36ef4bfa6Leon Scroggins III
144066c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            return bm;
144166c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        }
144266c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger    }
144366c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger
144466c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger    // This method may modify the decoder so it must be called prior to performing the decode
144566c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger    private static int computeDensity(@NonNull Source src, @NonNull ImageDecoder decoder) {
144666c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        // if the caller changed the size then we treat the density as unknown
144766c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        if (decoder.requestedResize()) {
144866c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            return Bitmap.DENSITY_NONE;
144966c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        }
145066c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger
145166c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        // Special stuff for compatibility mode: if the target density is not
145266c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        // the same as the display density, but the resource -is- the same as
145366c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        // the display density, then don't scale it down to the target density.
145466c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        // This allows us to load the system's density-correct resources into
145566c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        // an application in compatibility mode, without scaling those down
145666c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        // to the compatibility density only to have them scaled back up when
145766c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        // drawn to the screen.
145866c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        Resources res = src.getResources();
145966c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        final int srcDensity = src.getDensity();
146066c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        if (res != null && res.getDisplayMetrics().noncompatDensityDpi == srcDensity) {
146166c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger            return srcDensity;
14620c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III        }
146366c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger
14648290eaba47b99398fbe0bd59138f902bde558ecbLeon Scroggins III        // For P and above, only resize if it would be a downscale. Scale up prior
14658290eaba47b99398fbe0bd59138f902bde558ecbLeon Scroggins III        // to P in case the app relies on the Bitmap's size without considering density.
146666c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        final int dstDensity = src.computeDstDensity();
14678290eaba47b99398fbe0bd59138f902bde558ecbLeon Scroggins III        if (srcDensity == Bitmap.DENSITY_NONE || srcDensity == dstDensity
14688290eaba47b99398fbe0bd59138f902bde558ecbLeon Scroggins III                || (srcDensity < dstDensity && sApiLevel >= Build.VERSION_CODES.P)) {
14698290eaba47b99398fbe0bd59138f902bde558ecbLeon Scroggins III            return srcDensity;
147066c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger        }
147166c6d78908e0203a497c2e97398c824b2591ea19Derek Sollenberger
14728290eaba47b99398fbe0bd59138f902bde558ecbLeon Scroggins III        float scale = (float) dstDensity / srcDensity;
14738290eaba47b99398fbe0bd59138f902bde558ecbLeon Scroggins III        int scaledWidth = (int) (decoder.mWidth * scale + 0.5f);
14748290eaba47b99398fbe0bd59138f902bde558ecbLeon Scroggins III        int scaledHeight = (int) (decoder.mHeight * scale + 0.5f);
147564481195e13e2dd7197fff569344e5a263b7871aLeon Scroggins III        decoder.setTargetSize(scaledWidth, scaledHeight);
14768290eaba47b99398fbe0bd59138f902bde558ecbLeon Scroggins III        return dstDensity;
14770c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    }
14780c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III
1479e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    @NonNull
14801fad09d4d3f43112abd842da4c94cf00fb1cb46dLeon Scroggins III    private String getMimeType() {
14811fad09d4d3f43112abd842da4c94cf00fb1cb46dLeon Scroggins III        return nGetMimeType(mNativePtr);
14821fad09d4d3f43112abd842da4c94cf00fb1cb46dLeon Scroggins III    }
14831fad09d4d3f43112abd842da4c94cf00fb1cb46dLeon Scroggins III
14841a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III    @Nullable
14851a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III    private ColorSpace getColorSpace() {
14861a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III        return nGetColorSpace(mNativePtr);
14871a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III    }
14881a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III
1489b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III    /**
1490b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III     *  See {@link #decodeBitmap(Source, OnHeaderDecodedListener)}.
1491b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III     */
1492b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III    @NonNull
1493b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III    public static Bitmap decodeBitmap(@NonNull Source src) throws IOException {
1494c9aa856559ca3b08c9409164b2f86c218c71505fLeon Scroggins III        return decodeBitmapImpl(src, null);
1495b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III    }
1496b1cc8e64374832c8b296f609bebabff068ded460Leon Scroggins III
14978c9d8f2aec65e449005a4a69c54f691ebd514e52Leon Scroggins III    /**
14988c9d8f2aec65e449005a4a69c54f691ebd514e52Leon Scroggins III     * Private method called by JNI.
14998c9d8f2aec65e449005a4a69c54f691ebd514e52Leon Scroggins III     */
15008c9d8f2aec65e449005a4a69c54f691ebd514e52Leon Scroggins III    @SuppressWarnings("unused")
1501e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    private int postProcessAndRelease(@NonNull Canvas canvas) {
15028c9d8f2aec65e449005a4a69c54f691ebd514e52Leon Scroggins III        try {
1503e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III            return mPostProcessor.onPostProcess(canvas);
15048c9d8f2aec65e449005a4a69c54f691ebd514e52Leon Scroggins III        } finally {
15058c9d8f2aec65e449005a4a69c54f691ebd514e52Leon Scroggins III            canvas.release();
15068c9d8f2aec65e449005a4a69c54f691ebd514e52Leon Scroggins III        }
15078c9d8f2aec65e449005a4a69c54f691ebd514e52Leon Scroggins III    }
15088c9d8f2aec65e449005a4a69c54f691ebd514e52Leon Scroggins III
1509e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    /**
1510e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     * Private method called by JNI.
1511e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III     */
1512e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    @SuppressWarnings("unused")
1513cf7294fda671a39e6aa21da30be0dac261d71638Leon Scroggins III    private void onPartialImage(@DecodeException.Error int error, @Nullable Throwable cause)
15141d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            throws DecodeException {
15151d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        DecodeException exception = new DecodeException(error, cause, mSource);
15161d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        if (mOnPartialImageListener == null
15171d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III                || !mOnPartialImageListener.onPartialImage(exception)) {
15181d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            throw exception;
15191d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III        }
1520e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    }
1521e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III
15221d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III    private static native ImageDecoder nCreate(long asset, Source src) throws IOException;
15231d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III    private static native ImageDecoder nCreate(ByteBuffer buffer, int position,
15241d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III                                               int limit, Source src) throws IOException;
15251d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III    private static native ImageDecoder nCreate(byte[] data, int offset, int length,
15261d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III                                               Source src) throws IOException;
15271d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III    private static native ImageDecoder nCreate(InputStream is, byte[] storage,
15281d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III                                               Source src) throws IOException;
1529e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    // The fd must be seekable.
15301d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III    private static native ImageDecoder nCreate(FileDescriptor fd, Source src) throws IOException;
1531ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    @NonNull
15320c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III    private static native Bitmap nDecodeBitmap(long nativePtr,
15331d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            @NonNull ImageDecoder decoder,
15341d2bf2b846f0a98f7403bbc791adb2969685d87aLeon Scroggins III            boolean doPostProcess,
15350c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            int width, int height,
1536e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III            @Nullable Rect cropRect, boolean mutable,
15370c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III            int allocator, boolean requireUnpremul,
15381a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III            boolean conserveMemory, boolean decodeAsAlphaMask,
15391a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III            @Nullable ColorSpace desiredColorSpace)
1540ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III        throws IOException;
1541e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    private static native Size nGetSampledSize(long nativePtr,
1542e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III                                               int sampleSize);
1543e5de9aa4a9bab9c4d8288212d6352a65e9808737Leon Scroggins III    private static native void nGetPadding(long nativePtr, @NonNull Rect outRect);
1544ed074fd70011cf804a14b5cf53ffd4b529c5f367Leon Scroggins III    private static native void nClose(long nativePtr);
15451fad09d4d3f43112abd842da4c94cf00fb1cb46dLeon Scroggins III    private static native String nGetMimeType(long nativePtr);
15461a69f4598faef083d0123bb9b6bfcd6acfdec4e0Leon Scroggins III    private static native ColorSpace nGetColorSpace(long nativePtr);
15470c01dbf8f283b7bcaf6babf540a501735c73b4f5Leon Scroggins III}
1548