Generating Bitmap of shot photo

I am trying to generate a bitmap of a photo taken:

public void onClick(View v) {
    final Runnable runnable = new Runnable() {
        @Override
        public void run() {
            Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
            // para usar fragment getActivity().getApplicationContext()
            uriImagem = ProcessImages.getOutputMediaFileUri(ProcessImages.MEDIA_TYPE_IMAGE, ChecklistActivity.this);

            cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, uriImagem);
            startActivityForResult(cameraIntent, CAMERA_REQUEST);       
        };
    }
}

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.i("uriImagemNova", uriImagem.getPath());
    if(requestCode == CAMERA_REQUEST && resultCode == RESULT_OK) {
            new CarregaMiniaturaAsyncTask().execute();
        }
}

private class CarregaMiniaturaAsyncTask extends AsyncTask<Object, Object, Object> {

    @Override
    protected Object doInBackground(Object... params) {
        // Cria um novo cursor para obter o caminho do arquivo da imagem e sua miniatura.
        Cursor myCursor = null;

        // As colunas que queremos retornar.
        String[] projectionImage = {
                MediaStore.Images.ImageColumns._ID,
                MediaStore.Images.ImageColumns.DATA,
                MediaStore.Images.ImageColumns.DATE_TAKEN,
                MediaStore.Images.ImageColumns.DATE_ADDED,
                MediaStore.Images.ImageColumns.ORIENTATION};
        // Ira organizar a consulta por data em ordem decrescente.
        String imageSort = MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC";

        ContentResolver contentResolver = getContentResolver();
        // Consulta as imagens armazenadas no sistema de arquivos.
        myCursor = contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projectionImage, null, null, imageSort);

        long imageId = 0l; // Armazena o id da imagem.
        String imagePath = null; // Armazena o caminho para o arquivo da imagem.
        long imageDataTaken = 0l; // Armazena a data em que a imagem foi capturada da camera.
        long imageDataAdded = 0l; // Armazena a data em que a imagem foi adicionada ao MediaStore.
        int imageOrientation = 0; // Armazena a orientacao da imagem.

        // Obtem os dados da imagem
        try {
            myCursor.moveToFirst();
            imageId = myCursor.getLong(myCursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns._ID));
            imagePath = myCursor.getString(myCursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DATA));
            imageDataTaken = myCursor.getLong(myCursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DATE_TAKEN));
            imageDataAdded = myCursor.getLong(myCursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DATE_ADDED));
            imageOrientation = myCursor.getInt(myCursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.ORIENTATION));

            Log.d("PROCESSAMENTO DE IMAGENS", "Imagem id.: " + imageId);
            Log.d("PROCESSAMENTO DE IMAGENS", "Imagem path.: " + imagePath);
            Log.d("PROCESSAMENTO DE IMAGENS", "Imagem data taken.: " + imageDataTaken);
            Log.d("PROCESSAMENTO DE IMAGENS", "Imagem data added.: " + imageDataAdded);
            Log.d("PROCESSAMENTO DE IMAGENS", "Imagem Orientation.: " + imageOrientation);

            // Obtem o URI da imagem em tamanho real para ser utilizado na visualizacao da imagem caso clique na miniatura.
            //uriImagem = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, String.valueOf(imageId));
            Log.d("PROCESSAMENTO DE IMAGENS", "Imagem uri.: " + uriImagem.getPath());

            // Armazena o id da imagem para ser utilizado no recarregamento da imagem ao voltar da galeria do Android (Gallery App).
            long imagemId = imageId;

            List<Object> imagemCompactada = ProcessImages.compactarImagem(uriImagem.getPath());
            imagemBitmap = (Bitmap) imagemCompactada.get(0);
            byte[] imagemBytes = (byte[]) imagemCompactada.get(1);
            encoded = Base64.encodeBytes(imagemBytes, Base64.DONT_BREAK_LINES | Base64.URL_SAFE);
        } catch (IllegalArgumentException e) {
            Log.e("PROCESSAMENTO DE IMAGENS", "A coluna nao existe", e);
        } catch (IndexOutOfBoundsException e) {
            Log.e("PROCESSAMENTO DE IMAGENS", "Voce tentou acessar uma localizacao menor que zero ou maior que o tamanho da lista.", e);
        } finally {
            myCursor.close();
        }

        return ProcessImages.getMiniaturaImagem(contentResolver, uriImagem.getPath(), imageId);
    }

    @Override
    protected void onPostExecute(Object result) {
        super.onPostExecute(result);
        imagemBitmap = (Bitmap) result;
        imageView1.setImageBitmap(imagemBitmap);
    }
}

