66

画像をキャプチャしたいアプリケーションを作成し、その画像を電子メールで添付ファイルとして送信したいと考えています。

android.provider.MediaStore.ACTION_IMAGE_CAPTUREインテント アクションを使用してカメラを開き、ファイルの Uri をパラメーターとして渡してEXTRA_OUTPUT、画像をファイルに戻しています。external storage uriこれは完全に機能しており、 を使用するとキャプチャされた画像を取得できますEXTRA_OUTPUTが、データフォルダー uri を使用すると機能せず、カメラが閉じず、すべてのボタンが機能しません。

外部ストレージディレクトリで結果を取得するための私のコードは次のとおりです

Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
File out = Environment.getExternalStorageDirectory();
out = new File(out, imagename);
i.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(out));
startActivityForResult(i, CAMERA_RESULT);

そして、このコードは、データフォルダー内の画像を取得するためのものです

Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
File out = getFilesDir();
out = new File(out, MyPharmacyOptions.PRESCRIPTION_IMAGE_NAME);
i.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(out));
startActivityForResult(i, CAMERA_RESULT);

3 番目のアプリケーションがデータ フォルダーにアクセスできないことはわかっていたので、これが問題を引き起こす可能性があるため、ファイルを共有するコンテンツ プロバイダーを 1 つ作成しました。

これが私のコンテンツ提供クラスです

public class MyContentProvider extends ContentProvider {
    private static final String Tag = RingtonContentProvider.class.getName();
    public static final Uri CONTENT_URI = Uri
            .parse("content://x.y.z/");
    private static final HashMap<String, String> MIME_TYPES = new HashMap<String, String>();

    static {
        MIME_TYPES.put(".mp3", "audio/mp3");
        MIME_TYPES.put(".wav", "audio/mp3");
        MIME_TYPES.put(".jpg", "image/jpeg");
    }

    @Override
    public boolean onCreate() {
        return true;
    }

    @Override
    public String getType(Uri uri) {
        String path = uri.toString();

        for (String extension : MIME_TYPES.keySet()) {
            if (path.endsWith(extension)) {
                return (MIME_TYPES.get(extension));
            }
        }

        return (null);
    }

    @Override
    public ParcelFileDescriptor openFile(Uri uri, String mode)
            throws FileNotFoundException {
        File f = new File(getContext().getFilesDir(), uri.getPath());

        if (f.exists()) {
            return (ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY));
        }

        throw new FileNotFoundException(uri.getPath());
    }

    @Override
    public Cursor query(Uri url, String[] projection, String selection,
            String[] selectionArgs, String sort) {
        throw new RuntimeException("Operation not supported");
    }

    @Override
    public Uri insert(Uri uri, ContentValues initialValues) {
        File file = new File(getContext().getFilesDir(), uri.getPath());
        if(file.exists()) file.delete();
        try {
            file.createNewFile();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return Uri.fromFile(file);
    }

    @Override
    public int update(Uri uri, ContentValues values, String where,
            String[] whereArgs) {
        throw new RuntimeException("Operation not supported");
    }

    @Override
    public int delete(Uri uri, String where, String[] whereArgs) {
        File f = new File(getContext().getFilesDir(), "image1.jpg");
        if(f.exists()) f.delete();
        f = new File(getContext().getFilesDir(), "image2.jpg");
        if(f.exists()) f.delete();

        getContext().getContentResolver().notifyChange(CONTENT_URI, null);

    }
}

したがって、このコンテンツ プロバイダーを使用するには、次のコードを使用して uri をカメラ アクティビティに渡します。

Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
Uri uri = MyContentProvider.CONTENT_URI;
uri = Uri.withAppendedPath(uri, imagename);
getContentResolver().insert(uri, null);
getContentResolver().notifyChange(RingtonContentProvider.CONTENT_URI, null);
Log.d(Tag, uri.toString());
i.putExtra(MediaStore.EXTRA_OUTPUT, uri);

startActivityForResult(i, CAMERA_RESULT);

ここで、外部ストレージ ディレクトリ以外の URL を渡すと、カメラは開いていますが、エミュレータでは閉じていませんが、デバイスではカメラが閉じようとしていますが、結果が得られません。

マニフェスト ファイルでこのコンテンツ プロバイダーを宣言しました

<provider
android:name=".contentproviders.MyContentProvider"
android:authorities="x.y.z" />

また、外部ストレージへの書き込みとカメラの使用も許可しています。

外部ストレージを使用して画像をキャプチャすることはできますが、外部ストレージが使用できない場合に画像をキャプチャしてメールを送信したいため、外部ストレージではなくデータディレクトリに画像を保存したいと考えています。

コンテンツ プロバイダーを作成すると、イメージを電子メール アプリケーションに共有することもできます。

カメラの意図でエクストラを提供しない場合、アクティビティ結果のバイト[]として画像をデータエクストラとして返しますが、これはサムネイルのためであるため、この方法を使用して高解像度の画像を取得することはできません.

4

6 に答える 6

71

この問題を解決するには 2 つの方法があります。

1. onActivityResult メソッドで受け取ったビットマップを保存

以下のコードを使用して、写真をキャプチャする目的でカメラを起動できます

Intent cameraIntent=new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, CAMERA_REQUEST);

写真をキャプチャした後、 onActivityResult メソッドでビットマップを取得します

