1

How can I limit the size of the image when saving to SQLite? I have this error when I retrieve which I think didn't get the big size of the blob Image from SQLite. However, I tried putting limit 500 in the query like this SELECT id,cash_card,hh_number,cc_image FROM CgList limit 500, but the result is the same, it crashes my application.

In short, Is there any way to reduce the file size of the image when inserting to the SQLite database?

Error

android.database.sqlite.SQLiteBlobTooBigException: Row too big to fit into CursorWindow requiredPos=0, totalRows=4

Insert data and blob

 public void insertData(String cash_card, String hh_number,String series_number ,byte[] cc_image,byte[] id_image){
    SQLiteDatabase database = getWritableDatabase();
    String sql = "INSERT INTO CgList VALUES (NULL,?, ?, ?, ?, ?)";
    SQLiteStatement statement = database.compileStatement(sql);
    statement.clearBindings();

    statement.bindString(1, cash_card);
    statement.bindString(2, hh_number);
    statement.bindString(3, series_number);
    statement.bindBlob(4, cc_image);
    statement.bindBlob(5, id_image);
    statement.executeInsert();
}

Getting data

  Cursor cursor = ScannedDetails.sqLiteHelper.getData("SELECT id,cash_card,hh_number,cc_image FROM CgList");
    list.clear();
    while (cursor.moveToNext()) {   // the error is here
        int id = cursor.getInt(0);
        String name = cursor.getString(1);
        String price = cursor.getString(2);
        byte[] image = cursor.getBlob(3);

        list.add(new Inventory(name, price, image, id));
    }
    adapter.notifyDataSetChanged();

When I click button to save to SQLite

    btnSubmit.setOnClickListener( new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            sqLiteHelper.insertData(
                    edtCashCard.getText().toString().trim(),
                    edtHhnumber.getText().toString().trim(),
                    edtSeriesno.getText().toString().trim(),
                    imageViewToByte(mPreviewCashcard),
                    imageViewToByte(mPreview4PsId)
            );
        }
    });

Converting Image To Byte

 public static byte[] imageViewToByte(ImageView image) {
   Bitmap bitmap = ((BitmapDrawable)image.getDrawable()).getBitmap();
   ByteArrayOutputStream stream = new ByteArrayOutputStream();
   bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
   byte[] byteArray = stream.toByteArray();
   return byteArray;
 }

Updated

I think this is the problem when capturing an image it provide bigger size, I need this because after I capture the image I want to crop the image for some purpose but I want to display the actual capture not the cropped image to another activity

 private void pickCamera() {
    ContentValues values = new ContentValues();
    values.put(MediaStore.Images.Media.TITLE, "NewPic");
    values.put(MediaStore.Images.Media.DESCRIPTION, "Image to Text");
    image_uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,values);
    Intent cameraIntent = new Intent (MediaStore.ACTION_IMAGE_CAPTURE);
    cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, image_uri);
    startActivityForResult(cameraIntent, IMAGE_PICK_CAMERA_CODE);
}

OnActivityResult

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK){
        if (requestCode == IMAGE_PICK_GALLER_CODE){
            CropImage.activity(data.getData()).setGuidelines(CropImageView.Guidelines.ON).start(this);
        }
        if (requestCode == IMAGE_PICK_CAMERA_CODE){

            CropImage.activity(image_uri).setGuidelines(CropImageView.Guidelines.ON).start(this);
        }
    }
    if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE){
        CropImage.ActivityResult result = CropImage.getActivityResult(data);
        if(resultCode ==RESULT_OK){
            Uri resultUri = result.getUri();
            resultUri.getPath();
            mPreviewIv.setImageURI(resultUri);
            BitmapDrawable bitmapDrawable = (BitmapDrawable)mPreviewIv.getDrawable();
            Bitmap bitmap = bitmapDrawable.getBitmap();
            TextRecognizer recognizer = new TextRecognizer.Builder(getApplicationContext()).build();

            if(!recognizer.isOperational()){
                Toast.makeText(this,"Error",Toast.LENGTH_SHORT).show();
            }
            else{
                Frame frame = new Frame.Builder().setBitmap(bitmap).build();
                SparseArray<TextBlock> items = recognizer.detect(frame);
                StringBuilder sb = new StringBuilder();

                for (int i = 0; i<items.size(); i++){
                    TextBlock myItem = items.valueAt(i);
                    sb.append(myItem.getValue());
                    sb.append("\n");
                }
                
                Intent i = new Intent(MainActivity.this, ScannedDetails.class);   
                //camera
                i.putExtra("CashCardImage",image_uri.toString());  //This data pass to another activity
                startActivity(i);
            }
        }
    }
}

Retrieve to another Activity

Bundle extras = getIntent().getExtras();
   String resultUri = extras.getString("CashCardImage");
   Uri myUri = Uri.parse(resultUri);
   mPreviewCashCard.setImageURI(myUri);

The other one I tried when saving to SQLITE the size is not big it's just KIB, I think the problem is on the 1st PickCamera but those code need for cropping an Image

 private void pickCamera() {
   Intent intent = new Intent(ScannedDetails.this, InventoryList.class);
   startActivity(intent);
   }
