Util.java revision c1c20e9ce386c1f660059acaede591d2d718995a
1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.camera;
18
19import android.content.ContentResolver;
20import android.content.Context;
21import android.graphics.Bitmap;
22import android.graphics.BitmapFactory;
23import android.graphics.Matrix;
24import android.media.MediaMetadataRetriever;
25import android.net.Uri;
26import android.os.ParcelFileDescriptor;
27import android.util.Log;
28
29import java.io.ByteArrayOutputStream;
30import java.io.Closeable;
31import java.io.IOException;
32import java.io.FileDescriptor;
33
34/**
35 * Collection of utility functions used in this package.
36 */
37public class Util {
38    private static final boolean VERBOSE = false;
39    private static final String TAG = "db.Util";
40
41    private Util() {
42    }
43
44    // Rotates the bitmap by the specified degree.
45    // If a new bitmap is created, the original bitmap is recycled.
46    public static Bitmap rotate(Bitmap b, int degrees) {
47        if (degrees != 0 && b != null) {
48            Matrix m = new Matrix();
49            m.setRotate(degrees,
50                    (float) b.getWidth() / 2, (float) b.getHeight() / 2);
51            try {
52                Bitmap b2 = Bitmap.createBitmap(
53                        b, 0, 0, b.getWidth(), b.getHeight(), m, true);
54                if (b != b2) {
55                    b.recycle();
56                    b = b2;
57                }
58            } catch (OutOfMemoryError ex) {
59                // We have no memory to rotate. Return the original bitmap.
60            }
61        }
62        return b;
63    }
64
65    /*
66     * Compute the sample size as a function of the image size and the target.
67     * Scale the image down so that both the width and height are just above the
68     * target. If this means that one of the dimension goes from above the
69     * target to below the target (e.g. given a width of 480 and an image width
70     * of 600 but sample size of 2 -- i.e. new width 300 -- bump the sample size
71     * down by 1.
72     */
73    public static int computeSampleSize(
74            BitmapFactory.Options options, int target) {
75        int w = options.outWidth;
76        int h = options.outHeight;
77
78        int candidateW = w / target;
79        int candidateH = h / target;
80        int candidate = Math.max(candidateW, candidateH);
81
82        if (candidate == 0) return 1;
83
84        if (candidate > 1) {
85            if ((w > target) && (w / candidate) < target) candidate -= 1;
86        }
87
88        if (candidate > 1) {
89            if ((h > target) && (h / candidate) < target) candidate -= 1;
90        }
91
92        return candidate;
93    }
94
95    /**
96     * Creates a centered bitmap of the desired size. Recycles the input.
97     * @param source
98     */
99    public static Bitmap extractMiniThumb(
100            Bitmap source, int width, int height) {
101        return Util.extractMiniThumb(source, width, height, true);
102    }
103
104    public static Bitmap extractMiniThumb(
105            Bitmap source, int width, int height, boolean recycle) {
106        if (source == null) {
107            return null;
108        }
109
110        float scale;
111        if (source.getWidth() < source.getHeight()) {
112            scale = width / (float) source.getWidth();
113        } else {
114            scale = height / (float) source.getHeight();
115        }
116        Matrix matrix = new Matrix();
117        matrix.setScale(scale, scale);
118        Bitmap miniThumbnail = ImageLoader.transform(matrix, source,
119                width, height, false);
120
121        if (recycle && miniThumbnail != source) {
122            source.recycle();
123        }
124        return miniThumbnail;
125    }
126
127    /**
128     * Creates a byte[] for a given bitmap of the desired size. Recycles the
129     * input bitmap.
130     */
131    public static byte[] miniThumbData(Bitmap source) {
132        if (source == null) return null;
133
134        Bitmap miniThumbnail = extractMiniThumb(
135                source, ImageManager.MINI_THUMB_TARGET_SIZE,
136                ImageManager.MINI_THUMB_TARGET_SIZE);
137
138        ByteArrayOutputStream miniOutStream = new ByteArrayOutputStream();
139        miniThumbnail.compress(Bitmap.CompressFormat.JPEG, 75, miniOutStream);
140        miniThumbnail.recycle();
141
142        try {
143            miniOutStream.close();
144            byte [] data = miniOutStream.toByteArray();
145            return data;
146        } catch (java.io.IOException ex) {
147            Log.e(TAG, "got exception ex " + ex);
148        }
149        return null;
150    }
151
152    /**
153     * @return true if the mimetype is a video mimetype.
154     */
155    public static boolean isVideoMimeType(String mimeType) {
156        return mimeType.startsWith("video/");
157    }
158
159    /**
160     * Create a video thumbnail for a video. May return null if the video is
161     * corrupt.
162     *
163     * @param filePath
164     */
165    public static Bitmap createVideoThumbnail(String filePath) {
166        Bitmap bitmap = null;
167        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
168        try {
169            retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY);
170            retriever.setDataSource(filePath);
171            bitmap = retriever.captureFrame();
172        } catch (IllegalArgumentException ex) {
173            // Assume this is a corrupt video file
174        } catch (RuntimeException ex) {
175            // Assume this is a corrupt video file.
176        } finally {
177            try {
178                retriever.release();
179            } catch (RuntimeException ex) {
180                // Ignore failures while cleaning up.
181            }
182        }
183        return bitmap;
184    }
185
186    public static int indexOf(String [] array, String s) {
187        for (int i = 0; i < array.length; i++) {
188            if (array[i].equals(s)) {
189                return i;
190            }
191        }
192        return -1;
193    }
194
195    public static void closeSiliently(Closeable c) {
196        if (c == null) return;
197        try {
198            c.close();
199        } catch (Throwable t) {
200            // do nothing
201        }
202    }
203
204    public static void closeSiliently(ParcelFileDescriptor c) {
205        if (c == null) return;
206        try {
207            c.close();
208        } catch (Throwable t) {
209            // do nothing
210        }
211    }
212
213    /**
214     * Make a bitmap from a given Uri.
215     *
216     * @param uri
217     */
218    public static Bitmap makeBitmap(int targetWidthOrHeight, Uri uri,
219            ContentResolver cr) {
220        ParcelFileDescriptor input = null;
221        try {
222            input = cr.openFileDescriptor(uri, "r");
223            return makeBitmap(targetWidthOrHeight, uri, cr, input, null);
224        } catch (IOException ex) {
225            return null;
226        } finally {
227            closeSiliently(input);
228        }
229    }
230
231    public static Bitmap makeBitmap(int targetWidthHeight, Uri uri,
232            ContentResolver cr, ParcelFileDescriptor pfd,
233            BitmapFactory.Options options) {
234        Bitmap b = null;
235        try {
236            if (pfd == null) pfd = makeInputStream(uri, cr);
237            if (pfd == null) return null;
238            if (options == null) options = new BitmapFactory.Options();
239
240            FileDescriptor fd = pfd.getFileDescriptor();
241            options.inSampleSize = 1;
242            if (targetWidthHeight != -1) {
243                options.inJustDecodeBounds = true;
244                BitmapManager.instance().decodeFileDescriptor(
245                        fd, null, options);
246                if (options.mCancel || options.outWidth == -1
247                        || options.outHeight == -1) {
248                    return null;
249                }
250                options.inSampleSize =
251                        computeSampleSize(options, targetWidthHeight);
252                options.inJustDecodeBounds = false;
253            }
254
255            options.inDither = false;
256            options.inPreferredConfig = Bitmap.Config.ARGB_8888;
257            b = BitmapManager.instance()
258                    .decodeFileDescriptor(fd, null, options);
259        } catch (OutOfMemoryError ex) {
260            Log.e(TAG, "Got oom exception ", ex);
261            return null;
262        } finally {
263            closeSiliently(pfd);
264        }
265        return b;
266    }
267
268    private static ParcelFileDescriptor makeInputStream(
269            Uri uri, ContentResolver cr) {
270        try {
271            return cr.openFileDescriptor(uri, "r");
272        } catch (IOException ex) {
273            return null;
274        }
275    }
276}
277