The bitmap is generated with the last photo in the public gallery, and not with the photo that is taken from the camera and stored in the application folder.

insert the description of the image here

Apparently, the cursor can only get data from the Android public gallery. What I'm trying to do now, is let the photos that are in the application folder, be visible / indexed in the public album, just as it happens with whatsapp. Does anyone know the best way to do this?

Author: Morfina, 2015-12-17

2 answers

As noted in the comments of my first answer, it is incorrect, does not work properly on all devices. I could have deleted it but I will leave it as a form of consultation and understanding.

A new solution I discovered is as follows:

Note: I did not put emphasis on the words of the code comments.

private Uri fileImageUri; // Variavel de instancia onde sera salvo o novo arquivo de imagem

// Chame este metodo para capturar a foto
private void dispatchTakePictureIntent() {
    // Cria a intent para capturar a imagem da camera e retorna o controle para o chamador.
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    // Aqui nos usamos a classe ProcessaImagens para criar um Arquivo (Para saber sobre a criacao do arquivo, veja o codigo da classe)
    fileImageUri = ProcessaImagens.getOutputMediaFileUri(ProcessaImagens.MEDIA_TYPE_IMAGE, getApplicationContext());
    // Passamos a URI desse novo arquivo para a Intent, dizendo que queremos salvar a nova imagem nele.
    intent.putExtra(MediaStore.EXTRA_OUTPUT, fileImageUri);
    // Inicia a intent para captura da imagem e espera pelo resultado no metodo: "onActivityResult"
    startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    // Se finalizou a activity em startForActivityResult.
    if (resultCode == RESULT_OK) {
        if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
            processImageCaptured(); // Este metodo ira processar a imagem nesta Activity/Fragment
        }
    }
    // Se cancelou a activity em startForActivityResult.
    else if (resultCode == RESULT_CANCELED) {
        if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
            // Usuário cancelou a captura da imagem
        }
    }
    // Se um erro ocorreu na activity em startForActivityResult.
    else {
        // Captura da imagem falhou, avisa ao usuario.
        Toast.makeText(this, getString(R.string.fail_activity_take_image), Toast.LENGTH_SHORT).show();
    }
}

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    // Para evitar erros com mudancas de orientacao do dispositivo, entre outros, salve o valor da URI no Bundle
    // Recupere o valor da URI em onCreate ou onRestoreInstanceState.
    outState.putParcelable(FILE_IMAGE_URI, fileImageUri); // FILE_IMAGE_URI e uma constante qualquer apenas para guardar o valor
}

private void processImageCaptured() {
    // PRESTE ATENCAO: CHAME APENAS ESTE METODO SE QUISER QUE SUA IMAGEM SEJA ARMAZENA NO PROVEDOR DE CONTEUDO DO SISTEMA
    // E SEJA EXIBIDA NA GALERIA DO ANDROID E OUTROS APPS. LEIA O JAVADOC DO METODO PARA ENTENDER MELHOR.
    galleryAddPic(); 

    // Uma Lista contendo o objeto Bitmap compactado na primeira posicao (0) e seu array de bytes na segunda posicao (1).
    List<Object> image = ProcessaImagens.compactarImagem(fileImageUri.getPath());

    // FACA ALGUMA COISA COM SUA IMAGEM.
}

/**
 * Chame scanner de mídia do sistema para adicionar sua foto ao banco de dados do Provedor de Media,
 * Tornando-o disponível no aplicativo Gallery Android e outros aplicativos.
 */
private void galleryAddPic() {
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    mediaScanIntent.setData(fileImageUri);
    this.sendBroadcast(mediaScanIntent);
}