Shainnah Jane
  • 221
  • 2
  • 15
  • Does this answer your question? [SQLiteBlobTooBigException: Row too big to fit into CursorWindow requiredPos=0, totalRows=1](https://stackoverflow.com/questions/51959944/sqliteblobtoobigexception-row-too-big-to-fit-into-cursorwindow-requiredpos-0-t) – Arthur Attout Sep 01 '21 at 05:41
  • btw. keeping such big blob in sqlite is highly unefficient (saving/fetching) – snachmsm Sep 01 '21 at 05:42
  • @ArthurAttout thanks for your response but I didn't get the idea of the answer there can you tell me what's going on, it is the problem when inserting data? – Shainnah Jane Sep 01 '21 at 05:51
  • @snachmsm thanks for your response Is there anyway to limit the size of the image? – Shainnah Jane Sep 01 '21 at 05:54
  • I tried the 1st answer above and it display the image but the question is , is there anyway how can I limit the size of the image when saving into the SQLITE? @Arthur Attout – Shainnah Jane Sep 01 '21 at 06:03
  • @blackapps Thanks for your response I added the code above on how I managed the Image, Is there anyway just need help about this one – Shainnah Jane Sep 01 '21 at 06:54
  • That is the wrong code added. We still know nothing. For you function insertData() you should show us how you convert your image to `byte[] cc_image,byte[]id_image`. And explain why you use two byte arrays. Also tell size of original image file and length of arrays. Start with the obtained uri. – blackapps Sep 01 '21 at 07:10
  • @blackapps Thanks for your response, I updates the code above on how I convert Image to Byte – Shainnah Jane Sep 01 '21 at 07:25
  • @blackapps this is the source I've been following [link](https://github.com/quocvn/food-sqlite-demo) Do you have recommendations for this problem? I'm just out of option how can I managed to lessen the file size though it displays and insert in SQLite Android studio but It is not best practice to insert huge file in SQLite – Shainnah Jane Sep 01 '21 at 07:31
  • Sorry but what should i do with that link? Looking at a video? No way. Post your code. And adapt the title. Also remove that android-studio tag. – blackapps Sep 01 '21 at 07:37
  • @blackapps Should I make a new post or change the title of my post? – Shainnah Jane Sep 01 '21 at 07:40
  • @blackapps Sorry I didn't get adapt the title – Shainnah Jane Sep 01 '21 at 07:43
  • ??? you can just edit it. I dont understand. – blackapps Sep 01 '21 at 07:59
  • `imageViewToByte(ImageView image)` Why do you first put your file in an ImageView? I would expect a function `UriToByte(Uri uri)`. You can have a good reason but i wonder. Further you should try both functions and compare sizes. You also did not tell us the sizes i requested. – blackapps Sep 01 '21 at 08:03
  • `Bitmap.CompressFormat.PNG` Is the original image a .png? Why do you compress to .png where compressing to .jpg or .webp would give much less bytes? – blackapps Sep 01 '21 at 08:04

2 Answers2

1

However, I tried putting limit 500 in the query like this SELECT id,cash_card,hh_number,cc_image FROM CgList limit 500

LIMIT limits the number of rows returned, is does not limit the size of a row.

The issue is that a single row exceeds the capacity of the cache/buffer (CursorWindow) that a Cursor uses. This restriction does not apply when inserting the said row/rows.

The typical solution is to not store images but to instead store a reference, such as a file path, from which the image (or other large item) can then be retrieved.

Here's an example that stores images less than a set size (100k in the example) as a blob and those larger as files in data/data/myimages, which could be another solution.

It is possible to break a large image into chunks of data and store/retrieve that. Here's an example of doing that.

MikeT
  • 51,415
  • 16
  • 49
  • 68
  • Thanks for your response I tried but I still don't get the idea, I'm also a slow learner, I don't know how can I apply that source to my code, please need help – Shainnah Jane Sep 02 '21 at 04:04
  • @ShainnahJane Your first step is to decide how you are going handle the storage of the images, as 1) chunks of data, as 2) a reference to files or 3) a mix of storing those that can be stored and others as references. Then examine the relevant example and extract/modify the methods to suit. – MikeT Sep 02 '21 at 06:35
  • Thanks for your response I intent to save data with images to SQLite in my phone , the images is comes from my Camera , the question is what is the best way to save image should I use `BLOB` or just the path of the imageUri? – Shainnah Jane Sep 02 '21 at 07:27
  • @ShainnahJane the uri, although this would be susceptible to the image being moved. – MikeT Sep 02 '21 at 08:01
  • Actually I have two ImagePreview when saving to SQLITE the file size of the two images are different, one is just only `KIB` and the other one is bigger which is `MiB` I think there's no problem inserting in SQLite the difference is that how I capture the camera, but I don't know why they have different file size – Shainnah Jane Sep 03 '21 at 03:43
  • I added code above with some explanation can you help me? I'm confused what's the problem – Shainnah Jane Sep 03 '21 at 03:44
0

Don't store an image directly in your database. Instead, save the image to a file or to a webserver. Then in the database store the file path or URL to the image.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
  • Thanks for your response but I intent to save data to SQLite in my phone then I want to sync all data with images and send it through API, but for now, I know it's a bit common to ask but still don't have yet solve my problem on how can I limit the image size to my SQLite can you help pls. – Shainnah Jane Sep 02 '21 at 04:02