How to select a database blob and transform into bitmap?

Asked

Viewed 607 times

2

I have the following error in my project, I select an image of the gallery turn it into byte register in the database, but at the moment of loading it to imageView it does not appear and not the application error, I’m not touching the part of the photo taking code but if someone has some better code because that the image loses quality, I appreciate the help.

public class Main extends AppCompatActivity {

    private int REQUEST_CAMERA = 0, SELECT_FILE = 1;
    private Button btnSelect;
    private Button btnCamera;
    private Button btnSave;
    private ImageView ivImage;
    private String Chave;
    banco db = new banco(this);
    SQLiteDatabase banco;
    String local;
    byte[] imagem;

    Bitmap bitmap;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ivImage = (ImageView) findViewById(R.id.ivImage);
        btnSelect = (Button) findViewById(R.id.btnSelect);
        btnCamera = (Button) findViewById(R.id.btnCamera);
        btnSave = (Button) findViewById(R.id.btnSalvar);


        btnSelect.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Chave = "Selecionar";
                galleryIntent();

            }
        });

        btnCamera.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Chave = "Camera";
                cameraIntent();

            }
        });

        btnSave.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {

                banco = db.getReadableDatabase();
                banco.execSQL("insert into tabela (imagem) values('"+imagem+"')");
                Toast.makeText(Main.this, imagem+" Imagem salva!", Toast.LENGTH_SHORT).show();
                banco.close();

            }
        });

        carregar();

    }


    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case Utility.MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    if(Chave.equals("Camera"))
                        cameraIntent();
                    else if(Chave.equals("Selecionar"))
                        galleryIntent();
                }
                break;
        }
    }

    private void galleryIntent()
    {
        Intent intent = new Intent();
        intent.setType("image/*");
        intent.setAction(Intent.ACTION_GET_CONTENT);
        startActivityForResult(Intent.createChooser(intent, "Select File"),SELECT_FILE);
    }

    private void cameraIntent()
    {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        startActivityForResult(intent, REQUEST_CAMERA);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (resultCode == Activity.RESULT_OK) {
            if (requestCode == SELECT_FILE)
                onSelectFromGalleryResult(data);
            else if (requestCode == REQUEST_CAMERA)
                onCaptureImageResult(data);
        }

    }

    private void onCaptureImageResult(Intent data) {
        bitmap = (Bitmap) data.getExtras().get("data");
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 90, bytes);

        File destination = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".jpg");

        local = destination.getName();

        FileOutputStream fo;
        try {
            destination.createNewFile();
            fo = new FileOutputStream(destination);
            fo.write(bytes.toByteArray());
            fo.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        ivImage.setImageBitmap(bitmap);

    }

    @SuppressWarnings("deprecation")
    private void onSelectFromGalleryResult(Intent data) {

        bitmap = null;
        if (data != null) {
            try {

                bitmap = MediaStore.Images.Media.getBitmap(getApplicationContext().getContentResolver(), data.getData());

            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        ivImage.setImageBitmap(bitmap);

        Bitmap bitmap2 = ((BitmapDrawable)ivImage.getDrawable()).getBitmap();
        ByteArrayOutputStream saida = new ByteArrayOutputStream();
        bitmap2.compress(Bitmap.CompressFormat.PNG,100,saida);
        imagem = saida.toByteArray();

        Toast.makeText(Main.this, imagem.toString(), Toast.LENGTH_SHORT).show();
    }




    public void carregar() {

        banco = db.getReadableDatabase();

        Cursor cur = banco.rawQuery("select * from tabela", null);

        cur.moveToFirst();

        if(cur.isAfterLast()== false) {

            cur.moveToLast();

            byte[] image = cur.getBlob(cur.getColumnIndex("imagem"));

            if (image != null) {
                Bitmap bmp = BitmapFactory.decodeByteArray(image, 0, image.length);
                ivImage.setImageBitmap(bmp);
            }
        }

    }


}
  • Did you confirm that byte[] image in the method carregar() is not null?

2 answers

1

Your image is certainly too big to be drawn on surface of a bitmap, because it bursts the maximum allowed size for the texture memory of Android. If you use the Android Monitor within the Android Studio will see a lot of warning like "Bitmap Too large to be uploaded into a Texture". You need to do downsampling of the same. Avoid manipulating bitmaps directly, use a library for this. It is much more complicated to deal with bitmaps on android than one imagines. Very much!

Note: In cases of low remaining system memory, read file operations to an array of bytes in memory may fail. In extreme situations of low memory, not even using a library with Glide can prevent these errors from occurring, but Glide handles them gracefully, another advantage of using a library like this.

So study the library Glide, that does all the work for you of reading the image in a background thread (avoiding crashing the user interface) and still considers screen orientation rotations (which would give you an exception of NullReferenceException), and also implements an image cache to improve application performance.

Install Glide by adding the following line to your Gradle:

dependencies {
    compile 'com.github.bumptech.glide:glide:3.7.0'
    compile 'com.android.support:support-v4:19.1.0'
}

Once installed Glide modify its display routine to:

public void carregar() {

    banco = db.getReadableDatabase();

    Cursor cur = banco.rawQuery("select * from tabela", null);

    cur.moveToFirst();

    if(cur.isAfterLast()== false) {

        cur.moveToLast();

        byte[] image = cur.getBlob(cur.getColumnIndex("imagem"));

        if (image != null) {

            Glide.with(this)
                .load(image)
                .asBitmap()
                .into(ivImage);

        }
    }

Note: I noticed an error in your implementation of capturing the image by the camera. You are only taking the thumbnail of the captured image. This is a common mistake/prank from anyone who starts working with the camera on Android. I have an answer on exactly what you can see here: Working with the camera or gallery

  • If that were the problem(too big picture) would not give error?

  • @ramaral No. The error gets hidden because Android prefers to avoid taking down an application because of a very large image and just emits a warning (Warning) and displays nothing. If you look at Android Studio on the flap Android Monitor will see a lot of message like "Bitmap Too large to be uploaded into a Texture" .

  • In all the identical situations I came across Outofmemoryerror. The problem must be elsewhere(that method carregar() is a little "strange"), especially since he may be using the thumbnail and not the image.

  • @ramaral certainly were not identical situations. I am telling you that the mistake is what I reported, I have no doubt. The method to load is not strange. Just take a blob from the bank. The use of the miniature is a conceptual error, but even with the miniature everything will seem to work, because the image is small and will fit in the texture memory android. And that’s the important point: the gallery bitmap is too big to fit in that memory, not in android memory in general. May occur OutOfMemoryError if you have low system memory. I’ll make it clearer in the answer.

  • I will not insist but we are talking about a miniature and not the image. Never happened to me without error. When I speak strange is why: cur.moveToFirst();if(cur.isAfterLast()== false){cur.moveToLast(); ...} doesn’t mean he doesn’t do what he wants is just a weird way to go to the last record(if that’s what he wants).

  • I have had experience when saving the image directly on Sqlite, I had some problems with OutOfMemoryError, because the size limits on some types of variables is quite low,(besides that Sqlite has some limitations regarding the size of the query and the record), I ended up choosing to always create a file, pass this file to the camera and record the path of that file in the bank. This theme is discussed here

  • @ramaral did not want to stop to teach him how to use cursors or database, because he would have to put an order there. If you want to prove what I said about the problem not being outOfMemoryError, just create a simple program to display the images from the gallery. He doesn’t just use the thumbnail! That’s only when he goes through the camera. His biggest problem is when he selects through the gallery. The android today has more than 1, 2 and 4 GB of memory... any bitmap fits in memory. Certainly this is not the case (except in low system memory situations)

  • @Lucasqueirozribeiro myself indicated to the same user who asked this question that this is not the best way to save images. My answer can be seen here: http://answall.com/questions/159944/workingcom-imagens-de-high-quality e-no-sqlite3/160040#160040

  • 1

    @Loudenvier OutOfMemoryError can be fired for not having heap memory sufficient for that variable. No matter if the device has many GB of memory, the variables have their limited size.

  • @Lucasqueirozribeiro I know this may be a cause, but it is not what is happening in this case reported by the user. This happens to ALL the gallery images it displays. If it chooses one of Whatsapp it will work because it is smaller. If you are in doubt just write an app in 5min that displays an image selected by the gallery in an image view. It will not give Outofmemory and will give the warning I informed... Of course, if your phone is not low free memory. I updated the answer to be clearer on this matter.

  • 1

    Excellent reading on the subject: http://stackoverflow.com/a/10271095/285678

Show 6 more comments

0

Here’s a basic example of how to manipulate images in Sqlite:

IMAGE:

public void add( byte[] image) throws SQLiteException{
    ContentValues cv = new  ContentValues();
    cv.put(KEY_IMAGE,   image);
    database.insert( DB_TABLE, null, cv );
}

To load the image use the method getBlob :

byte[] image = cursor.getBlob(1);

Browser other questions tagged

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