Generating Bitmap of photo taken

Asked

Viewed 1,296 times

2

I’m 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 from the public gallery, not with the photo that is taken from the camera and stored in the application folder.

inserir a descrição da imagem aqui

Apparently, the cursor can only get data from the android public gallery. What I’m trying to do now, is to let the photos that are in the application folder, be visible/indexed in the public album, just like with Whatsapp. Someone knows the best way to do it?

  • Tell me exactly which line went wrong.

  • Sorry for the delay, I put an image with the error in the question. I’m probably missing some argument on getMiniaturaImage, or I’m not sure how to call it, thank you!

2 answers

1


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

A new solution I discovered is the following:

NOTE: I did not put accent 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 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 folder "Pictures" Android. It can be shared across applications. To learn more about creating the folder/file that will be created the images, see internally the responsible method within the class ProcessaImagens.

  • Very good, it’s working now. However, it has a detail, that after taking the photo and loading the bitmap in an imageview, in size MINI_KIND for example, it gets small, but when minimizing the app or turn off the screen, when it comes back, the bitmap is large. You know what it can be?

  • @Morphine honestly do not know what can be, this only happens with type MINI_KIND? Tried the other type? Strange this.

  • If this is the correct answer, check as correct to help and facilitate other people’s searches here at Stackoverflow.

  • Then, with MICRO_KIND seems to occur the reverse. When returning in the app, it gets smaller than it was

  • I don’t know what it might be. I’ll try to look into it later.

  • 1

    I was setting the bitmap in the imageview in the wrong place, your code works perfectly, thanks for everything expensive!

  • @You’re welcome, I’m glad it worked. I’m happy to help.

Show 2 more comments

0

As you said, the error is in the argument that is passing to the method getMiniaturaImagem(). This method calls 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 id of the Image related to the thumbnail.

To get the image id, you will have to make a query to MediaStore, at least it’s the only way I know how, and this should be done in a Thread outside the UI. I’ll give you a code where you can get the image thumbnail correctly. Another thing I THINK you’ve confused, I’m not entirely sure, but I think the method ProcessImages.getOutputMediaFileUri(...) does not need to run outside the Thread UI, so this code snippet:

    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 run on the same main thread. You can check this by seeing if it is necessary or not to do a google search if any internal code of the method I created needs 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 );
}

So far I haven’t 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);
    }
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.