I believe that with this new encoding, it will work on all devices. Remembering that this way the photo is saved in a folder with the name of your application, inside the "Pictures" folder of Android. It can be shared between applications. To learn more about creating the folder / file that will create the images, see internally the method responsible within the ProcessaImagens class.

 1
Author: Lucas Santos, 2016-01-13 21:38:05

As you said, the error is in the argument that is passing to the getMiniaturaImagem() method. This method asks for three arguments: ContentResolver cr, String imagePath, long imageId. In this case, you passed the argument imageId incorrectly. It has to be the id referring to the image that was captured, you passed a wrong argument, called resultCode that does not match the image id related to the thumbnail.

To get the image id, you'll have to make a query to MediaStore, at least it's the only way I know of, and that should be done on a thread outside the UI. I will pass you a code where it is possible to get the thumbnail of the image correctly. Another thing I think you've confused, I'm not totally sure, but I think the ProcessImages.getOutputMediaFileUri(...) method doesn't need to run outside of the UI Thread, so this snippet of code:

    Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    // para usar fragment getActivity().getApplicationContext()
    uriImagem = ProcessImages.getOutputMediaFileUri(ProcessImages.MEDIA_TYPE_IMAGE, ChecklistActivity.this);

    cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, uriImagem);
    startActivityForResult(cameraIntent, CAMERA_REQUEST); 

Could be run on the same main thread. You can check this by seeing if it is necessary or not by doing a Google search if any internal code of the method I created need it or not.

I recommend you structure your code as follows now:

/**
  * (ISTO é uma variável de instância) Contem o caminho e o nome do arquivo onde desejamos salvar a imagem. 
  * Usado principalmente para iniciar uma Intent.Action_View com esta URI. (GalleryApp)
  */
private Uri uriImagem = null;

public void onClickCamera(View v){
    // Cria uma intent para capturar uma imagem e retorna o controle para quem o chamou (NAO PRECISA DECLARAR PERMISSAO NO MANIFESTO PARA ACESSAR A CAMERA POIS O FAZEMOS VIA INTENT).
    Intent intent = new Intent( MediaStore.ACTION_IMAGE_CAPTURE );
    // Cria um arquivo para salvar a imagem.
    uriImagem = ProcessaImagens.getOutputMediaFileUri( ProcessaImagens.MEDIA_TYPE_IMAGE, getActivity().getApplicationContext() );
    // Passa para intent um objeto URI contendo o caminho e o nome do arquivo onde desejamos salvar a imagem. Pegaremos atraves do parametro data do metodo onActivityResult().
    intent.putExtra( MediaStore.EXTRA_OUTPUT, uriImagem );
    // Inicia a intent para captura de imagem e espera pelo resultado.
    startActivityForResult( intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE );
}

Until then I have not used Thread or AsyncTask. Now after the image is captured, let's treat the result in onActivityResult and get the thumbnail and compress the image as well.

