1 /* ownCloud Android client application
2 * Copyright (C) 2012-2014 ownCloud Inc.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2,
6 * as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 package com
.owncloud
.android
.utils
;
19 import com
.owncloud
.android
.lib
.common
.utils
.Log_OC
;
21 import android
.graphics
.Bitmap
;
22 import android
.graphics
.BitmapFactory
;
23 import android
.graphics
.Matrix
;
24 import android
.graphics
.BitmapFactory
.Options
;
25 import android
.media
.ExifInterface
;
26 import android
.net
.Uri
;
27 import android
.webkit
.MimeTypeMap
;
32 * Utility class with methods for decoding Bitmaps.
34 * @author David A. Velasco
36 public class BitmapUtils
{
40 * Decodes a bitmap from a file containing it minimizing the memory use, known that the bitmap
41 * will be drawn in a surface of reqWidth x reqHeight
43 * @param srcPath Absolute path to the file containing the image.
44 * @param reqWidth Width of the surface where the Bitmap will be drawn on, in pixels.
45 * @param reqHeight Height of the surface where the Bitmap will be drawn on, in pixels.
48 public static Bitmap
decodeSampledBitmapFromFile(String srcPath
, int reqWidth
, int reqHeight
) {
50 // set desired options that will affect the size of the bitmap
51 final Options options
= new Options();
52 options
.inScaled
= true
;
53 options
.inPurgeable
= true
;
54 if (android
.os
.Build
.VERSION
.SDK_INT
>= android
.os
.Build
.VERSION_CODES
.GINGERBREAD_MR1
) {
55 options
.inPreferQualityOverSpeed
= false
;
57 if (android
.os
.Build
.VERSION
.SDK_INT
>= android
.os
.Build
.VERSION_CODES
.HONEYCOMB
) {
58 options
.inMutable
= false
;
61 // make a false load of the bitmap to get its dimensions
62 options
.inJustDecodeBounds
= true
;
64 BitmapFactory
.decodeFile(srcPath
, options
);
66 // calculate factor to subsample the bitmap
67 options
.inSampleSize
= calculateSampleFactor(options
, reqWidth
, reqHeight
);
69 // decode bitmap with inSampleSize set
70 options
.inJustDecodeBounds
= false
;
71 return BitmapFactory
.decodeFile(srcPath
, options
);
77 * Calculates a proper value for options.inSampleSize in order to decode a Bitmap minimizing
78 * the memory overload and covering a target surface of reqWidth x reqHeight if the original
79 * image is big enough.
81 * @param options Bitmap decoding options; options.outHeight and options.inHeight should
83 * @param reqWidth Width of the surface where the Bitmap will be drawn on, in pixels.
84 * @param reqHeight Height of the surface where the Bitmap will be drawn on, in pixels.
85 * @return The largest inSampleSize value that is a power of 2 and keeps both
86 * height and width larger than reqWidth and reqHeight.
88 private static int calculateSampleFactor(Options options
, int reqWidth
, int reqHeight
) {
90 final int height
= options
.outHeight
;
91 final int width
= options
.outWidth
;
94 if (height
> reqHeight
|| width
> reqWidth
) {
95 final int halfHeight
= height
/ 2;
96 final int halfWidth
= width
/ 2;
98 while ((halfHeight
/ inSampleSize
) > reqHeight
99 && (halfWidth
/ inSampleSize
) > reqWidth
) {
108 * Rotate bitmap according to EXIF orientation.
109 * Cf. http://www.daveperrett.com/articles/2012/07/28/exif-orientation-handling-is-a-ghetto/
110 * @param bitmap Bitmap to be rotated
111 * @param storagePath Path to source file of bitmap. Needed for EXIF information.
112 * @return correctly EXIF-rotated bitmap
114 public static Bitmap
rotateImage(Bitmap bitmap
, String storagePath
){
115 Bitmap resultBitmap
= bitmap
;
119 ExifInterface exifInterface
= new ExifInterface(storagePath
);
120 int orientation
= exifInterface
.getAttributeInt(ExifInterface
.TAG_ORIENTATION
, 1);
122 Matrix matrix
= new Matrix();
127 if (orientation
== ExifInterface
.ORIENTATION_FLIP_HORIZONTAL
)
129 matrix
.postScale(-1.0f
, 1.0f
);
132 else if (orientation
== ExifInterface
.ORIENTATION_ROTATE_180
)
134 matrix
.postRotate(180);
137 else if (orientation
== ExifInterface
.ORIENTATION_FLIP_VERTICAL
)
139 matrix
.postScale(1.0f
, -1.0f
);
142 else if (orientation
== ExifInterface
.ORIENTATION_TRANSPOSE
)
144 matrix
.postRotate(-90);
145 matrix
.postScale(1.0f
, -1.0f
);
148 else if (orientation
== ExifInterface
.ORIENTATION_ROTATE_90
)
150 matrix
.postRotate(90);
153 else if (orientation
== ExifInterface
.ORIENTATION_TRANSVERSE
)
155 matrix
.postRotate(90);
156 matrix
.postScale(1.0f
, -1.0f
);
159 else if (orientation
== ExifInterface
.ORIENTATION_ROTATE_270
)
161 matrix
.postRotate(270);
165 resultBitmap
= Bitmap
.createBitmap(bitmap
, 0, 0, bitmap
.getWidth(), bitmap
.getHeight(), matrix
, true
);
166 if (resultBitmap
!= bitmap
) {
170 catch (Exception exception
)
172 Log_OC
.e("BitmapUtil", "Could not rotate the image: " + storagePath
);
178 * Checks if file passed is an image
182 public static boolean isImage(File file
) {
183 Uri selectedUri
= Uri
.fromFile(file
);
184 String fileExtension
= MimeTypeMap
.getFileExtensionFromUrl(selectedUri
.toString().toLowerCase());
185 String mimeType
= MimeTypeMap
.getSingleton().getMimeTypeFromExtension(fileExtension
);
187 return (mimeType
!= null
&& mimeType
.startsWith("image/"));