if (requestCode == CAMERA_REQUEST) {  
    Bitmap photo = (Bitmap) data.getExtras().get("data"); 
 }

これで、このビットマップを内部ストレージに簡単に保存できます

注: ここでビットマップ オブジェクトはサム イメージで構成されており、フル解像度のイメージはありません。

2. コンテンツ プロバイダーを使用してビットマップを内部ストレージに直接保存する

ここでは、コンテンツ プロバイダー クラスを作成して、カメラ アクティビティに対するローカル ストレージ ディレクトリの許可を許可します。

以下のサンプルプロバイダーの例

public class MyFileContentProvider extends ContentProvider {
    public static final Uri CONTENT_URI = Uri.parse
                                    ("content://com.example.camerademo/");
    private static final HashMap<String, String> MIME_TYPES = 
                                     new HashMap<String, String>();

    static {
        MIME_TYPES.put(".jpg", "image/jpeg");
        MIME_TYPES.put(".jpeg", "image/jpeg");
    }

    @Override
    public boolean onCreate() {

        try {
            File mFile = new File(getContext().getFilesDir(), "newImage.jpg");
            if(!mFile.exists()) {
                mFile.createNewFile();
            }
            getContext().getContentResolver().notifyChange(CONTENT_URI, null);
            return (true);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }

    @Override
    public String getType(Uri uri) {
        String path = uri.toString();

        for (String extension : MIME_TYPES.keySet()) {
            if (path.endsWith(extension)) {
                return (MIME_TYPES.get(extension));
            }
        }
        return (null);
    }

    @Override
    public ParcelFileDescriptor openFile(Uri uri, String mode)
    throws FileNotFoundException {

        File f = new File(getContext().getFilesDir(), "newImage.jpg");
        if (f.exists()) {
            return (ParcelFileDescriptor.open(f,
                    ParcelFileDescriptor.MODE_READ_WRITE));
        }
        throw new FileNotFoundException(uri.getPath());
    }
}

その後、URI を使用して、以下のコードを使用してカメラ アクティビティに渡すことができます。

Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
i.putExtra(MediaStore.EXTRA_OUTPUT, MyFileContentProvider.CONTENT_URI);
startActivityForResult(i, CAMERA_RESULT);

独自のプロバイダーを作成したくない場合は、support-library-v4 のFileProviderを使用できます。詳細なヘルプについては、この投稿をご覧ください

于 2012-04-19T13:34:22.847 に答える
5

写真を撮るために電話するつもり、

Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);  
startActivityForResult(cameraIntent, CAMERA_REQUEST);  

次に、ビットマップを取り込みますActivityResult

 if (requestCode == CAMERA_REQUEST) {   
            Bitmap photo = (Bitmap) data.getExtras().get("data");  
 }   

次に、それを内部メモリに書き込みます。これを参照してください

// The openfileOutput() method creates a file on the phone/internal storage in the context of your application  
final FileOutputStream fos = openFileOutput("my_new_image.jpg", Context.MODE_PRIVATE); 

// Use the compress method on the BitMap object to write image to the OutputStream 
bm.compress(CompressFormat.JPEG, 90, fos); 

次にそのファイルを読み取るときは、

Bitmap bitmap = BitmapFactory.decodeFile(file); 
于 2012-04-18T12:51:45.647 に答える
3

まずは来た写真を外部ストレージに保存して試してみてください。

@Override
public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.main);
   this.imageView = (ImageView)this.findViewById(R.id.imageView1);
   Button photoButton = (Button) this.findViewById(R.id.button1);
   photoButton.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View v) {
        Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); 
        startActivityForResult(cameraIntent, CAMERA_REQUEST); 
    }
});
}

protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
   if (requestCode == CAMERA_REQUEST) {  
        Bitmap bmp = intent.getExtras().get("data");
        ByteArrayOutputStream stream = new ByteArrayOutputStream();

         bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
         byte[] byteArray = stream.toByteArray(); // convert camera photo to byte array

         // save it in your external storage.
        FileOutputStream fo = new FileOutputStream(new File(Environment.getExternalStorageDirectory() + "/_camera.png"));

        fo.write(byteArray);
        fo.flush();
        fo.close();
   }  
} 

次のターゲット -

File cameraFile = new File(Environment.getExternalStorageDirectory() + "/_camera.png");                 
startActivityForResult(Intent.createChooser(new Intent(Intent.ACTION_SEND)
        .setType("image/jpg")
        .putExtra(Intent.EXTRA_SUBJECT, "Subject")
        .putExtra(Intent.EXTRA_STREAM, Uri.fromFile(cameraFile))
        .putExtra(Intent.EXTRA_TEXT, textBody), "Send your message using"), Constant.EMAIL);
于 2012-04-06T11:35:56.480 に答える
1

このバグをしばらく調査した結果、カメラ インテントを呼び出したアクティビティは、電話のメモリが不足している場合にのみ再開されることに気付きました。アクティビティが再開されるため、キャプチャされた画像へのパスまたは Uri を保持するオブジェクトが更新 (null) されます。

そのため、onActivityResult で null オブジェクトをキャッチ/検出し、ユーザーにデバイスのスペースを解放するか、電話を再起動して一時的な修正を迅速に行うことをお勧めします。

于 2015-10-14T16:01:22.593 に答える