@Override
public void onActivityResult( int requestCode, int resultCode, Intent data ) {
    // Se finalizou a activity em startForActivityResult.
    if ( resultCode == Activity.RESULT_OK ) {
        if ( requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE ) {
            new CarregaMiniaturaAsyncTask().execute();
        }
    }
    // Se cancelou a activity em startForActivityResult.
    else if ( resultCode == Activity.RESULT_CANCELED ) {
        if ( requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE ) {
            // Usuario cancelou a captura da imagem.
            Log.d( getTag(), "Captura de imagem CANCELADA!" );
        }
    }
    // Se ocorreu algum erro na activity em startForActivityResult.
    else {
        // Captura da imagem falhou, avisa ao usuario.
        Toast.makeText( getActivity().getApplicationContext(), "FALHA! A captura da imagem falhou!", Toast.LENGTH_LONG ).show();
        Log.e( getTag(), "FALHA! A captura da imagem falhou!" );
    }
}

    /**
     * Thread responsavel por carregar a miniatura de uma imagem.
     * Obtem o id da imamgem; Obtem o URI da imagem; Obtem o array de bytes da imagem; Obtem a miniatura da imagem.
     * Define o componente ImageView com a miniatura da imagem.
     */
    private class CarregaMiniaturaAsyncTask extends AsyncTask<Object, Object, Object> {
    @Override
    protected Object doInBackground(Object... params) {
        // Cria um novo cursor para obter o caminho do arquivo da imagem e sua miniatura.
        Cursor myCursor = null;

        // As colunas que queremos retornar.
        String[] projectionImage = {
                MediaStore.Images.ImageColumns._ID,
                MediaStore.Images.ImageColumns.DATA,
                MediaStore.Images.ImageColumns.DATE_TAKEN,
                MediaStore.Images.ImageColumns.DATE_ADDED,
                MediaStore.Images.ImageColumns.ORIENTATION};
        // Ira organizar a consulta por data em ordem decrescente.
        String imageSort = MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC";

        ContentResolver contentResolver = getContentResolver();
        // Consulta as imagens armazenadas no sistema de arquivos.
        myCursor = contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projectionImage, null, null, imageSort);

        long imageId = 0l; // Armazena o id da imagem.
        String imagePath = null; // Armazena o caminho para o arquivo da imagem.
        long imageDataTaken = 0l; // Armazena a data em que a imagem foi capturada da camera.
        long imageDataAdded = 0l; // Armazena a data em que a imagem foi adicionada ao MediaStore.
        int imageOrientation = 0; // Armazena a orientacao da imagem.

        // Obtem os dados da imagem
        try {
            myCursor.moveToFirst();
            imageId = myCursor.getLong(myCursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns._ID));
            imagePath = myCursor.getString(myCursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DATA));
            imageDataTaken = myCursor.getLong(myCursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DATE_TAKEN));
            imageDataAdded = myCursor.getLong(myCursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DATE_ADDED));
            imageOrientation = myCursor.getInt(myCursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.ORIENTATION));

            Log.d("PROCESSAMENTO DE IMAGENS", "Imagem id.: " + imageId);
            Log.d("PROCESSAMENTO DE IMAGENS", "Imagem path.: " + uriImagem.getPath());
            Log.d("PROCESSAMENTO DE IMAGENS", "Imagem data taken.: " + imageDataTaken);
            Log.d("PROCESSAMENTO DE IMAGENS", "Imagem data added.: " + imageDataAdded);
            Log.d("PROCESSAMENTO DE IMAGENS", "Imagem Orientation.: " + imageOrientation);

            // Obtem o URI da imagem em tamanho real para ser utilizado na visualizacao da imagem caso clique na miniatura.
            //uriImagem = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, String.valueOf(imageId));
            Log.d("PROCESSAMENTO DE IMAGENS", "Imagem uri.: " + uriImagem.getPath());

            // Armazena o id da imagem para ser utilizado no recarregamento da imagem ao voltar da galeria do Android (Gallery App).
            long imagemId = imageId;

            List<Object> imagemCompactada = ProcessImages.compactarImagem(uriImagem.getPath());
            imagemBitmap = (Bitmap) imagemCompactada.get(0);
            byte[] imagemBytes = (byte[]) imagemCompactada.get(1);
            encoded = Base64.encodeBytes(imagemBytes, Base64.DONT_BREAK_LINES | Base64.URL_SAFE);
        } catch (IllegalArgumentException e) {
            Log.e("PROCESSAMENTO DE IMAGENS", "A coluna nao existe", e);
        } catch (IndexOutOfBoundsException e) {
            Log.e("PROCESSAMENTO DE IMAGENS", "Voce tentou acessar uma localizacao menor que zero ou maior que o tamanho da lista.", e);
        } finally {
            myCursor.close();
        }

        Log.i("uriImagemNova", uriImagem.getPath());

        return ProcessImages.getMiniaturaImagem(contentResolver, uriImagem.getPath(), imageId);
    }

    @Override
    protected void onPostExecute(Object result) {
        super.onPostExecute(result);
        imagemBitmap = (Bitmap) result;
        imageView1.setImageBitmap(imagemBitmap);
    }
}
 0
Author: Lucas Santos, 2016-01-04 15:56:50