Search code examples
c#imagecompressionimage-compressionimagelibrary

Saveable image library with compression?


this may be impossible, or rather, not very popular, but I was wondering how I'd go about creating a data file for images, that would actually compress them? Say I had 200MB total of image files, is there some system I can use to store them in a single file, that would compress them to a total size of like 150MB? (Just example numbers, ratios not important).

I know I can encode the images with Base64 and then store them in an SQLite database, but I read that storing images in their encoded forms actually resulted in a slightly larger size than the original image file itself.

I was also thinking of a ZIP file, but I wasn't sure if it could be used as a 'library' as such?

If something like this doesn't exist as a predefined class, could someone lead me on the right track?

This is a mock of what I'm sort of looking for:

class ImageLibrary {
  //this is where the code would go for the library?
}

class MyProgram{
  public MyProgram() 
  {
    ImageLibrary library = new ImageLibrary();
    library.Add(<Image object here, with an ID of sorts>);
    library.Add(<Another image object here, also with an ID>);
    Load += new FormLoadEventHandler(MyProgram_Load);
  }

  void MyProgram_Load(object sender, EventArgs e)
  {
    PictureBox.Image = library.Get(<image id here>);
  }
}

I hope this is possible. Else, I'll just put up with a slightly larger file size and Base64 encode them. But, because I have, at the moment, almost 500 images I want to store, a kB saved is a kB earned. :) Also, please don't judge the quality of my code example, it's just a mock up and I wrote it off the cuff.

Cheers, and thankyou in advance.


Solution

  • If save your images as binary files will help this is a code I use to convert them to binary and then save into SQLite:

    public byte[] ImageToByte(Image image, System.Drawing.Imaging.ImageFormat format){
            using (MemoryStream ms = new MemoryStream())
            {
                // Convert Image to byte[]
                image.Save(ms, format);
                byte[] imageBytes = ms.ToArray();
                return imageBytes;
            }
        }
        public Image ByteToImage(byte[] imageBytes)
        {
            // Convert byte[] to Image
            MemoryStream ms = new MemoryStream(imageBytes, 0, imageBytes.Length);
            ms.Write(imageBytes, 0, imageBytes.Length);
            Image image = new Bitmap(ms); 
            return image;
        }
    

    And then to save the binary:

    void SaveImage(byte[] image){
            string conStringDatosUsuarios = @" Data Source = \Program Files\GPS___CAM\Data\DatosUsuarios.s3db ";            
            SQLiteConnection con = new SQLiteConnection(conStringDatosUsuarios); 
            SQLiteCommand cmd = con.CreateCommand();
            cmd.CommandText = String.Format("INSERT INTO Users (Foto) VALUES (@0);");
            SQLiteParameter p = new SQLiteParameter("@0", System.Data.DbType.Binary);
            p.Value = image;
            cmd.Parameters.Add(p);            
            con.Open(); 
            try
            {
                cmd.ExecuteNonQuery();
            }
            catch (Exception exc1)
            {
                MessageBox.Show(exc1.Message);
            }
            con.Close();
        }
    

    Hope it helps

    EDIT As you asked, I'm updating with the load image code: (to convert the byte to image you must use the ByteToImage function)

    void LoadImage(string tag){
            string query = "SELECT Foto FROM Users;";
            string conString = @" conection to your database ";
            SQLiteConnection con = new SQLiteConnection(conString); 
            SQLiteCommand cmd = new SQLiteCommand(query, con);            
            con.Open();
            try
            {
                SQLiteDataReader rdr = cmd.ExecuteReader();
                try
                {
                    while (rdr.Read())
                    {
                        pictureBox1.Image = ByteToImage((System.Byte[])rdr[0]);
                    }
                }
                catch (Exception exc) { MessageBox.Show(exc.Message); }
            }
            catch (Exception ex) { MessageBox.Show(ex.Message); }
            con.Close();
        }
    

    EDIT 2 Try this to see which type of data are you trying to load:

    System.Type checkType = rdr[0].GetType();
    pictureBox1.Image = ByteToImage((System.Byte[])rdr[0]);
    

    add the first line in your code and put a breakpoint in that line. Check checkType's type. Probably it isn't binary. Let me know the result to help you.