Comment obtenir le résultat de la caméra en tant qu'uri dans le dossier de données?

je crée une application dans laquelle je veux capturer une image et puis je veux envoyer cette image dans le courriel en pièce jointe.

j'ouvre une caméra en utilisant l'action android.provider.MediaStore.ACTION_IMAGE_CAPTURE et je passe L'Uri du fichier comme paramètre EXTRA_OUTPUT pour ramener l'image au fichier. Cela fonctionne parfaitement, et je suis en mesure d'obtenir l'image capturée si j'utilise le external storage uri comme un EXTRA_OUTPUT mais si j'utilise le dossier data uri, elle n'est pas de travail et la caméra ne se ferme pas et tous les boutons ne fonctionnent pas.

Voici mon code pour obtenir le résultat dans le répertoire de stockage externe

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);

Et ce code est pour obtenir l'image dans le dossier de données

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);

je savais que le dossier de données n'est pas accessible à la troisième application donc cela peut causer un problème donc j'ai créé un fournisseur de contenu pour partager le fichier.

Voici mon contenu fournir la classe

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);

    }
}

donc pour utiliser ce contenu fournir que j'utilise le code suivant pour passer l'uri à l'activité de caméra

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);

maintenant si je passe l'url autre que le répertoire de stockage externe la caméra s'ouvre mais ne se ferme pas dans l'émulateur mais dans l'appareil la caméra va se fermer mais je ne reçois pas le résultat.

j'ai déclaré ce contenu fournir dans le manifeste

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

Aussi, j'ai donné l'autorisation écrire le stockage externe et aussi pour utilisation de la caméra .

je suis capable de capturer l'image en utilisant le stockage externe, mais je veux stocker l'image dans le répertoire de données au lieu du stockage externe parce que si le stockage externe n'est pas disponible, je veux capturer l'image et je veux envoyer du courrier.

si je crée le contenu provide puis je peux également partager mon image à l'application de courrier électronique.

si nous ne fournissons pas les extras avec l'intention de caméra il retournera l'image comme un octet[] dans le résultat de l'activité comme un extra de données, mais c'est pour le but de la vignette donc je ne peux pas obtenir l'image de haute résolution en utilisant cette façon.

63
demandé sur CopsOnRoad 2012-04-06 15:15:11

6 réponses

Il y a deux façons de résoudre ce problème.

1. Enregistrer bitmap que vous avez reçu de la méthode onActivityResult

vous pouvez démarrer l'appareil photo par intention de capturer la photo en utilisant le code ci-dessous

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

après la photo de capture, vous obtiendrez bitmap dans la méthode onActivityResult

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

maintenant vous pouvez simplement sauvegarder ce bitmap dans le stockage interne

Note: ici l'objet bitmap se compose d'une image de pouce, il n'aura pas une image de pleine résolution

2. Enregistrer bitmap directement dans le stockage interne en utilisant le fournisseur de contenu

ici, nous allons créer la classe de fournisseur de contenu pour permettre l'Autorisation du répertoire de stockage local à l'activité de caméra

exemple de fournisseur D'échantillon selon ci-dessous

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());
    }
}

après que vous pouvez simplement utiliser L'URI pour passer à l'activité de caméra en utilisant le code ci-dessous

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

Si vous ne voulez pas créer votre propre fournisseur, vous pouvez utiliser FileProvider de soutien-bibliothèque-v4. Pour une aide détaillée, vous pouvez regarder dans ce post

66
répondu Dharmendra 2017-05-23 11:47:20

la meilleure solution que j'ai trouvée est: FileProvider (needs support-library-v4) Il utilise le stockage interne! https://developer.android.com/reference/android/support/v4/content/FileProvider.html

  1. Définissez votre FileProvider dans le Manifeste de l'élément de la demande:

    <provider
          android:name="android.support.v4.content.FileProvider"
          android:authorities="your.package.name.fileprovider"
          android:exported="false"
          android:grantUriPermissions="true" >
          <meta-data
                     android:name="android.support.FILE_PROVIDER_PATHS"
                     android:resource="@xml/image_path" />
    </provider>
    
  2. ajouter les permissions dans l'élément racine manifeste:

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" android:required="false" />
    
  3. Définissez vos chemins d'image dans par exemple res/xml/image_path.xml:

    <paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="captured_image" path="your/path/"/>
    </paths>
    
  4. Java:

    private static final int IMAGE_REQUEST_CODE = 1;
    // your authority, must be the same as in your manifest file 
    private static final String CAPTURE_IMAGE_FILE_PROVIDER = "your.package.name.fileprovider";
    

