2

I have a SQLite database with a table have a good amount if images, and I got some problems in database size, So I converted the logic to store the images in a folder and retrieve the needed images, so what I'm doing now it trying to get all the images stored on the database and save it in folder but I'm getting an error Out of memory.

Note: I used a compress method to compress the image before insert it to the database and also using decompress method when retrieve the image.

here is my code :

protected void Save()
    {
        try
        {
            using (SQLiteDataReader reader = DBConn.ExecuteReader("Select ID,image from transfers", CommandType.Text))
            {
                while (reader.Read())
                {
                    if (reader["image"] != DBNull.Value)
                    {
                        byte[] image = (byte[])reader["image"];
                        image = Decompress(image);
                        Image newImage = byteArrayToImage(image);

                        string path = string.Format(@"E:\images\CI-{0}.Jpeg", reader["ID"].ToString());
                        newImage.Save(path, ImageFormat.Jpeg);
                    }
                }
            }
            MessageBox.Show("done");
        }
        catch (SQLiteException ex)
        {
            // Do some logging or something. 
            MessageBox.Show("There was an error accessing your data. DETAIL: " + ex.Message);
        }
    }

method to get image from byte

public Image byteArrayToImage(byte[] bytesArr)
    {
        Bitmap newBitmap;
        using (MemoryStream memoryStream = new MemoryStream(bytesArr))
        {
            using (Image newImage = Image.FromStream(memoryStream))
            {
                newBitmap = new Bitmap(newImage);
            }
        }
        return newBitmap;

        // I tried this code also.
        //return (Bitmap)((new ImageConverter()).ConvertFrom(bytesArr));
    }

And this is the Decompress method

public static byte[] Decompress(byte[] data)
    {
        using (MemoryStream input = new MemoryStream(data))
        using (MemoryStream output = new MemoryStream())
        {
            using (DeflateStream dstream = new DeflateStream(input, CompressionMode.Decompress))
            {
                dstream.CopyTo(output);
            }
            return output.ToArray();
        }
    }
eglease
  • 2,445
  • 11
  • 18
  • 28
RabQab
  • 51
  • 4
  • Why not just save the bytes? Why load it into an image and then save the image? (All this l – Caius Jard Sep 18 '21 at 19:25
  • What happens if you properly Dispose `newImage` in your top level block of code: `using (Image newImage = byteArrayToImage(image)) { /* get path & save image */ }`? – Flydog57 Sep 18 '21 at 19:29
  • There's no point in *compressing* images: unless you're using a BMP or SVG formats, JPEG and PNG images are already compressed. As mentioned, just get the bytes and use `File.WriteAllBytes()` to save the bytes to disc. I assume you have also stored the original image format or file extension. Don't change the Image format to save it to disc with weird methods. – Jimi Sep 18 '21 at 19:34
  • @Jimi, yes you are correct, This is and old project and I didn't know that when I did it, now if I don't use the Decompress method the images will be saved but I cannot open it. and I used the `File.WriteAllBytes()` and I'm able to save the first 63 image then it crashes, the problem in the Decompress method 'out of memory' – RabQab Sep 18 '21 at 20:02
  • @CaiusJard, Yes Now I'm writing directly to the path, Thank you – RabQab Sep 18 '21 at 20:03
  • You'd perhaps be better streaming it from the db through the decompressor and to disk (if sqlite reader supports it; I've never looked. If it only supports byte array then at least stream from the array through the decompressor and to disk – Caius Jard Sep 18 '21 at 20:09

1 Answers1

2

I Changed the code from the advices I got from the comments so Thank you.

here is the final code:

 protected void Save()
    {
        try
        {
            using (SQLiteDataReader reader = DBConn.ExecuteReader("Select ID,image from transfers", CommandType.Text))
            {
                while (reader.Read())
                {
                    if (reader["image"] != DBNull.Value)
                    {
                        byte[] image = (byte[])reader["image"];
                        image = Decompress(image);

                        string path = string.Format(@"E:\images\CI-{0}.jpeg", reader["ID"].ToString());
                        File.WriteAllBytes(path, image);
                    }
                }
            }
            MessageBox.Show("done");
        }
        catch (SQLiteException ex)
        {
            // Do some logging or something. 
            MessageBox.Show("There was an error accessing your data. DETAIL: " + ex.Message);
        }
    }

I changed the Decompress method as bellow :

    public static byte[] Decompress(byte[] inputData)
    {
        if (inputData == null)
            throw new ArgumentNullException("inputData must be non-null");

        MemoryStream input = new MemoryStream(inputData);
        MemoryStream output = new MemoryStream();
        using (DeflateStream dstream = new DeflateStream(input, CompressionMode.Decompress))
        {
            dstream.CopyTo(output);
        }
        return output.ToArray();

        if (inputData == null)
            throw new ArgumentNullException("inputData must be non-null");
    }
RabQab
  • 51
  • 4