Laden...

OLE-Objekt aus Access 2007 in PictureBox einfügen

Erstellt von Johnny B vor 13 Jahren Letzter Beitrag vor 13 Jahren 8.554 Views
J
Johnny B Themenstarter:in
47 Beiträge seit 2010
vor 13 Jahren
OLE-Objekt aus Access 2007 in PictureBox einfügen

Hallo Community, ich verzweifle.

Habe google schon vergewaltigt und diverse Varianten an Code auspropiert aber nichts scheint zu funktionieren.

Wie der Titel schon sagt, möchte ich ein Bild (Windows 7 Beispielbild: Penguins.jpg 1024 x 768) aus einer Access 2007 Tabelle auslesen und in eine Picturebox einfügen.

Muss dazu sagen ich habe noch nie ein Bild aus einer Datenbank ausgelesen, habe da also keine Erfahrung.

Hier der Code mit dem ich es probiert habe:

Variante 1


OleDbConnection con = new OleDbConnection(
                @"Provider=Microsoft.ACE.OLEDB.12.0;
            Data Source=C:\Users\xy\Desktop\Bestellungen.accdb");

            OleDbCommand cmd = new OleDbCommand("Select top 1 Foto from Bestellzeile", con);
            con.Open();
            byte[] imageData = (byte[])cmd.ExecuteScalar();
            con.Close();
            pictureBox1.Image = Image.FromStream(new MemoryStream(imageData));

Variante 2


OleDbConnection con = new OleDbConnection(
                @"Provider=Microsoft.ACE.OLEDB.12.0;
            Data Source=C:\Users\xy\Desktop\Bestellungen.accdb");

OleDbCommand cmd = new OleDbCommand("Select top 1 Foto from Bestellzeile", con);
            con.Open();
            OleDbDataReader oReader = cmd.ExecuteReader(CommandBehavior.SequentialAccess);

            while (oReader.Read())
            {
                byte[] imageBytes = (byte[])oReader.GetValue(0);

                MemoryStream ms = new MemoryStream(imageBytes, 78, imageBytes.Length - 78);
                ms.Write(imageBytes, 78, imageBytes.Length - 78);
                //Bitmap bmp = new Bitmap(ms);
                pictureBox1.Image = Image.FromStream(ms);
            }

            oReader.Close();
            con.Close();

Debugge ich, wird das Bild einfach nicht geladen, es kommt aber auch keine Fehlermeldung.
Starte ich ohne Debuggen, kommte ein Fehlerfenster mit der Meldung "Ungültiger Parameter".

Egal ob bei Variante 1 oder Variante 2.

Detail:
************** Ausnahmetext **************
System.ArgumentException: Ungültiger Parameter.
bei System.Drawing.Image.FromStream(Stream stream, Boolean useEmbeddedColorManagement, Boolean validateImageData)
bei System.Drawing.Image.FromStream(Stream stream)
bei Bestellverwaltung.Form1.Form1_Load(Object sender, EventArgs e) in C:\Users\xy\Desktop\Bestellverwaltung\Bestellverwaltung\Form1.cs:Zeile 51.
bei System.Windows.Forms.Form.OnLoad(EventArgs e)
bei System.Windows.Forms.Form.OnCreateControl()
bei System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
bei System.Windows.Forms.Control.CreateControl()
bei System.Windows.Forms.Control.WmShowWindow(Message& m)
bei System.Windows.Forms.Control.WndProc(Message& m)
bei System.Windows.Forms.ScrollableControl.WndProc(Message& m)
bei System.Windows.Forms.ContainerControl.WndProc(Message& m)
bei System.Windows.Forms.Form.WmShowWindow(Message& m)
bei System.Windows.Forms.Form.WndProc(Message& m)
bei System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
bei System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
bei System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

Vielleicht kann mir wer einen Tipp geben wo es da hakt.
mfg
Johnny

X
1.177 Beiträge seit 2006
vor 13 Jahren

huhu,

ja, der Stream für Image ist "ungültig".

für Version 1: ExecutScalar liefert nur Feld 1 aus Datenzeile 1 zurück - ich bezwefle, dass hier das Image als Bytes komplett zurück kommt.

zu 2. Warum wird erst ab Byte 78 gelesen?

schau Dir mal http://msdn.microsoft.com/de-de/library/87z0hy49.aspx an, da gehts um genau dieses Thema.

😃

Xynratron

Herr, schmeiss Hirn vom Himmel - Autsch!

Die Erfahrung zeigt immer wieder, dass viele Probleme sich in Luft auslösen, wenn man sich den nötigen Abstand bzw. Schlaf gönnt.

J
Johnny B Themenstarter:in
47 Beiträge seit 2010
vor 13 Jahren

hi,

Hab in einem Forum gelesen dass man erst ab 78 auslesen muss. Alles davor sei nur header. Keine Ahnung ob das so stimmt.

Ok, werd mir den Link mal zu Gemüte führen, danke dafür!

mfg
Johnny

X
1.177 Beiträge seit 2006
vor 13 Jahren

huhu,"

Hab in einem Forum gelesen dass man erst ab 78 auslesen muss. Alles davor sei nur header.

ok, denjenigen fordere ich gerne auf dem Oktoberfest heraus. Vielleicht wirds mir dann klar. Aktuell behaute ich aber: absoluter Blödsinn. Keine DB "verschwendet" mal kurz XX Bytes.

Wenn Deine Datenbank dir Daten liefert, dann lies bitte immer alles. Wenn es Probleme gibt, dann kann mann immer noch den Stream analysieren.

😃

Xynratron

Herr, schmeiss Hirn vom Himmel - Autsch!

Die Erfahrung zeigt immer wieder, dass viele Probleme sich in Luft auslösen, wenn man sich den nötigen Abstand bzw. Schlaf gönnt.

F
10.010 Beiträge seit 2004
vor 13 Jahren

Das mit den 78 Byte betrifft Bilder die man als OLE Object per Access in die DB gepackt hat.

Wenn das "nur" Bilder sind, dann kann/muss das natürlich weg.

286 Beiträge seit 2011
vor 13 Jahren

also ich mag mich da direkt mal einklinken..
sitz seit ner weile an dem ähnlichen wenn nich sogar dem gleichen problem:

ich will bilderin ne access-db schreiben und wieder auslesen undhab mich dabei recht genau an die wege aus msdn gehalten.

in nem kleinen testprogramm (ne form, 2button und ne picturebox)
funktioniert das schreiben und lesen wunderbar mit folgendem code:

Schreiben:


                   OleDbConnection cn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=test.mdb");

            OleDbCommand cmd = new OleDbCommand("UPDATE Objekte SET Test=@BildData WHERE Projekt=1", cn);
            String Filepath = "";
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                Filepath = openFileDialog1.FileName;
            }

            FileStream myFileStream = new FileStream(Filepath, FileMode.Open, FileAccess.Read);
            Byte[] myByte = new Byte[myFileStream.Length];
            myFileStream.Read(myByte, 0, myByte.Length);
            myFileStream.Close();

            OleDbParameter prm = new OleDbParameter("@BildData", OleDbType.VarBinary, myByte.Length, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Current, myByte);
            cmd.Parameters.Add(prm);

            cn.Open();
            cmd.ExecuteNonQuery();
            cn.Close();

Lesen:


            OleDbConnection cn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=test.mdb");

            cn.Open();

            OleDbCommand cmd = new OleDbCommand("SELECT Test FROM Objekte WHERE Projekt=1", cn);
            OleDbDataReader myReader = cmd.ExecuteReader(CommandBehavior.SequentialAccess);

            while (myReader.Read())
            {
                byte[] myByte = (byte[])myReader.GetValue(0);
                MemoryStream myStream = new MemoryStream(myByte, 0, myByte.Length);
                myStream.Write(myByte, 0, myByte.Length);
                pictureBox1.Image = Image.FromStream(myStream);
            }
            cn.Close();

Das klappt soweit wunderbar und ohne Probleme....

Schreibe ich nun den gleichen code in mein eigentliches programm. funktioniert es nicht mehr mit der gleichen Fehlermeldung wie bei Johhny B... (ArgumentException, Ungültiger Parameter..)

Was mir beim debuggen aufgfallen ist:
In der funktionierenden Version ist das ist des myByte so in der Dimension byte[280783].in der nicht funktionierenden nur byte[12].. ich hab absolut keine idee mehr woher das kommen kann...
beim schreiben sind se in beiden Versionen gleich groß für identische bilder..

2+2=5( (für extrem große Werte von 2)

J
Johnny B Themenstarter:in
47 Beiträge seit 2010
vor 13 Jahren

schau Dir mal
>
an, da gehts um genau dieses Thema.

😃

Xynratron

Ok, hier wird ein File mit Hilfe eines Streams aufgebaut. Kann ich ein Image mit Hilfe eines Streams "aufbauen"?

J
Johnny B Themenstarter:in
47 Beiträge seit 2010
vor 13 Jahren

Lesen:

  
            OleDbConnection cn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=test.mdb");  
  
            cn.Open();  
  
            OleDbCommand cmd = new OleDbCommand("SELECT Test FROM Objekte WHERE Projekt=1", cn);  
            OleDbDataReader myReader = cmd.ExecuteReader(CommandBehavior.SequentialAccess);  
  
            while (myReader.Read())  
            {  
                byte[] myByte = (byte[])myReader.GetValue(0);  
                MemoryStream myStream = new MemoryStream(myByte, 0, myByte.Length);  
                myStream.Write(myByte, 0, myByte.Length);  
                pictureBox1.Image = Image.FromStream(myStream);  
            }  
            cn.Close();  
  

Das klappt soweit wunderbar und ohne Probleme....

Schreibe ich nun den gleichen code in mein eigentliches programm. funktioniert es nicht mehr mit der gleichen Fehlermeldung wie bei Johhny B... (ArgumentException, Ungültiger Parameter..)

Es ist echt zum Haare ausraufen. Kein Plan was da falsch läuft. Keiner ne Idee??

F
10.010 Beiträge seit 2004
vor 13 Jahren

Wer schreibt denn die Bilder in die DB?

J
Johnny B Themenstarter:in
47 Beiträge seit 2010
vor 13 Jahren

Die hab ich testweise per Hand im Access reingeschrieben.
Also Rechtsklick auf die Ausprägung und "Objekt einfügen..."

F
10.010 Beiträge seit 2004
vor 13 Jahren

Dann erstelle eine Funktion die das was da in der Spalte steht mal in eine Datei schreibt.

Wenn du weisst das da z.b. ein jpg drin sein soll, schaust du mit einem hexfileviewer wie die Datei am Anfang aussieht.

Davon machst du dann mal einen Screenshot, und dann kann man dir auch weiterhelfen.

J
Johnny B Themenstarter:in
47 Beiträge seit 2010
vor 13 Jahren

Also ich hoffe ich hab das jetzt korrekt verstanden.
Mit http://msdn.microsoft.com/de-de/library/87z0hy49.aspx habe ich das Bild nun in eine Datei rausgeschrieben (sie lässt sich allerdings nicht öffnen 😕 )

Screen nach rausschreiben:
http://img545.imageshack.us/i/hexpy.png/

Bild davor (original - bmp)
http://img156.imageshack.us/img156/3820/hexdavor.png

MfG
Johnny B

F
10.010 Beiträge seit 2004
vor 13 Jahren

Jetzt ist das auch klar 😉

Wie du siehst ist deine Orginal Datei ab offset 77 zu sehen.

Du wirst wahrscheinlich ( entgegen deiner Aussage ) nicht nur so wie im MSDN auslesen, sondern irgendwie das erste Byte überlesen.

Wenn du als erst 78 bytes überliest, hast du auch wieder den BMP Header.

J
Johnny B Themenstarter:in
47 Beiträge seit 2010
vor 13 Jahren

Vielen Dank erstmal für die Hilfe.

Ich kann aber versichern, ich hab nix am MSDN Code verändert außer Connectionstring und Abfrage! 😉

Habe jetzt

// Reset the starting byte for the new BLOB.
  startIndex = 0;

auf

// Reset the starting byte for the new BLOB.
  startIndex = 77;

umgeändert. Nun funktioniert es. Das heißt ich kann die erzeugte Bild-Datei öffnen.
Bei .jpg Bildern ist die Startposition/offset 210.

Das Bild kann nun auch in eine Picturebox eingelesen werden. Siehe:

        void BildEinlesen()
        {
     
            OleDbConnection cn = new OleDbConnection(
    @"Provider=Microsoft.ACE.OLEDB.12.0;
            Data Source=C:\Users\xy\Desktop\Bestellungen.accdb");

            cn.Open();

            OleDbCommand cmd = new OleDbCommand("Select top 1 Foto from Bestellzeile", cn);
            OleDbDataReader myReader = cmd.ExecuteReader(CommandBehavior.SequentialAccess);
            MemoryStream myStream = null;

            while (myReader.Read())
            {
                byte[] myByte = (byte[])myReader.GetValue(0);
                myStream = new MemoryStream(myByte, 77, myByte.Length - 77);
                myStream.Write(myByte, 77, myByte.Length - 77);
            }
            pictureBox1.Image = Image.FromStream(myStream);
            cn.Close();
        }

77 Byte Offset scheint also zumindest für .bmp Dateien zu funktionieren. Jpg ist 210. Weiteres ist noch nicht getestet.

Vielen Dank an alle Helfer!!
@Xynratron: Da wird ein Bier beim Oktoberfest fällig! 😉

LG
Johnny

Edit: Scheint aber etwas umständlich zu sein. Ich muss so ja immer irgendwie abfragen welcher Dateityp in der DB gespeichert ist...

F
10.010 Beiträge seit 2004
vor 13 Jahren

Oder verhindern das Access da OleObjekte hineinschreibt.

J
Johnny B Themenstarter:in
47 Beiträge seit 2010
vor 13 Jahren

Naja, der Datentyp ist ja Ole-Objekt. Dann muss das auch rein oder versteh ich was falsch?

Das mit dem Offset kann so auch leider nicht stimmen. Je nach Datei ist jetzt das Offset verschieden. Das heißt, .jpg hat nicht immer ein offset von 210 sondern das ist auch verschieden. Das kann doch nicht so kompliziert sein! 😦

F
10.010 Beiträge seit 2004
vor 13 Jahren

Nein, der Datentyp ist Image, was unter .NET einfach nur der Begriff für ein Byte Array ist.

Nur weil Du ein Oleobject per Access hineingeladen hast, ist dieses Problem entstanden.
Wenn du die Daten per .NET dort hinein lädst ist da kein Header.

Und natürlich ist das einfacher.
Du musst ja nur den OleObject Header parsen, dann weist du ja, was da drin ist, wo das anfängt und wie lang das ist.

J
Johnny B Themenstarter:in
47 Beiträge seit 2010
vor 13 Jahren

kleine Ergänzung:

Habs mit dem Code von emuu probiert. Also das Bild per Code ein- und wieder ausgelesen. Und so funktioniert es jetzt ohne Probleme und das Problem mit dem Offset fällt auch weg. 😃

Kleine Frage am Rande die nicht zwingend mit dem Thread was zu tun hat. Möchte dafür aber keinen eigenen thread aufmachen:

  • aus Form1 öffne ich Form2 mit ShowDialog()
  • in Form 2 werden Daten in die Datenbank geschrieben

Wird Form2 geschlossen möchte ich ich mir das Dataset mit dem Adapter (von Form1) neu füllen. (zur Aktualisierung). Gibt es dazu ein Event von Form1 oder wie reagiere ich am besten von Form1 auf das Schließen von Form2.
Habe es mit "Enter" probiert, aber das feuert irgendwie nicht...

mfg
JOhnny

F
10.010 Beiträge seit 2004
vor 13 Jahren

Naja, die Routine in Form1 die ShowDialog aufruft, ist ja direkt danach wieder dran.
[FAQ] Kommunikation von 2 Forms

J
Johnny B Themenstarter:in
47 Beiträge seit 2010
vor 13 Jahren

danke 😃

X
1.177 Beiträge seit 2006
vor 13 Jahren

huhu,

@Xynratron: Da wird ein Bier beim Oktoberfest fällig! 😉

Nur weil Du ein Oleobject per Access hineingeladen hast, ist dieses Problem entstanden.

Bild per Code ein- und wieder ausgelesen. Und so funktioniert es jetzt ohne Probleme und das Problem mit dem Offset fällt auch weg

Du zahlst 😃

Herr, schmeiss Hirn vom Himmel - Autsch!

Die Erfahrung zeigt immer wieder, dass viele Probleme sich in Luft auslösen, wenn man sich den nötigen Abstand bzw. Schlaf gönnt.