4.1 intention de capture:

    File path = new File(activity.getFilesDir(), "your/path");
    if (!path.exists()) path.mkdirs();
    File image = new File(path, "image.jpg");
    Uri imageUri = FileProvider.getUriForFile(activity, CAPTURE_IMAGE_FILE_PROVIDER, image);
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
    startActivityForResult(intent, IMAGE_REQUEST_CODE);

4.2 onActivityResult ():

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
        if (requestCode == IMAGE_REQUEST_CODE) {
            if (resultCode == Activity.RESULT_OK) {
                File path = new File(getFilesDir(), "your/path");
                if (!path.exists()) path.mkdirs();
                File imageFile = new File(path, "image.jpg");
                // use imageFile to open your image
            }
        }
        super.onActivityResult(requestCode, resultCode, intent);
    }
18
répondu Harry 2015-10-07 20:41:54

intention d'appeler pour capturer la photo,

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

puis prendre Bitmap dans ActivityResult

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

alors écrivez cela dans la mémoire interne, voir ce

// 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); 

puis la prochaine fois pour lire ce fichier,

Bitmap bitmap = BitmapFactory.decodeFile(file); 
5
répondu MKJParekh 2017-05-23 11:54:58

d'abord save est venu photo dans votre stockage externe et essayer -

@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();
   }  
} 

à Côté de la cible

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);
3
répondu Suvam Roy 2012-04-06 11:35:56

vous pouvez également le faire sans avoir besoin d'un fournisseur de contenu puisque vous aurez besoin de la carte sd pour ouvrir l'objectif de capture d'image de la caméra de toute façon. Vous pouvez bien sûr contourner la présence de la carte sd mais pas avec la caméra de capture d'intention....Vous vérifiez donc le stockage externe, mais vous en avez besoin à ce stade.... FYI vous devriez également vérifier une bibliothèque de récolte comme crop-image au lieu d'utiliser natif, car il n'est pas bien supporté à travers les appareils.

File mediaStorageDir;
String photoFileName = "photo.jpg";


    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // page = getArguments().getInt("someInt", 0);
    // title = getArguments().getString("someTitle");
    // Get safe storage directory for photos
        mediaStorageDir = new File(
                Environment                          .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
                APP_TAG);
        // Create the storage directory if it does not exist
        if (!mediaStorageDir.exists() && !mediaStorageDir.mkdirs()) {
            Log.d(APP_TAG, "Directory exists: " + mediaStorageDir.isDirectory());
            Log.d(APP_TAG, "Directory exists: " + mediaStorageDir.getPath());
            Log.d(APP_TAG,
                    "Directory exists: "
                            + Environment.getExternalStorageState());
            Log.d(APP_TAG, "failed to create directory");
        }

}

in votre code 'take the pic':

            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, getPhotoFileUri(photoFileName));

...

public Uri getPhotoFileUri(String fileName) {

    return Uri.fromFile(new File(mediaStorageDir.getPath() + File.separator
            + fileName));
}
1
répondu Droid Teahouse 2014-11-13 00:41:46

après avoir fait des recherches sur ce bug pendant un certain temps, j'ai remarqué que l'activité qui a appelé l'intention de l'appareil photo n'est relancée que lorsque le téléphone est en panne de mémoire. ainsi, parce que l'activité est redémarrée, l'objet tenant le chemin ou L'Uri vers l'image capturée est rafraîchi (nulled)

donc je vous suggérerais d'attraper / détecter l'objet nul dans le résultat onActivityResult, et d'inviter l'utilisateur à libérer de l'espace sur leur appareil ou redémarrer leur téléphone pour un rapide temporaire fixer.

0
répondu kc ochibili 2015-10-14 16:01:22