Avatar billede jackass- Nybegynder
02. december 2010 - 12:29 Der er 15 kommentarer og
1 løsning

Billede fra blob

Hej igen,

Jeg forsøger at hente et billede i en SQLite DB i formatet blob og vise det i en pictureBox. Jeg har prøvet 2 måder, men får fejl ved begge.

Metode 1:
---------

byte[] blob = (byte[])myRow[4];

MemoryStream mStream = new MemoryStream(blob);
mStream.Position = 0;
Image img = Image.FromStream(mStream);
mStream.Close();
mStream.Dispose();
pictureBox1.Image = img;
pictureBox1.Refresh();

Giver fejlen: {"Parameter is not valid."} ved Image img = Image.FromStream(mStream);


Metode 2:
---------

byte[] blob = (byte[])myRow[4];

using (FileStream FS = new FileStream("image.jpg", FileMode.Create))
{
    FS.Write(blob, 0, blob.Length);
    FS.Close();
}
pictureBox1.Image = Image.FromFile("image.jpg");
pictureBox1.SizeMode = PictureBoxSizeMode.AutoSize;
pictureBox1.Refresh();

Giver fejlen: {"Out of memory."} ved pictureBox1.Image = Image.FromFile("image.jpg");


Det skal måske lige nævnes at når jeg vælger "Show picture" i SQLite Administrator, så vises billedet fint. Men "image.jpg" fra ovenstående kode kan ikke vises med Windows preview eller mspaint, fejl: The file appears to be damaged, corrupted or is too large (6 KB).

Nogen der kan fortælle hvad der går galt og hvorfor formatet er forkert?
Avatar billede arne_v Ekspert
03. december 2010 - 00:34 #1
Hvilken ADO.NET provider for SQLite bruger du?

BLOB er en noget speciel data type og nogen gange kræver den speciel håndtering.
Avatar billede jackass- Nybegynder
03. december 2010 - 07:49 #2
Det er ADO.NET 2.0 Provider for SQLite.

Er det skidt at gemme billede i SQLite DB? Og er det bedre at smide dem i \pics\ fx og så nøjes med at gemme filnavnet i DB, ud fra et performance mæssigt synspunkt.
Avatar billede arne_v Ekspert
03. december 2010 - 18:41 #3
Jeg tror at det er den jeg ogsaa har. Jeg maa proeve at eksperimentere lidt.

Hvis billederne ikke er for store boer performance vare OK med billeder i database
Avatar billede arne_v Ekspert
04. december 2010 - 01:39 #4
Hmm.

Jeg kan ikke genskabe problemet.

Test kode:

using System;
using System.Data;
using System.IO;

using System.Data.SQLite;

namespace E
{
    public class Program
    {
        public static void Main(string[] args)
        {
            File.Delete(@"C:\TestBlob.db");
            using(SQLiteConnection con = new SQLiteConnection(@"Data Source=C:\TestBlob.db;Version=3;Password=hemmeligt;New=True"))
            {
                con.Open();
                SQLiteCommand cre = new SQLiteCommand("CREATE TABLE tbl (id INTEGER NOT NULL, data BLOB, PRIMARY KEY(id))", con);
                cre.ExecuteNonQuery();
                SQLiteCommand ins = new SQLiteCommand("INSERT INTO tbl VALUES(@id,@data)", con);
                ins.Parameters.Add("@id", DbType.Int32);
                ins.Parameters.Add("@data", DbType.Object);
                for(int i = 0; i < 3; i++)
                {
                    ins.Parameters["@id"].Value = i + 1;
                    byte[] b = new byte[(i + 1) * 100];
                    for(int j = 0; j < b.Length; j++) b[j] = (byte)((i + 1 + j) % 255);
                    ins.Parameters["@data"].Value = b;
                    ins.ExecuteNonQuery();
                }
                SQLiteCommand sel = new SQLiteCommand("SELECT id,data FROM tbl", con);
                SQLiteDataReader rdr = sel.ExecuteReader();
                while(rdr.Read())
                {
                    int id = (int)(long)rdr[0];
                    byte[] b = (byte[])rdr[1];
                    if(b.Length != id * 100)
                    {
                        throw new Exception("oops");
                    }
                    for(int j = 0; j < b.Length; j++)
                    {
                        if(b[j] != (id + j) % 255)
                        {
                            throw new Exception("oops");
                        }
                    }
                    Console.WriteLine("id " + id + " is OK");
                }
                rdr.Close();
            }
            Console.ReadKey();
        }
    }
}
Avatar billede jackass- Nybegynder
08. december 2010 - 07:06 #5
Hmm.. det virker ikke her. Der bliver intet gemt - men heller ingen fejl;



            try
            {
                string strFileName;
                openFileDialog1.Filter = "Image File (*.jpg;*.bmp;*.gif)|*.jpg;*.bmp;*.gif";
                openFileDialog1.FilterIndex = 1;
                openFileDialog1.Title = "Vælg billede";
                if (openFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    strFileName = openFileDialog1.FileName;
                }


                SQLiteConnection connectionString = new SQLiteConnection("Data Source=" + Path.GetDirectoryName(Application.ExecutablePath) + "\\MyDB.s3db;Version=3;New=False;Compress=True");
                using (SQLiteConnection conn = new SQLiteConnection(connectionString))
                {
                    conn.Open();
                    string sql = "UPDATE MyTable set picture = @pic WHERE rowid = " + treeView1.SelectedNode.Tag;
                    SQLiteCommand cmd = new SQLiteCommand(sql,conn);

                    MemoryStream stream = new MemoryStream();
                    pictureBox1.Image.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
                    byte[] pic = stream.ToArray();
                    cmd.Parameters.AddWithValue("@pic",pic);

                    cmd.Connection = conn;
                    cmd.CommandTimeout = 120;
                    cmd.ExecuteNonQuery();
                    cmd.Connection.Close();
                }
            }


