OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / frameworks / base / graphics / java / android / graphics / BitmapRegionDecoder.java
1 /* Copyright (C) 2010 The Android Open Source Project
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 package android.graphics;
17
18 import android.content.res.AssetManager;
19
20 import java.io.BufferedInputStream;
21 import java.io.FileDescriptor;
22 import java.io.FileInputStream;
23 import java.io.IOException;
24 import java.io.InputStream;
25
26 /**
27  * BitmapRegionDecoder can be used to decode a rectangle region from an image.
28  * BitmapRegionDecoder is particularly useful when an original image is large and
29  * you only need parts of the image.
30  *
31  * <p>To create a BitmapRegionDecoder, call newInstance(...).
32  * Given a BitmapRegionDecoder, users can call decodeRegion() repeatedly
33  * to get a decoded Bitmap of the specified region.
34  *
35  */
36 public final class BitmapRegionDecoder {
37     private int mNativeBitmapRegionDecoder;
38     private boolean mRecycled;
39
40     /**
41      * Create a BitmapRegionDecoder from the specified byte array.
42      * Currently only the JPEG and PNG formats are supported.
43      *
44      * @param data byte array of compressed image data.
45      * @param offset offset into data for where the decoder should begin
46      *               parsing.
47      * @param length the number of bytes, beginning at offset, to parse
48      * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
49      *                    shallow reference to the input. If this is false,
50      *                    then the BitmapRegionDecoder will explicitly make a copy of the
51      *                    input data, and keep that. Even if sharing is allowed,
52      *                    the implementation may still decide to make a deep
53      *                    copy of the input data. If an image is progressively encoded,
54      *                    allowing sharing may degrade the decoding speed.
55      * @return BitmapRegionDecoder, or null if the image data could not be decoded.
56      * @throws IOException if the image format is not supported or can not be decoded.
57      */
58     public static BitmapRegionDecoder newInstance(byte[] data,
59             int offset, int length, boolean isShareable) throws IOException {
60         if ((offset | length) < 0 || data.length < offset + length) {
61             throw new ArrayIndexOutOfBoundsException();
62         }
63         return nativeNewInstance(data, offset, length, isShareable);
64     }
65
66     /**
67      * Create a BitmapRegionDecoder from the file descriptor.
68      * The position within the descriptor will not be changed when
69      * this returns, so the descriptor can be used again as is.
70      * Currently only the JPEG and PNG formats are supported.
71      *
72      * @param fd The file descriptor containing the data to decode
73      * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
74      *                    shallow reference to the input. If this is false,
75      *                    then the BitmapRegionDecoder will explicitly make a copy of the
76      *                    input data, and keep that. Even if sharing is allowed,
77      *                    the implementation may still decide to make a deep
78      *                    copy of the input data. If an image is progressively encoded,
79      *                    allowing sharing may degrade the decoding speed.
80      * @return BitmapRegionDecoder, or null if the image data could not be decoded.
81      * @throws IOException if the image format is not supported or can not be decoded.
82      */
83     public static BitmapRegionDecoder newInstance(
84             FileDescriptor fd, boolean isShareable) throws IOException {
85         return nativeNewInstance(fd, isShareable);
86     }
87
88     /**
89      * Create a BitmapRegionDecoder from an input stream.
90      * The stream's position will be where ever it was after the encoded data
91      * was read.
92      * Currently only the JPEG and PNG formats are supported.
93      *
94      * @param is The input stream that holds the raw data to be decoded into a
95      *           BitmapRegionDecoder.
96      * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
97      *                    shallow reference to the input. If this is false,
98      *                    then the BitmapRegionDecoder will explicitly make a copy of the
99      *                    input data, and keep that. Even if sharing is allowed,
100      *                    the implementation may still decide to make a deep
101      *                    copy of the input data. If an image is progressively encoded,
102      *                    allowing sharing may degrade the decoding speed.
103      * @return BitmapRegionDecoder, or null if the image data could not be decoded.
104      * @throws IOException if the image format is not supported or can not be decoded.
105      */
106     public static BitmapRegionDecoder newInstance(InputStream is,
107             boolean isShareable) throws IOException {
108         // we need mark/reset to work properly in JNI
109
110         if (!is.markSupported()) {
111             is = new BufferedInputStream(is, 16 * 1024);
112         }
113
114         if (is instanceof AssetManager.AssetInputStream) {
115             return nativeNewInstance(
116                     ((AssetManager.AssetInputStream) is).getAssetInt(),
117                     isShareable);
118         } else {
119             // pass some temp storage down to the native code. 1024 is made up,
120             // but should be large enough to avoid too many small calls back
121             // into is.read(...).
122             byte [] tempStorage = new byte[16 * 1024];
123             return nativeNewInstance(is, tempStorage, isShareable);
124         }
125     }
126
127     /**
128      * Create a BitmapRegionDecoder from a file path.
129      * Currently only the JPEG and PNG formats are supported.
130      *
131      * @param pathName complete path name for the file to be decoded.
132      * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
133      *                    shallow reference to the input. If this is false,
134      *                    then the BitmapRegionDecoder will explicitly make a copy of the
135      *                    input data, and keep that. Even if sharing is allowed,
136      *                    the implementation may still decide to make a deep
137      *                    copy of the input data. If an image is progressively encoded,
138      *                    allowing sharing may degrade the decoding speed.
139      * @return BitmapRegionDecoder, or null if the image data could not be decoded.
140      * @throws IOException if the image format is not supported or can not be decoded.
141      */
142     public static BitmapRegionDecoder newInstance(String pathName,
143             boolean isShareable) throws IOException {
144         BitmapRegionDecoder decoder = null;
145         InputStream stream = null;
146
147         try {
148             stream = new FileInputStream(pathName);
149             decoder = newInstance(stream, isShareable);
150         } finally {
151             if (stream != null) {
152                 try {
153                     stream.close();
154                 } catch (IOException e) {
155                     // do nothing here
156                 }
157             }
158         }
159         return decoder;
160     }
161
162     /*  Private constructor that must receive an already allocated native
163         region decoder int (pointer).
164
165         This can be called from JNI code.
166     */
167     private BitmapRegionDecoder(int decoder) {
168         mNativeBitmapRegionDecoder = decoder;
169         mRecycled = false;
170     }
171
172     /**
173      * Decodes a rectangle region in the image specified by rect.
174      *
175      * @param rect The rectangle that specified the region to be decode.
176      * @param options null-ok; Options that control downsampling.
177      *             inPurgeable is not supported.
178      * @return The decoded bitmap, or null if the image data could not be
179      *         decoded.
180      */
181     public Bitmap decodeRegion(Rect rect, BitmapFactory.Options options) {
182         checkRecycled("decodeRegion called on recycled region decoder");
183         if (rect.left < 0 || rect.top < 0 || rect.right > getWidth()
184                 || rect.bottom > getHeight())
185             throw new IllegalArgumentException("rectangle is not inside the image");
186         return nativeDecodeRegion(mNativeBitmapRegionDecoder, rect.left, rect.top,
187                 rect.right - rect.left, rect.bottom - rect.top, options);
188     }
189
190     /** Returns the original image's width */
191     public int getWidth() {
192         checkRecycled("getWidth called on recycled region decoder");
193         return nativeGetWidth(mNativeBitmapRegionDecoder);
194     }
195
196     /** Returns the original image's height */
197     public int getHeight() {
198         checkRecycled("getHeight called on recycled region decoder");
199         return nativeGetHeight(mNativeBitmapRegionDecoder);
200     }
201
202     /**
203      * Frees up the memory associated with this region decoder, and mark the
204      * region decoder as "dead", meaning it will throw an exception if decodeRegion(),
205      * getWidth() or getHeight() is called.
206      *
207      * <p>This operation cannot be reversed, so it should only be called if you are
208      * sure there are no further uses for the region decoder. This is an advanced call,
209      * and normally need not be called, since the normal GC process will free up this
210      * memory when there are no more references to this region decoder.
211      */
212     public void recycle() {
213         if (!mRecycled) {
214             nativeClean(mNativeBitmapRegionDecoder);
215             mRecycled = true;
216         }
217     }
218
219     /**
220      * Returns true if this region decoder has been recycled.
221      * If so, then it is an error to try use its method.
222      *
223      * @return true if the region decoder has been recycled
224      */
225     public final boolean isRecycled() {
226         return mRecycled;
227     }
228
229     /**
230      * Called by methods that want to throw an exception if the region decoder
231      * has already been recycled.
232      */
233     private void checkRecycled(String errorMessage) {
234         if (mRecycled) {
235             throw new IllegalStateException(errorMessage);
236         }
237     }
238
239     @Override
240     protected void finalize() throws Throwable {
241         try {
242             recycle();
243         } finally {
244             super.finalize();
245         }
246     }
247
248     private static native Bitmap nativeDecodeRegion(int lbm,
249             int start_x, int start_y, int width, int height,
250             BitmapFactory.Options options);
251     private static native int nativeGetWidth(int lbm);
252     private static native int nativeGetHeight(int lbm);
253     private static native void nativeClean(int lbm);
254
255     private static native BitmapRegionDecoder nativeNewInstance(
256             byte[] data, int offset, int length, boolean isShareable);
257     private static native BitmapRegionDecoder nativeNewInstance(
258             FileDescriptor fd, boolean isShareable);
259     private static native BitmapRegionDecoder nativeNewInstance(
260             InputStream is, byte[] storage, boolean isShareable);
261     private static native BitmapRegionDecoder nativeNewInstance(
262             int asset, boolean isShareable);
263 }