8

次のように、画像を切り抜くコードがあります。

public void doCrop(){
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setType("image/");
List<ResolveInfo> list = getPackageManager().queryIntentActivities(intent,0);
int size = list.size();
if (size == 0 ){
   Toast.makeText(this, "Cant find crop app").show();
   return;
} else{
   intent.setData(selectImageUri);
   intent.putExtra("outputX", 300);
   intent.putExtra("outputY", 300);
   intent.putExtra("aspectX", 1);
   intent.putExtra("aspectY", 1);
   intent.putExtra("scale", true);
   intent.putExtra("return-data", true);
   if (size == 1) {
       Intent i = new Intent(intent);
       ResolveInfo res = list.get(0);
       i.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
       startActivityForResult(i, CROP_RESULT);
   }
}
}

public void onActivityResult (int requestCode, int resultCode, Intent dara){
   if (resultCode == RESULT_OK){
      if (requestCode == CROP_RESULT){
          Bundle extras = data.getExtras();
          if (extras != null){
              bmp = extras.getParcelable("data");
          }
          File f = new File(selectImageUri.getPath());
          if (f.exists()) f.delete();
          Intent inten3 = new Intent(this, tabActivity.class);
          startActivity(inten3);
      }
   }
}

私が読んだものから、コードintent.putExtra("outputX", 300); intent.putExtra("outputY", 300);はトリミング結果の解像度を設定するために使用されていますが、なぜ300x300よりも高い結果画像解像度を取得できないのですか?切り抜き関数を設定しintent.putExtra("outputX", 800); intent.putExtra("outputY", 800);ても結果やクラッシュは発生しませんが、この状況について何か考えはありますか?

ログ猫は「!!!バインダートランザクションに失敗しました!!!」と言います。

4

2 に答える 2

29

この質問は、stackoverflow全体にあります。そして、最近自分でこれを整理しなければならなかったので、それはうれしいです。私は行くにつれていくつかの重複をマークするために最善を尽くしますが、限られた画像サイズの問題に対処するので、これを好みます。

短い答え

簡単な答えは、return-dataオプションを使用しないことです。そのオプションと画像を取得する方法の詳細については、http ://www.androidworks.com/crop_large_photos_with_androidをご覧ください。この記事は、インテントの(既知の)構成オプションとその使用方法をリストした素晴らしい仕事をしています。