Hvad gør jeg galt? :-/
Avatar billede Syska Mester
08. december 2010 - 10:03 #6
Hvor er catch delen?

Du burde nok også bruge parameters til din treeView1.SelectedNode.Tag ... bare sådan for at gøre det hele kønt :-)

mvh
Avatar billede jackass- Nybegynder
08. december 2010 - 10:52 #7
Du får lige hele metoden, det er vist nemmere:

        public void SaveNewPicture()
        {
            try
            {
                string strFileName;
                openFileDialog1.Filter = "Image File (*.jpg;*.bmp;*.gif)|*.jpg;*.bmp;*.gif";
                openFileDialog1.FilterIndex = 1;
                openFileDialog1.Title = "Vælg billede";
                if (openFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    strFileName = openFileDialog1.FileName;
                }
               
                SQLiteConnection connectionString = new SQLiteConnection("Data Source=" + Path.GetDirectoryName(Application.ExecutablePath) + "\\MyDB.s3db;Version=3;New=False;Compress=True");
                using (SQLiteConnection conn = new SQLiteConnection(connectionString))
                {
                    conn.Open();
                    string sql = "UPDATE MyTable set picture = @pic WHERE rowid = " + Convert.ToInt32(treeView1.SelectedNode.Tag);
                    SQLiteCommand cmd = new SQLiteCommand(sql, conn);

                    MemoryStream stream = new MemoryStream();
                    pictureBox1.Image.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
                    byte[] pic = stream.ToArray();
                    cmd.Parameters.AddWithValue("@pic", pic);

                    cmd.Connection = conn;
                    cmd.CommandTimeout = 120;
                    cmd.ExecuteNonQuery();
                    cmd.Connection.Close();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error: " + ex.Message);
            }
        }

Problemet er, at billedet ikke bliver gemt..?
Avatar billede Syska Mester
08. december 2010 - 11:18 #8
Jeg ville angive hvad type dit "pic" object er ... ligesom Arne_v gør ...
DbType.Object

og så ville jeg stadig bruger parameters til "rowid".
Avatar billede jackass- Nybegynder
08. december 2010 - 12:30 #9
Like this?


        public void SaveNewPicture()
        {
            try
            {
                string strFileName;
                openFileDialog1.Filter = "Image File (*.jpg;*.bmp;*.gif)|*.jpg;*.bmp;*.gif";
                openFileDialog1.FilterIndex = 1;
                openFileDialog1.Title = "Vælg billede";
                if (openFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    strFileName = openFileDialog1.FileName;
                }
               
                SQLiteConnection connectionString = new SQLiteConnection("Data Source=" + Path.GetDirectoryName(Application.ExecutablePath) + "\\MyDB.s3db;Version=3;New=False;Compress=True");
                using (SQLiteConnection conn = new SQLiteConnection(connectionString))
                {
                    conn.Open();
                    string sql = "UPDATE MyTable set picture = @pic WHERE rowid = @rowid";
                    SQLiteCommand cmd = new SQLiteCommand(sql, conn);

                    MemoryStream stream = new MemoryStream();
                    pictureBox1.Image.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
                    byte[] pic = stream.ToArray();
                    cmd.Parameters.Add("@rowid",DbType.Int32);
                    cmd.Parameters["@rowid"].Value = Convert.ToInt32(treeView1.SelectedNode.Tag);
                    cmd.Parameters.Add("@pic",DbType.Object);
                    cmd.Parameters["@pic"].Value = pic;

                    cmd.Connection = conn;
                    cmd.CommandTimeout = 120;
                    cmd.ExecuteNonQuery();
                    cmd.Connection.Close();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error: " + ex.Message);
            }
        }

Jeg får en exception med: object reference not set to an instance of an object.
Avatar billede Syska Mester
08. december 2010 - 12:37 #10
Du behøver ikke sætte din connection string på dit command object, det gør du allerede i din constructor.

I hvad linje får du din exception? Lidt svært for mig at sætte mig frem til :-)
Avatar billede jackass- Nybegynder
08. december 2010 - 13:02 #11
Exception sker på denne linie:

pictureBox1.Image.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
Avatar billede Syska Mester
08. december 2010 - 13:19 #12
Virker som om der slet ikke er nogen billede ... alt efter hvad der er null ...

Kan du ikke smide en null check ind på din pictureBox.Image ?

mvh
Avatar billede jackass- Nybegynder
08. december 2010 - 13:51 #13
Hmm der var ikke noget billede, jeg manglede:

pictureBox1.Image = new Bitmap(strFileName);

..oppe i:

                if (openFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    strFileName = openFileDialog1.FileName;
                    pictureBox1.Image = new Bitmap(strFileName);
                }

Nu har jeg smidt et tjek ind, just in case:

                    if (pictureBox1.Image != null)
                        pictureBox1.Image.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);


