Monthly Archives: Janeiro 2019

Tirar uma foto e gravar a imagem

Estive a fazer um programa em Java, para Android, que permite o utilizador tirar uma foto e gravá-la no dispositivo.

Como em todos os projetos, surgiram muitos percalços, mas o mais complexo foi a dificuldade em gravar a foto.

O erro que surgia era o seguinte:

FileProvider - IllegalArgumentException: Failed to find configured root

E, aparentemente, tinha a ver com uma falta de permissões para escrever na diretoria pretendida, embora eu tenha feito tudo exatamente como estava indicado nos exemplos do Android developers.

Basicamente pode fazer-se tudo como está indicado no site do Android, exceto o conteúdo do ficheiro file_paths.xml, que deve ser alterado para o seguinte, conforme a resposta número seis desta página do stackoverflow.

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path
        name="external"
        path="." />
    <external-files-path
        name="external_files"
        path="." />
    <cache-path
        name="cache"
        path="." />
    <external-cache-path
        name="external_cache"
        path="." />
    <files-path
        name="files"
        path="." />
</paths>

Quanto ao resto do código, aqui fica o código Java, incluindo o processo de pedir permissões ao utilizador para usar a câmara e o sd card. Basta chamar a função takePhoto().

public void takePhoto() {
       if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
           ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.CAMERA}, REQUEST_PERMISSION_CAMERA);
       } else {
           takePhoto2();
       }
   }

   public void takePhoto2() {
       if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
           ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_PERMISSION_READ_EXTERNAL_STORAGE);
       } else {
           takePhoto3();
       }
   }

   public void takePhoto3() {
       if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
           ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PERMISSION_WRITE_EXTERNAL_STORAGE);
       } else {
           takePhoto4();
       }
   }

   public void takePhoto4() {
       if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED ||
               ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ||
               ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
               ) {
           Log.d("ERROR", "No permissions!!!");
           //Toast.makeText(this, "No permission to take photos", Toast.LENGTH_LONG).show();
           return;
       } else {
      Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
      if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
         photoFile = null;
         photoFile = getFile();
         if (photoFile != null) {
            photoURI = FileProvider.getUriForFile(this,"pt.ulusofona.c3places.fileprovider", photoFile);

                   takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
            startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
         } else {
                   Toast.makeText(this, "Problems with the images folder", Toast.LENGTH_LONG).show();
               }
      }
   }
   }

   String mCurrentPhotoPath;
   File photoFolder;
   String imageFileName;
   File photoFile;
   final static int REQUEST_TAKE_PHOTO = 121;
   final static int MAX_IMAGE_DIM = 480;

   private File getFile() {
       photoFolder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);

       if(!photoFolder.exists()) { photoFolder.mkdir(); }

       String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
       imageFileName = "JPEG_"+ timeStamp;
       File image_file = null;

       try {
           image_file = File.createTempFile(imageFileName + "_",".jpg",photoFolder);
           mCurrentPhotoPath = image_file.getAbsolutePath();
       } catch (IOException e) {
           e.printStackTrace();
       }

       return image_file;
   }

   @Override
   protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);
    switch(requestCode) {
        case REQUEST_TAKE_PHOTO:
         try {
            Bitmap in = MediaStore.Images.Media.getBitmap(getContentResolver(),photoURI);
            int max = Math.max(in.getWidth(), in.getHeight());
            max = (int)(max/MAX_IMAGE_DIM);
            int larg = (int)(in.getWidth()/max);
            int alt = (int)(in.getHeight()/max);
            Bitmap out = Bitmap.createScaledBitmap(in, larg, alt, false);
            File file = new File(photoFolder, imageFileName + ".png");
            FileOutputStream fOut;
            fOut = new FileOutputStream(file);
            out.compress(Bitmap.CompressFormat.PNG, 100, fOut);
            fOut.flush();
            fOut.close();
            in.recycle();
            out.recycle();
            photoFile.delete();
         }catch (Exception e){
            e.printStackTrace();
         }
         break;
    }
}

Na função onActivityResult(), antes de gravar a foto, redimensiono-a.