2012/08/20

Android でカメラかギャラリーから画像を読み込んでトリミングして表示するサンプル

  • Android OS 2.3.6
  • Galaxy S
での動作。
動かない端末あるんだろうなぁとか思いつつもとりあえず動いたので公開。
トリミングの方法なんだけど、デフォルトのトリミングアプリがあるらしく、それを使ってみた。

ギャラリーから Picasa の画像選んだらなんか落ちそうだけど検証してない。
不具合あったら教えて下さい。


AndroidManifest.xml

android:configChanges="keyboardHidden|orientation"がキモ?
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="me.sotm.practice.camera"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:configChanges="keyboardHidden|orientation"
android:label="@string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

※2013/01/29 22:23 追記
上記の android:configChanges だと端末及び、API level によって Activity が再生成されるようです。以下が修正版です。
<activity
android:name=".MainActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:screenOrientation="portrait"
android:label="@string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
view raw gistfile1.xml hosted with ❤ by GitHub


※2013/01/30 21:41 追記
そもそも間違っていました・・・・。
http://slumbers99.blogspot.jp/2013/01/android.html に追記という形で書きました。

layout/activity_main.xml

レイアウトXMLとくにこれと言ってなし。
<!-- layout/activity_main.xml -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:padding="@dimen/padding_medium"
android:text="@string/please_select"
tools:context=".MainActivity" />
<ImageView
android:id="@+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:contentDescription="@null"
android:adjustViewBounds="true"
tools:context=".MainActivity" />
</RelativeLayout>


menu/activity_main.xml

メニューの XML とくにこれと言ってなし。
<!-- menu/activity_main.xml -->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/menu_camera"
android:title="@string/menu_camera"
android:orderInCategory="100"
android:showAsAction="never" />
<item android:id="@+id/menu_gallery"
android:title="@string/menu_gallery"
android:orderInCategory="200"
android:showAsAction="never" />
</menu>


ExternalAppOpener.java

外部アプリ(カメラ、ギャラリー、クロップ)を開く。
ContentResolver を使ってUriを保存。それらを参照する。
/**
*
*/
package me.sotm.practice.camera;
import java.util.List;
import android.app.Activity;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.provider.MediaStore;
/**
*
*/
public class ExternalAppOpener {
public static final int REQUEST_GALLERY = 1;
public static final int REQUEST_CAMERA = 2;
public static final int REQUEST_CROP = 3;
private static final int _TRIMMING_X = 640;
private static final int _TRIMMING_Y = 640;
private static final int _ASPECT_X = 1;
private static final int _ASPECT_Y = 1;
/**
* ギャラリーを開く
*
* @param activity
*/
public static void openGallery(Activity activity) {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
activity.startActivityForResult(intent, ExternalAppOpener.REQUEST_GALLERY);
}
/**
* カメラアプリを開く
*
* @param activity
* @return
*/
public static Uri openCamera(Activity activity) {
Uri uri = null;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(System.currentTimeMillis());
stringBuilder.append(".jpg");
String fileName = stringBuilder.toString();
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, fileName);
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
ContentResolver contentResolver = activity.getContentResolver();
uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
Intent intent = new Intent();
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
activity.startActivityForResult(intent, ExternalAppOpener.REQUEST_CAMERA);
return uri;
}
/**
* 切り抜きのアプリを開く
*
*/
public static boolean openCrop(Activity activity, Uri uri) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setType("image/*");
List<ResolveInfo> resolveInfoList = activity.getPackageManager().queryIntentActivities(intent, 0);
int resolveInfoSize = resolveInfoList.size();
if (0 == resolveInfoSize) {
return false;
} else {
intent.setData(uri);
intent.putExtra("outputX", ExternalAppOpener._TRIMMING_X);
intent.putExtra("outputY", ExternalAppOpener._TRIMMING_Y);
intent.putExtra("aspectX", ExternalAppOpener._ASPECT_X);
intent.putExtra("aspectY", ExternalAppOpener._ASPECT_Y);
intent.putExtra("scale", true);
intent.putExtra("setWallpaper", false);
intent.putExtra("noFaceDetection", false);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
ResolveInfo resolveInfo = resolveInfoList.get(0);
String packageName = resolveInfo.activityInfo.packageName;
String name = resolveInfo.activityInfo.name;
intent.setComponent(new ComponentName(packageName, name));
activity.startActivityForResult(intent, ExternalAppOpener.REQUEST_CROP);
return true;
}
}
}


