4

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.

Connor Deckers
  • 2,447
  • 4
  • 26
  • 45
  • base64 would be about 1.33 times the size, but I'm pretty sure SQLite supports BLOBs, so encoding them isn't necessary. – Thomas Jun 11 '12 at 11:50
  • @Thomas Good to know, I didn't think of that. So, I know that it'll at least be the same size as the images, plus about a kb for each image because of additional detail for them stored in the database. Is there any way to compress these images before they're stored? – Connor Deckers Jun 11 '12 at 11:53
  • 1
    @Spiritfire: usually you won't get any size reduction (sometimes even an increase!) from compressing an optimized jpg/png etc. Just make sure they are optimized before saving. – Michal B. Jun 11 '12 at 11:57

2 Answers2

3

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.

Ignacio Gómez
  • 1,587
  • 4
  • 23
  • 41
  • This could be promising. Do you know what it does to the file size? E.g. smaller, larger, equal? – Connor Deckers Jun 11 '12 at 12:01
  • @Spiritfyre I use this code to save my images to my db and the size is equal than the original. I probe to save them with base64 but it turn into larger files. So far this is the best I could achieve to save my images – Ignacio Gómez Jun 11 '12 at 12:04
  • Excellent, I'm using this and it's working wonderfully. Sadly, I have no image compression, but at least it's 90% of what I was looking for. Added bonus is, it's in an `SQLite` database, making my work extremely simple. Thanks so much :) – Connor Deckers Jun 11 '12 at 13:01
  • Glad to help! If you find a way to compress the images let me know ;) – Ignacio Gómez Jun 11 '12 at 13:15
  • I have another small question.. I have the images stored into the database fine, and it worked nicely. However, how do I retrieve them again? How can I retrieve the field as a `byte[]` array, so it can be turned back into an image? Or is there another way of converting the binary to an `Image` type again? – Connor Deckers Jun 12 '12 at 03:03
  • @Spiritfyre I will edit my post to add the code of Loading Image ;) – Ignacio Gómez Jun 12 '12 at 11:48
  • I thought that'd be the way to go with it, and I had already had that going, and when I compile my code, theres no errors, but I get a run-time error quoting `InvalidCastException: Specified cast is not valid.` Any ideas why? I can guarantee that all the content in that field is purely binary, so it can't be a conflict, can it? I'm confused. – Connor Deckers Jun 12 '12 at 21:03
1

Check out this article: http://msdn.microsoft.com/en-us/library/aa479502.aspx

I hope it helps. An idea for accessing files from a ZIP. It's not ready-to-use solution, but a nice concept explanation.

Michal B.
  • 5,676
  • 6
  • 42
  • 70
  • This looks like it might be worth looking into.. but before I dig too deep into this, do you know if it supports indexs? Like, putting a string with each file to index it, sort of like a database would? – Connor Deckers Jun 11 '12 at 11:58