- Android OS 2.3.6
- Galaxy S
動かない端末あるんだろうなぁとか思いつつもとりあえず動いたので公開。
トリミングの方法なんだけど、デフォルトのトリミングアプリがあるらしく、それを使ってみた。
ギャラリーから Picasa の画像選んだらなんか落ちそうだけど検証してない。
不具合あったら教えて下さい。
AndroidManifest.xml
android:configChanges="keyboardHidden|orientation"がキモ?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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 が再生成されるようです。以下が修正版です。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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> |
※2013/01/30 21:41 追記
そもそも間違っていました・・・・。
http://slumbers99.blogspot.jp/2013/01/android.html に追記という形で書きました。
layout/activity_main.xml
レイアウトXMLとくにこれと言ってなし。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- 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 とくにこれと言ってなし。ExternalAppOpener.java
外部アプリ(カメラ、ギャラリー、クロップ)を開く。ContentResolver を使ってUriを保存。それらを参照する。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* | |
*/ | |
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() でわざわざ別に書きだしたのは、
このあとフィルターかけたりするため。
カメラで撮った画像だったらいいけど、ギャラリーから選択したものに、上書き保存しちゃったらアレだと思ったのです・・・・。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |