Generating photo bitmap taken

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

In all probability, the cursor can only get data from the public android gallery. What I'm trying to do now is to leave the photos that remain in the application folder, to be visible / indexed in the public album, just like whatsapp. Does anyone know the best way to do this?

    
asked by anonymous 17.12.2015 / 20:58

2 answers

1

As noted in the comments from my first response, it is incorrect, does not work correctly 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 emphasize the comments of the code.

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 coding, it will work on all devices. Remember 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 the images will be created, internally view the responsible method within the ProcessaImagens class.

    
13.01.2016 / 22:38
0

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 imageId argument incorrectly. It has to be the id of 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 id of the image, you will have to query the MediaStore , at least it's the only way I know it, and this should be done on a Thread outside of the UI. I'll give you a code where you can get the image thumbnail correctly. Another thing I think you confused, I'm not sure, but I think the ProcessImages.getOutputMediaFileUri(...) method does not have to be run outside the Thread UI, so this code snippet is:

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

It 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 some internal method code I created needs it or not.

I recommend you structure your code as follows:

/**
  * (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 did not use Thread or AsyncTask. Now after the image is captured, we will treat the result in onActivityResult and get the thumbnail and COMPACT the image too.

@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);
    }
}
    
18.12.2015 / 18:45