web-dev-qa-db-fra.com

Comment obtenir le résultat de la caméra sous la forme d'un uri dans un dossier de données?

Je crée une application dans laquelle je veux capturer une image, puis je veux l'envoyer en pièce jointe dans le courrier électronique.

J'ouvre une caméra en utilisant l'action Android.provider.MediaStore.ACTION_IMAGE_CAPTURE intentionnelle et je passe l'URI du fichier en tant que paramètre EXTRA_OUTPUT pour que l'image soit renvoyée dans le fichier. Cela fonctionne parfaitement et je peux obtenir l'image capturée si j'utilise le external storage uri en tant que EXTRA_OUTPUT, mais si j'utilise le dossier de données uri, il ne fonctionne pas, l'appareil photo ne se ferme pas et tous ses 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 data n'était pas accessible à une troisième application il en est peut-être ainsi qui pose un problème. J'ai donc 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, utilisez le code suivant pour transmettre l'uri à l'activité de l'appareil photo.

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 est en train de s’ouvrir mais elle ne se ferme pas dans l’émulateur mais dans le périphérique, la caméra va se fermer mais je n’obtiens pas le résultat.

J'ai déclaré ce contenu à fournir dans le fichier manifeste 

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

Aussi, j'ai donné la permission de écrire le stockage externe et aussi pour utiliser l'appareil photo .

Je suis en mesure de capturer l'image à l'aide du stockage externe, mais je souhaite stocker l'image dans le répertoire de données plutôt que dans le stockage externe, car si le stockage externe n'est pas disponible, je souhaite capturer l'image et envoyer du courrier.

Si je crée du contenu, je peux également partager mon image avec l'application de messagerie.

Si nous ne fournissons pas les extras avec l'objectif de la caméra, l'image renvoyée sera sous forme d'octet [] dans le résultat de l'activité, mais ceci est destiné à la vignette, je ne peux donc pas obtenir l'image haute résolution avec par ici.

64
Dharmendra

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

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

Vous pouvez démarrer la caméra par l’intention de capturer une photo en utilisant le code ci-dessous.

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

Après la capture de la photo, vous obtiendrez une image bitmap dans la méthode onActivityResult

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

Maintenant, vous pouvez simplement sauvegarder cette image dans la mémoire interne

Remarque: ici, l’objet bitmap consiste en une image miniature, il n’aura pas d’image en pleine résolution

2. Enregistrez le bitmap directement sur le stockage interne à l'aide du fournisseur de contenu

Ici, nous allons créer une classe de fournisseur de contenu pour autoriser l’activité de la caméra du répertoire de stockage local.

Exemple de fournisseur comme 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 cela, vous pouvez simplement utiliser l’URI pour passer à l’activité 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 support-library-v4. Pour une aide détaillée, vous pouvez consulter cet article

67
Dharmendra

La meilleure solution que j'ai trouvée est: FileProvider (nécessite support-library-v4) Il utilise la mémoire de stockage interne! https://developer.Android.com/reference/Android/support/v4/content/ FileProvider.html

  1. Définissez votre FileProvider dans l'élément Manifest dans l'application:

    <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 des autorisations dans l'élément racine du 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
Harry

Intention d'appeler pour capturer une photo,

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

Puis prenez Bitmap dans ActivityResult 

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

Puis écrivez cela dans la mémoire interne, voir ceci

// 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
MKJParekh

Au début sauvegarder la photo dans votre stockage externe et essayez-le -

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

Cible suivante - 

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
Suvam Roy

Vous pouvez également le faire sans faire appel à un fournisseur de contenu, car vous aurez quand même besoin de la carte SD pour ouvrir l’intention de capture d’image de la caméra. Vous pouvez bien sûr contourner la présence de la carte SD mais pas avec la capture d’intention de la caméra .... Donc, vous vérifiez le stockage externe mais vous en avez besoin à ce stade ... crop-image au lieu d'utiliser native, car il n'est pas bien pris en charge sur tous 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");
        }

}

dans votre code "prenez la photo":

            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
Droid Teahouse

Après avoir recherché ce bogue pendant un certain temps, j'ai remarqué que l'activité appelée Intention de la caméra ne redémarre que lorsque le téléphone manque de mémoire .. C'est pourquoi l'activité a été relancée. l'image capturée est actualisée (annulée)

je vous suggère donc de capturer/détecter l'objet null dans onActivityResult et de demander à l'utilisateur de libérer de l'espace sur son appareil ou de redémarrer son téléphone pour une correction temporaire rapide.

0
kc ochibili