MainActivity.java

Activity。onActivityResult() でいろいろゴニョゴニョ。
_savePictureToExternalStrage() でわざわざ別に書きだしたのは、
このあとフィルターかけたりするため。
カメラで撮った画像だったらいいけど、ギャラリーから選択したものに、上書き保存しちゃったらアレだと思ったのです・・・・。
package me.sotm.practice.camera;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.BaseColumns;
import android.provider.MediaStore;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ImageView;
public class MainActivity extends Activity {
private ImageView _imageView;
private Uri _imageUri;
private Uri _cropedImageUri;
private String _saveDirectory;
/*
* (non-Javadoc)
*
* @see android.app.Activity#onCreate(android.os.Bundle)
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.activity_main);
this._imageView = (ImageView) this.findViewById(R.id.image_view);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES));
stringBuilder.append("/");
stringBuilder.append(this.getString(R.string.app_name));
this._saveDirectory = stringBuilder.toString();
}
/*
* (non-Javadoc)
*
* @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = this.getMenuInflater();
menuInflater.inflate(R.menu.activity_main, menu);
return true;
}
/*
* (non-Javadoc)
*
* @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
switch (itemId) {
case R.id.menu_camera:
this._imageUri = ExternalAppOpener.openCamera(this);
break;
case R.id.menu_gallery:
ExternalAppOpener.openGallery(this);
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
/*
* (non-Javadoc)
*
* @see android.app.Activity#onActivityResult(int, int,
* android.content.Intent)
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (Activity.RESULT_OK == resultCode) {
if (requestCode == ExternalAppOpener.REQUEST_GALLERY || requestCode == ExternalAppOpener.REQUEST_CAMERA) {
this._imageUri = this._getImageUri(data);
if (null != this._imageUri) {
this._cropedImageUri = this._savePictureToExternalStrage(this._imageUri);
ExternalAppOpener.openCrop(this, this._cropedImageUri);
}
} else if (requestCode == ExternalAppOpener.REQUEST_CROP) {
if (null != this._cropedImageUri) {
this._imageView.setImageURI(this._cropedImageUri);
}
}
}
}
/**
* 画像取得
*
* @param data
* @return
*/
private Uri _getImageUri(Intent data) {
Uri result = null;
if (null != data) {
result = data.getData();
} else if (null != this._imageUri) {
result = this._imageUri;
} else {
ContentResolver contentResolver = this.getContentResolver();
Cursor cursor = MediaStore.Images.Media.query(contentResolver, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null,
MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC");
cursor.moveToFirst();
String id = cursor.getString(cursor.getColumnIndexOrThrow(BaseColumns._ID));
result = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
}
return result;
}
/**
* クロップように外に書き出す
*
* @param sourceUri
* @return
*/
private Uri _savePictureToExternalStrage(Uri sourceUri) {
OutputStream outputStream = null;
InputStream inputStream = null;
ByteArrayOutputStream byteArrayOutputStream = null;
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
String fileName = simpleDateFormat.format(new Date()) + ".jpg";
String filePath = this._saveDirectory + "/" + fileName;
ContentResolver contentResolver = this.getContentResolver();
Uri uri = null;
try {
File dir = new File(this._saveDirectory);
if (!dir.exists()) {
dir.mkdir();
}
File file = new File(this._saveDirectory, fileName);
if (file.createNewFile()) {
outputStream = new FileOutputStream(file);
inputStream = contentResolver.openInputStream(sourceUri);
byteArrayOutputStream = new ByteArrayOutputStream();
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int len = 0;
while (inputStream.available() > 0 && (len = inputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, len);
}
outputStream.write(byteArrayOutputStream.toByteArray());
}
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, fileName);
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.Images.Media.DATA, filePath);
uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (Throwable t) {
t.printStackTrace();
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (Throwable t) {
t.printStackTrace();
}
}
if (byteArrayOutputStream != null) {
try {
byteArrayOutputStream.close();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
return uri;
}
}