オプション#2:return-dataを "false"に設定すると、onActivityResult Intentインラインからビットマップを受信しなくなります。代わりに、MediaStore.EXTRA_OUTPUTを(ファイルスキームのみの)URIに設定する必要があります。ビットマップを保存する必要があります。これにはいくつかの制限があります。最初に、ファイルスキームURIを指定するために、一時ファイルシステムの場所が必要です。大きな問題ではありません(sdcardがない一部のデバイスを除く)。

    /** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    thiz = this;
    setContentView(R.layout.main);
    mBtn = (Button) findViewById(R.id.btnLaunch);
    photo = (ImageView) findViewById(R.id.imgPhoto);
    mBtn.setOnClickListener(new OnClickListener(){

        public void onClick(View v) {
            try {
                // Launch picker to choose photo for selected contact
                Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
                intent.setType("image/*");
                intent.putExtra("crop", "true");
                intent.putExtra("aspectX", aspectX);
                intent.putExtra("aspectY", aspectY);
                intent.putExtra("outputX", outputX);
                intent.putExtra("outputY", outputY);
                intent.putExtra("scale", scale);
                intent.putExtra("return-data", return_data);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, getTempUri());
                intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
                intent.putExtra("noFaceDetection",!faceDetection); // lol, negative boolean noFaceDetection
                if (circleCrop) {
                    intent.putExtra("circleCrop", true);
                }

                startActivityForResult(intent, PHOTO_PICKED);
            } catch (ActivityNotFoundException e) {
                Toast.makeText(thiz, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show();
            }
        }
    });
}

private Uri getTempUri() {
    return Uri.fromFile(getTempFile());
}

private File getTempFile() {
    if (isSDCARDMounted()) {
        File f = new File(Environment.getExternalStorageDirectory(),TEMP_PHOTO_FILE);
        try {
            f.createNewFile();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            Toast.makeText(thiz, R.string.fileIOIssue, Toast.LENGTH_LONG).show();
        }
        return f;
    } else {
        return null;
    }
}

private boolean isSDCARDMounted(){
    String status = Environment.getExternalStorageState();    
    if (status.equals(Environment.MEDIA_MOUNTED))
        return true;
    return false;
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    switch (requestCode) {
        case PHOTO_PICKED:
            if (resultCode == RESULT_OK) {
                if (data == null) {
                    Log.w(TAG, "Null data, but RESULT_OK, from image picker!");
                    Toast.makeText(this, R.string.no_photo_picked,
Toast.LENGTH_SHORT).show();
                    return;
                }

            final Bundle extras = data.getExtras();
            if (extras != null) {
                File tempFile = getTempFile();
                // new logic to get the photo from a URI
                if (data.getAction() != null) {
                    processPhotoUpdate(tempFile);
                }
            }
        }
        break;
    }
}

コード例:http ://www.androidworks.com/crop_large_photos_with_android

詳しくは

長い答えは、その意図をまったく使用しないことです。理由を見つけるために読み続けてください。

非公式API

問題の核心は非公式の意図です。パブリックAPIの一部ではないため非公式。現在、ほとんどのデバイスで機能しますが、ほとんどのデバイスでは十分ではありません。また、Googleはあなたに通知することなくいつでもこの意図を変更することができます。それを使用してすべてのアプリを壊します。カレンダーAPIがかつて非公式だったのと同じように。実際、この作物の意図はすでに一度変わっています。したがって、このインテントの使用は避けてください。選択肢があります。このアドバイスは無視してかまいません。

「一部のデバイスで動作するステートメント」を証明するために、このリンクをたどって、Androidのコア機能の一部と見なす必要があるもの(そうでないもの)について話し合う欲求不満のAndroid開発者をお楽しみください:https ://code.google.com/p/android / issues / detail?id = 1480

コードの例の時間?このgithubプロジェクトを確認してください:https ://github.com/lorensiuswlt/AndroidImageCrop

サイズ制限について

この意図を探求しているときに私が経験したもう1つの問題は、画像のトリミングサイズの制限です。これは、上記のサンプルコードと300ピクセルを超える画像サイズを使用して簡単に再現できます。基本的に、この元の質問はすべてについてです。最良の場合、アプリはクラッシュします。しかし、バッテリーを取り外すことによってのみリセットできるデバイスがぶら下がっているところまで悪化しました。

これで、その「return-data」オプションを削除すると、再度実行できるようになります。結果を得る方法の詳細は、私がすでにこのリンクを参照した短い回答にあります:http ://www.androidworks.com/crop_large_photos_with_android

ソリューション

だから多くの問題。問題には解決策が必要です。GoogleがこのためのパブリックAPIを思い付くまでの唯一の適切な解決策は、独自の作物の意図を提供することです。githubでこのような適切な作物ライブラリを手に入れてください:https ://github.com/lvillani/android-cropimage

プロジェクトにはいくつかのドキュメントがありませんが、非公式のAndroidトリミングインテントの抜粋であるため、上にリストされている例を使用して開始できます。return-dataオプションを使用しないように注意してください。ああ、CropImageIntentBuilderクラスをチェックしてください。これにより、トリミングのインテントを簡単に作成できるようになります。このアクティビティをマニフェストに追加し、外部データストレージに書き込むためのアクセス許可を追加することを忘れないでください。

private void doCrop(File croppedResult){
        CropImageIntentBuilder builder = new CropImageIntentBuilder(600,600, croppedResult);
        // don't forget this, the error handling within the library is just ignoring if you do
        builder.setSourceImage(mImageCaptureUri);
        Intent  intent = builder.getIntent(getApplicationContext());
        // do not use return data for big images
        intent.putExtra("return-data", false);
        // start an activity and then get the result back in onActivtyResult
        startActivityForResult(intent, CROP_FROM_CAMERA);
    }

このライブラリを使用すると、さらにカスタマイズできるようになります。コアビットマップはサイズ変更に機能的に使用されていることを知っておくとよいでしょう:Androidで解析された画像をトリミングする方法は?

以上です。楽しみ!

于 2013-04-17T09:08:28.607 に答える
8

そのインテントはパブリックAndroidAPIの一部ではなく、すべてのデバイスで機能することが保証されているわけではありません。以前のバージョンのandroid1.xおよび2.xで使用されていましたが、現在は使用されていないため、お勧めしません。それがおそらく、それが場所全体でクラッシュしたり、不適切に動作したりする理由です。

Bitmap.createBitmap(..)またはなどの方法を使用Bitmap.createScaledBitmap(..)して、元の画像のサイズ変更またはトリミングされたバージョンを作成します。これらはAndroidAPIの一部であり、動作が保証されています。

ここここの公式ドキュメントを参照してください

ビットマップを切り抜くには、を使用できますBitmap.createBitmap(Bitmap, int x, int y, int width, int height)。たとえば、ビットマップの両側から10ピクセルをトリミングする必要がある場合は、次を使用します。

Bitmap croppedBitmap = Bitmap.createBitmap(originalBitmap, 10, 10, originalBitmap.getWidth() - 20, originalBitmap.getHeight() - 20);

セレクターをユーザーに表示する必要がある場合。次に、次のようなことを行うことができます。

private static final String TEMP_PHOTO_FILE = "temporary_holder.jpg";  

Intent photoPickerIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
photoPickerIntent.setType("image/*");
photoPickerIntent.putExtra("crop", "true");
photoPickerIntent.putExtra(MediaStore.EXTRA_OUTPUT, getTempUri());
photoPickerIntent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
startActivityForResult(photoPickerIntent, REQ_CODE_PICK_IMAGE);


    private Uri getTempUri() {
    return Uri.fromFile(getTempFile());
    }

    private File getTempFile() {
    if (isSDCARDMounted()) {

    File f = new File(Environment.getExternalStorageDirectory(),TEMP_PHOTO_FILE);
    try {
    f.createNewFile();
    } catch (IOException e) {

    }
    return f;
    } else {
    return null;
    }
    }

    private boolean isSDCARDMounted(){
    String status = Environment.getExternalStorageState();
    if (status.equals(Environment.MEDIA_MOUNTED))
    return true;
    return false;
    }




protected void onActivityResult(int requestCode, int resultCode,
        Intent imageReturnedIntent) {
    super.onActivityResult(requestCode, resultCode, imageReturnedIntent);

    switch (requestCode) {
    case REQ_CODE_PICK_IMAGE:
        if (resultCode == RESULT_OK) {  
          if (imageReturnedIntent!=null){



               File tempFile = getTempFile();

              String filePath= Environment.getExternalStorageDirectory()
            + "/temporary_holder.jpg";
              System.out.println("path "+filePath);


    Bitmap selectedImage =  BitmapFactory.decodeFile(filePath);
    _image = (ImageView) findViewById(R.id.image);
    _image.setImageBitmap(selectedImage );

}
}
}

ここからのコード

于 2012-10-06T10:04:03.500 に答える