Jeg får nu ingen fejl.. men billedet bliver stadig ikke gemt.. WTF? :-/

Sådan ser det komplet ud pt:




        public void SaveNewPicture()
        {
            try
            {
                string strFileName;
                openFileDialog1.Filter = "Image File (*.jpg;*.bmp;*.gif)|*.jpg;*.bmp;*.gif";
                openFileDialog1.FilterIndex = 1;
                openFileDialog1.Title = "Vælg billede";
                if (openFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    strFileName = openFileDialog1.FileName;
                    pictureBox1.Image = new Bitmap(strFileName);
                }

                SQLiteConnection connectionString = new SQLiteConnection("Data Source=" + Path.GetDirectoryName(Application.ExecutablePath) + "\\MyDB.s3db;Version=3;New=False;Compress=True");
                using (SQLiteConnection conn = new SQLiteConnection(connectionString))
                {
                    conn.Open();
                    string sql = "UPDATE MyTable set picture = @pic WHERE rowid = @rowid";
                    MessageBox.Show(sql);
                    SQLiteCommand cmd = new SQLiteCommand(sql);

                    MemoryStream stream = new MemoryStream();

                    if (pictureBox1.Image != null)
                        pictureBox1.Image.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
                    else
                        MessageBox.Show("Cannot save picture (null)");

                    byte[] pic = stream.ToArray();
                    cmd.Parameters.Add("@rowid", DbType.Int32);
                    cmd.Parameters["@rowid"].Value = Convert.ToInt32(treeView1.SelectedNode.Tag);
                    cmd.Parameters.Add("@pic", DbType.Object);
                    cmd.Parameters["@pic"].Value = pic;

                    cmd.Connection = conn;
                    cmd.CommandTimeout = 120;
                    cmd.ExecuteNonQuery();
                    cmd.Connection.Close();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error 8: " + ex.Message + " " + ex.InnerException);
            }
        }
Avatar billede arne_v Ekspert
09. december 2010 - 02:47 #14
Hvad returnerer cmd.ExecuteNonQuery() ?

Returnerer Convert.ToInt32(treeView1.SelectedNode.Tag) det som du tror den gør ?
Avatar billede jackass- Nybegynder
09. december 2010 - 11:31 #15
Jeg droppede i første omgang denne metode og gemmer nu bare filepath i databasen billederne som flade filer.

Men arne_v, jeg synes du skal have points'ene som tak for indsatsen, hvis du smider et svar?
Avatar billede arne_v Ekspert
09. december 2010 - 18:05 #16
ok
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester