172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project/* 272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * Copyright (C) 2008 Esmertec AG. 372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * 572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * you may not use this file except in compliance with the License. 772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * You may obtain a copy of the License at 872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * 972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 1072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * 1172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * See the License for the specific language governing permissions and 1572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * limitations under the License. 1672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project */ 1772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 1872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectpackage com.android.mms.ui; 1972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 2072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport com.android.mms.model.ImageModel; 219242286c35743422051d439d7460cd0a1426899cWei Huangimport com.android.mms.LogTag; 22bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjiev 23bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjievimport com.google.android.mms.ContentType; 24f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport com.google.android.mms.pdu.PduPart; 25fd644551e8506266aad2b76463b51b44154ed62fTom Taylorimport android.database.sqlite.SqliteWrapper; 2672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 2772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.content.Context; 2872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.database.Cursor; 2972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.graphics.Bitmap; 3072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.graphics.BitmapFactory; 3172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.graphics.Bitmap.CompressFormat; 3272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.net.Uri; 3372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.provider.MediaStore.Images; 34f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport android.provider.Telephony.Mms.Part; 3572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.text.TextUtils; 3672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.util.Log; 3772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.webkit.MimeTypeMap; 3872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 3972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport java.io.ByteArrayOutputStream; 4072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport java.io.FileNotFoundException; 4172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport java.io.IOException; 4272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport java.io.InputStream; 4337880013315d8b7abefd9081b2c36b060083d6faTom Taylorimport java.io.OutputStream; 4472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 4572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectpublic class UriImage { 469242286c35743422051d439d7460cd0a1426899cWei Huang private static final String TAG = "Mms/image"; 47b0664c5822ee07642617a73c932b02a2636a2223Tom Taylor private static final boolean DEBUG = false; 48150c4179995cc0a75f934ef194372f9295957ca2Joe Onorato private static final boolean LOCAL_LOGV = false; 4972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 5072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project private final Context mContext; 5172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project private final Uri mUri; 5272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project private String mContentType; 5372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project private String mPath; 5472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project private String mSrc; 5572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project private int mWidth; 5672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project private int mHeight; 5772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 5872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project public UriImage(Context context, Uri uri) { 5972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project if ((null == context) || (null == uri)) { 6072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project throw new IllegalArgumentException(); 6172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 6272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 6372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project String scheme = uri.getScheme(); 6472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project if (scheme.equals("content")) { 6572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project initFromContentUri(context, uri); 6672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } else if (uri.getScheme().equals("file")) { 6772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project initFromFile(context, uri); 6872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 69325a37787f144421f995eeb385f67a5d255d7820Tom Taylor 7072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project mContext = context; 7172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project mUri = uri; 7272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 7372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project decodeBoundsInfo(); 74b0664c5822ee07642617a73c932b02a2636a2223Tom Taylor 75b0664c5822ee07642617a73c932b02a2636a2223Tom Taylor if (LOCAL_LOGV) { 76b0664c5822ee07642617a73c932b02a2636a2223Tom Taylor Log.v(TAG, "UriImage uri: " + uri + " mPath: " + mPath + " mWidth: " + mWidth + 77b0664c5822ee07642617a73c932b02a2636a2223Tom Taylor " mHeight: " + mHeight); 78b0664c5822ee07642617a73c932b02a2636a2223Tom Taylor } 7972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 8072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 8172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project private void initFromFile(Context context, Uri uri) { 82325a37787f144421f995eeb385f67a5d255d7820Tom Taylor mPath = uri.getPath(); 8372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton(); 84325a37787f144421f995eeb385f67a5d255d7820Tom Taylor String extension = MimeTypeMap.getFileExtensionFromUrl(mPath); 85325a37787f144421f995eeb385f67a5d255d7820Tom Taylor if (TextUtils.isEmpty(extension)) { 86325a37787f144421f995eeb385f67a5d255d7820Tom Taylor // getMimeTypeFromExtension() doesn't handle spaces in filenames nor can it handle 87325a37787f144421f995eeb385f67a5d255d7820Tom Taylor // urlEncoded strings. Let's try one last time at finding the extension. 88325a37787f144421f995eeb385f67a5d255d7820Tom Taylor int dotPos = mPath.lastIndexOf('.'); 89325a37787f144421f995eeb385f67a5d255d7820Tom Taylor if (0 <= dotPos) { 90325a37787f144421f995eeb385f67a5d255d7820Tom Taylor extension = mPath.substring(dotPos + 1); 91325a37787f144421f995eeb385f67a5d255d7820Tom Taylor } 9272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 93325a37787f144421f995eeb385f67a5d255d7820Tom Taylor mContentType = mimeTypeMap.getMimeTypeFromExtension(extension); 94325a37787f144421f995eeb385f67a5d255d7820Tom Taylor // It's ok if mContentType is null. Eventually we'll show a toast telling the 95325a37787f144421f995eeb385f67a5d255d7820Tom Taylor // user the picture couldn't be attached. 96f5b73486499febb57260bd63f694c47b07e240faTom Taylor 97f5b73486499febb57260bd63f694c47b07e240faTom Taylor buildSrcFromPath(); 98f5b73486499febb57260bd63f694c47b07e240faTom Taylor } 99f5b73486499febb57260bd63f694c47b07e240faTom Taylor 100f5b73486499febb57260bd63f694c47b07e240faTom Taylor private void buildSrcFromPath() { 101f5b73486499febb57260bd63f694c47b07e240faTom Taylor mSrc = mPath.substring(mPath.lastIndexOf('/') + 1); 102f5b73486499febb57260bd63f694c47b07e240faTom Taylor 103f5b73486499febb57260bd63f694c47b07e240faTom Taylor if(mSrc.startsWith(".") && mSrc.length() > 1) { 104f5b73486499febb57260bd63f694c47b07e240faTom Taylor mSrc = mSrc.substring(1); 105f5b73486499febb57260bd63f694c47b07e240faTom Taylor } 106f5b73486499febb57260bd63f694c47b07e240faTom Taylor 107f5b73486499febb57260bd63f694c47b07e240faTom Taylor // Some MMSCs appear to have problems with filenames 108f5b73486499febb57260bd63f694c47b07e240faTom Taylor // containing a space. So just replace them with 109f5b73486499febb57260bd63f694c47b07e240faTom Taylor // underscores in the name, which is typically not 110f5b73486499febb57260bd63f694c47b07e240faTom Taylor // visible to the user anyway. 111f5b73486499febb57260bd63f694c47b07e240faTom Taylor mSrc = mSrc.replace(' ', '_'); 11272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 113325a37787f144421f995eeb385f67a5d255d7820Tom Taylor 11472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project private void initFromContentUri(Context context, Uri uri) { 11572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project Cursor c = SqliteWrapper.query(context, context.getContentResolver(), 11672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project uri, null, null, null, null); 11772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 118f5b73486499febb57260bd63f694c47b07e240faTom Taylor mSrc = null; 11972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project if (c == null) { 12072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project throw new IllegalArgumentException( 12172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project "Query on " + uri + " returns null result."); 12272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 12372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 12472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project try { 12572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project if ((c.getCount() != 1) || !c.moveToFirst()) { 12672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project throw new IllegalArgumentException( 12772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project "Query on " + uri + " returns 0 or multiple rows."); 12872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 12972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 13072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project String filePath; 13172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project if (ImageModel.isMmsUri(uri)) { 13272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project filePath = c.getString(c.getColumnIndexOrThrow(Part.FILENAME)); 13372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project if (TextUtils.isEmpty(filePath)) { 13472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project filePath = c.getString( 13572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project c.getColumnIndexOrThrow(Part._DATA)); 13672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 13772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project mContentType = c.getString( 13872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project c.getColumnIndexOrThrow(Part.CONTENT_TYPE)); 13972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } else { 140e7cee115c2e0deada90627fd265139c22fdc32d4Tom Taylor filePath = uri.getPath(); 1412c48c7894f1c4d4265bfe499e596fdd6fd3e9484Tom Taylor try { 1422c48c7894f1c4d4265bfe499e596fdd6fd3e9484Tom Taylor mContentType = c.getString( 1432c48c7894f1c4d4265bfe499e596fdd6fd3e9484Tom Taylor c.getColumnIndexOrThrow(Images.Media.MIME_TYPE)); // mime_type 1442c48c7894f1c4d4265bfe499e596fdd6fd3e9484Tom Taylor } catch (IllegalArgumentException e) { 1452c48c7894f1c4d4265bfe499e596fdd6fd3e9484Tom Taylor mContentType = c.getString(c.getColumnIndexOrThrow("mimetype")); 1462c48c7894f1c4d4265bfe499e596fdd6fd3e9484Tom Taylor } 147f5b73486499febb57260bd63f694c47b07e240faTom Taylor 148f5b73486499febb57260bd63f694c47b07e240faTom Taylor // use the original filename if possible 149f5b73486499febb57260bd63f694c47b07e240faTom Taylor int nameIndex = c.getColumnIndex(Images.Media.DISPLAY_NAME); 150f5b73486499febb57260bd63f694c47b07e240faTom Taylor if (nameIndex != -1) { 151f5b73486499febb57260bd63f694c47b07e240faTom Taylor mSrc = c.getString(nameIndex); 152f5b73486499febb57260bd63f694c47b07e240faTom Taylor if (!TextUtils.isEmpty(mSrc)) { 153f5b73486499febb57260bd63f694c47b07e240faTom Taylor // Some MMSCs appear to have problems with filenames 154f5b73486499febb57260bd63f694c47b07e240faTom Taylor // containing a space. So just replace them with 155f5b73486499febb57260bd63f694c47b07e240faTom Taylor // underscores in the name, which is typically not 156f5b73486499febb57260bd63f694c47b07e240faTom Taylor // visible to the user anyway. 157f5b73486499febb57260bd63f694c47b07e240faTom Taylor mSrc = mSrc.replace(' ', '_'); 158f5b73486499febb57260bd63f694c47b07e240faTom Taylor } else { 159f5b73486499febb57260bd63f694c47b07e240faTom Taylor mSrc = null; 160f5b73486499febb57260bd63f694c47b07e240faTom Taylor } 161f5b73486499febb57260bd63f694c47b07e240faTom Taylor } 16272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 16372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project mPath = filePath; 164f5b73486499febb57260bd63f694c47b07e240faTom Taylor if (mSrc == null) { 165f5b73486499febb57260bd63f694c47b07e240faTom Taylor buildSrcFromPath(); 166f5b73486499febb57260bd63f694c47b07e240faTom Taylor } 1672c48c7894f1c4d4265bfe499e596fdd6fd3e9484Tom Taylor } catch (IllegalArgumentException e) { 1682c48c7894f1c4d4265bfe499e596fdd6fd3e9484Tom Taylor Log.e(TAG, "initFromContentUri couldn't load image uri: " + uri, e); 16972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } finally { 17072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project c.close(); 17172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 17272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 17372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 17472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project private void decodeBoundsInfo() { 17572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project InputStream input = null; 17672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project try { 17772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project input = mContext.getContentResolver().openInputStream(mUri); 17872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project BitmapFactory.Options opt = new BitmapFactory.Options(); 17972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project opt.inJustDecodeBounds = true; 18072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project BitmapFactory.decodeStream(input, null, opt); 18172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project mWidth = opt.outWidth; 18272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project mHeight = opt.outHeight; 18372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } catch (FileNotFoundException e) { 18472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project // Ignore 18572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project Log.e(TAG, "IOException caught while opening stream", e); 18672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } finally { 18772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project if (null != input) { 18872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project try { 18972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project input.close(); 19072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } catch (IOException e) { 19172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project // Ignore 19272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project Log.e(TAG, "IOException caught while closing stream", e); 19372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 19472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 19572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 19672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 19772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 19872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project public String getContentType() { 19972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project return mContentType; 20072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 20172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 20272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project public String getSrc() { 20372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project return mSrc; 20472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 20572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 206721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor public String getPath() { 207721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor return mPath; 208721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor } 209721ad07121cb9b0cd76bdbbc88494aa8f4d45a6dTom Taylor 21072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project public int getWidth() { 21172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project return mWidth; 21272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 21372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 21472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project public int getHeight() { 21572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project return mHeight; 21672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 21772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 218bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjiev /** 219bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjiev * Get a version of this image resized to fit the given dimension and byte-size limits. Note 220bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjiev * that the content type of the resulting PduPart may not be the same as the content type of 221bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjiev * this UriImage; always call {@link PduPart#getContentType()} to get the new content type. 222bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjiev * 223bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjiev * @param widthLimit The width limit, in pixels 224bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjiev * @param heightLimit The height limit, in pixels 225bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjiev * @param byteLimit The binary size limit, in bytes 226bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjiev * @return A new PduPart containing the resized image data 227bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjiev */ 228f79b803adc0cee3778cf6aac52d203896cde5d95Christian Gustafsson public PduPart getResizedImageAsPart(int widthLimit, int heightLimit, int byteLimit) { 22972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project PduPart part = new PduPart(); 23072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 23137880013315d8b7abefd9081b2c36b060083d6faTom Taylor byte[] data = getResizedImageData(mWidth, mHeight, 23237880013315d8b7abefd9081b2c36b060083d6faTom Taylor widthLimit, heightLimit, byteLimit, mUri, mContext); 23372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project if (data == null) { 23472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project if (LOCAL_LOGV) { 23572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project Log.v(TAG, "Resize image failed."); 23672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 23772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project return null; 23872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 23972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 24072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project part.setData(data); 241bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjiev // getResizedImageData ALWAYS compresses to JPEG, regardless of the original content type 242bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjiev part.setContentType(ContentType.IMAGE_JPEG.getBytes()); 24372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 24472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project return part; 24572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 24672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 247f79b803adc0cee3778cf6aac52d203896cde5d95Christian Gustafsson private static final int NUMBER_OF_RESIZE_ATTEMPTS = 4; 248f79b803adc0cee3778cf6aac52d203896cde5d95Christian Gustafsson 249bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjiev /** 250bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjiev * Resize and recompress the image such that it fits the given limits. The resulting byte 251bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjiev * array contains an image in JPEG format, regardless of the original image's content type. 252bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjiev * @param widthLimit The width limit, in pixels 253bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjiev * @param heightLimit The height limit, in pixels 254bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjiev * @param byteLimit The binary size limit, in bytes 255bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjiev * @return A resized/recompressed version of this image, in JPEG format 256bbc5b8d0076b0cdae851bfec636a854ef77bd6ceTodor Kalaydjiev */ 25737880013315d8b7abefd9081b2c36b060083d6faTom Taylor public static byte[] getResizedImageData(int width, int height, 25837880013315d8b7abefd9081b2c36b060083d6faTom Taylor int widthLimit, int heightLimit, int byteLimit, Uri uri, Context context) { 25937880013315d8b7abefd9081b2c36b060083d6faTom Taylor int outWidth = width; 26037880013315d8b7abefd9081b2c36b060083d6faTom Taylor int outHeight = height; 26172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 2628c86a52a2c13083a25761256ab0dfc416260c162Tom Taylor float scaleFactor = 1.F; 2639aeb4e9e6aebe9d99cf817cedbdeb0bb0ae5a024Mark Wagner while ((outWidth * scaleFactor > widthLimit) || (outHeight * scaleFactor > heightLimit)) { 2649aeb4e9e6aebe9d99cf817cedbdeb0bb0ae5a024Mark Wagner scaleFactor *= .75F; 26572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 26672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 2679242286c35743422051d439d7460cd0a1426899cWei Huang if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) { 26837880013315d8b7abefd9081b2c36b060083d6faTom Taylor Log.v(TAG, "getResizedBitmap: wlimit=" + widthLimit + 2699242286c35743422051d439d7460cd0a1426899cWei Huang ", hlimit=" + heightLimit + ", sizeLimit=" + byteLimit + 27037880013315d8b7abefd9081b2c36b060083d6faTom Taylor ", width=" + width + ", height=" + height + 271b0664c5822ee07642617a73c932b02a2636a2223Tom Taylor ", initialScaleFactor=" + scaleFactor + 27237880013315d8b7abefd9081b2c36b060083d6faTom Taylor ", uri=" + uri); 2739242286c35743422051d439d7460cd0a1426899cWei Huang } 2749242286c35743422051d439d7460cd0a1426899cWei Huang 27572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project InputStream input = null; 27672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project try { 277f79b803adc0cee3778cf6aac52d203896cde5d95Christian Gustafsson ByteArrayOutputStream os = null; 278f79b803adc0cee3778cf6aac52d203896cde5d95Christian Gustafsson int attempts = 1; 2798c86a52a2c13083a25761256ab0dfc416260c162Tom Taylor int sampleSize = 1; 280946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev BitmapFactory.Options options = new BitmapFactory.Options(); 281946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev int quality = MessageUtils.IMAGE_COMPRESSION_QUALITY; 282946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev Bitmap b = null; 283f79b803adc0cee3778cf6aac52d203896cde5d95Christian Gustafsson 284946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev // In this loop, attempt to decode the stream with the best possible subsampling (we 285946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev // start with 1, which means no subsampling - get the original content) without running 286946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev // out of memory. 287f79b803adc0cee3778cf6aac52d203896cde5d95Christian Gustafsson do { 28837880013315d8b7abefd9081b2c36b060083d6faTom Taylor input = context.getContentResolver().openInputStream(uri); 289946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev options.inSampleSize = sampleSize; 2901cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor try { 291946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev b = BitmapFactory.decodeStream(input, null, options); 2923d8877fa3e07c019d1779793ca0081beca177b6aTom Taylor if (b == null) { 2933d8877fa3e07c019d1779793ca0081beca177b6aTom Taylor return null; // Couldn't decode and it wasn't because of an exception, 2943d8877fa3e07c019d1779793ca0081beca177b6aTom Taylor // bail. 2953d8877fa3e07c019d1779793ca0081beca177b6aTom Taylor } 296946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev } catch (OutOfMemoryError e) { 29737880013315d8b7abefd9081b2c36b060083d6faTom Taylor Log.w(TAG, "getResizedBitmap: img too large to decode (OutOfMemoryError), " + 298946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev "may try with larger sampleSize. Curr sampleSize=" + sampleSize); 299946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev sampleSize *= 2; // works best as a power of two 300946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev attempts++; 301946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev continue; 302946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev } finally { 303946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev if (input != null) { 304946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev try { 305946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev input.close(); 306946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev } catch (IOException e) { 307946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev Log.e(TAG, e.getMessage(), e); 308946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev } 309f79b803adc0cee3778cf6aac52d203896cde5d95Christian Gustafsson } 310946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev } 311946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev } while (b == null && attempts < NUMBER_OF_RESIZE_ATTEMPTS); 312946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev 313946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev if (b == null) { 31451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (Log.isLoggable(LogTag.APP, Log.VERBOSE) 31551e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor && attempts >= NUMBER_OF_RESIZE_ATTEMPTS) { 31651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor Log.v(TAG, "getResizedImageData: gave up after too many attempts to resize"); 31751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 318946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev return null; 319946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev } 320946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev 321852b629e3be73f8eb01651f1868f3ed1857df815Tom Taylor boolean resultTooBig = true; 322946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev attempts = 1; // reset count for second loop 323946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev // In this loop, we attempt to compress/resize the content to fit the given dimension 324946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev // and file-size limits. 325946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev do { 326946c8e09668d50bd1657a253a0220b807a4d1f28Todor Kalaydjiev try { 3271c4ee29d168bf380054499201e6e7c262d53e4a7Todor Kalaydjiev if (options.outWidth > widthLimit || options.outHeight > heightLimit || 3281c4ee29d168bf380054499201e6e7c262d53e4a7Todor Kalaydjiev (os != null && os.size() > byteLimit)) { 3291cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor // The decoder does not support the inSampleSize option. 3301cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor // Scale the bitmap using Bitmap library. 3318c86a52a2c13083a25761256ab0dfc416260c162Tom Taylor int scaledWidth = (int)(outWidth * scaleFactor); 3328c86a52a2c13083a25761256ab0dfc416260c162Tom Taylor int scaledHeight = (int)(outHeight * scaleFactor); 3339242286c35743422051d439d7460cd0a1426899cWei Huang 3349242286c35743422051d439d7460cd0a1426899cWei Huang if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) { 3351cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor Log.v(TAG, "getResizedImageData: retry scaling using " + 3361cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor "Bitmap.createScaledBitmap: w=" + scaledWidth + 3371cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor ", h=" + scaledHeight); 3389242286c35743422051d439d7460cd0a1426899cWei Huang } 3399242286c35743422051d439d7460cd0a1426899cWei Huang 3408c86a52a2c13083a25761256ab0dfc416260c162Tom Taylor b = Bitmap.createScaledBitmap(b, scaledWidth, scaledHeight, false); 3411cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor if (b == null) { 34251e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) { 34351e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor Log.v(TAG, "Bitmap.createScaledBitmap returned NULL!"); 34451e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 3451cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor return null; 3461cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor } 347f79b803adc0cee3778cf6aac52d203896cde5d95Christian Gustafsson } 348f79b803adc0cee3778cf6aac52d203896cde5d95Christian Gustafsson 3491cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor // Compress the image into a JPG. Start with MessageUtils.IMAGE_COMPRESSION_QUALITY. 3501cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor // In case that the image byte size is still too large reduce the quality in 3516798ba71f8b01d382bdc83b7f40757aa89c280cdTodor Kalaydjiev // proportion to the desired byte size. 3521cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor os = new ByteArrayOutputStream(); 3531cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor b.compress(CompressFormat.JPEG, quality, os); 3541cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor int jpgFileSize = os.size(); 3551cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor if (jpgFileSize > byteLimit) { 3566798ba71f8b01d382bdc83b7f40757aa89c280cdTodor Kalaydjiev quality = (quality * byteLimit) / jpgFileSize; // watch for int division! 3571c4ee29d168bf380054499201e6e7c262d53e4a7Todor Kalaydjiev if (quality < MessageUtils.MINIMUM_IMAGE_COMPRESSION_QUALITY) { 3581c4ee29d168bf380054499201e6e7c262d53e4a7Todor Kalaydjiev quality = MessageUtils.MINIMUM_IMAGE_COMPRESSION_QUALITY; 3591c4ee29d168bf380054499201e6e7c262d53e4a7Todor Kalaydjiev } 3601cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor 3611c4ee29d168bf380054499201e6e7c262d53e4a7Todor Kalaydjiev if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) { 3621c4ee29d168bf380054499201e6e7c262d53e4a7Todor Kalaydjiev Log.v(TAG, "getResizedImageData: compress(2) w/ quality=" + quality); 3631cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor } 3641c4ee29d168bf380054499201e6e7c262d53e4a7Todor Kalaydjiev 3651c4ee29d168bf380054499201e6e7c262d53e4a7Todor Kalaydjiev os = new ByteArrayOutputStream(); 3661c4ee29d168bf380054499201e6e7c262d53e4a7Todor Kalaydjiev b.compress(CompressFormat.JPEG, quality, os); 3671cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor } 3681cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor } catch (java.lang.OutOfMemoryError e) { 3695a3151adedd991252dd529c75e85a3374970dfb0Tom Taylor Log.w(TAG, "getResizedImageData - image too big (OutOfMemoryError), will try " 3705a3151adedd991252dd529c75e85a3374970dfb0Tom Taylor + " with smaller scale factor, cur scale factor: " + scaleFactor); 3711cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor // fall through and keep trying with a smaller scale factor. 3721cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor } 3739242286c35743422051d439d7460cd0a1426899cWei Huang if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) { 374f79b803adc0cee3778cf6aac52d203896cde5d95Christian Gustafsson Log.v(TAG, "attempt=" + attempts 3751cf7f03f05cf0a1172f027f75f67a6fff336c79bTom Taylor + " size=" + (os == null ? 0 : os.size()) 3768c86a52a2c13083a25761256ab0dfc416260c162Tom Taylor + " width=" + outWidth * scaleFactor 3778c86a52a2c13083a25761256ab0dfc416260c162Tom Taylor + " height=" + outHeight * scaleFactor 378f79b803adc0cee3778cf6aac52d203896cde5d95Christian Gustafsson + " scaleFactor=" + scaleFactor 379f79b803adc0cee3778cf6aac52d203896cde5d95Christian Gustafsson + " quality=" + quality); 380f79b803adc0cee3778cf6aac52d203896cde5d95Christian Gustafsson } 3818c86a52a2c13083a25761256ab0dfc416260c162Tom Taylor scaleFactor *= .75F; 382f79b803adc0cee3778cf6aac52d203896cde5d95Christian Gustafsson attempts++; 383852b629e3be73f8eb01651f1868f3ed1857df815Tom Taylor resultTooBig = os == null || os.size() > byteLimit; 384852b629e3be73f8eb01651f1868f3ed1857df815Tom Taylor } while (resultTooBig && attempts < NUMBER_OF_RESIZE_ATTEMPTS); 385fa9be169b5a572e0e143e582079259ee074d9d5aTom Taylor b.recycle(); // done with the bitmap, release the memory 38651e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor if (Log.isLoggable(LogTag.APP, Log.VERBOSE) && resultTooBig) { 38751e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor Log.v(TAG, "getResizedImageData returning NULL because the result is too big: " + 388852b629e3be73f8eb01651f1868f3ed1857df815Tom Taylor " requested max: " + byteLimit + " actual: " + os.size()); 38951e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor } 39051e4621fa12400b1e79cc18b7bb0f9a83af6b622Tom Taylor 391852b629e3be73f8eb01651f1868f3ed1857df815Tom Taylor return resultTooBig ? null : os.toByteArray(); 39272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } catch (FileNotFoundException e) { 39372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project Log.e(TAG, e.getMessage(), e); 39472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project return null; 3950ca1428f36dce56a402e19d6b6c04c4c1cc1e69aTom Taylor } catch (java.lang.OutOfMemoryError e) { 3960ca1428f36dce56a402e19d6b6c04c4c1cc1e69aTom Taylor Log.e(TAG, e.getMessage(), e); 3970ca1428f36dce56a402e19d6b6c04c4c1cc1e69aTom Taylor return null; 39872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 39972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 40072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project} 401