Bild mehrmals speichern

  • VB.NET
  • .NET (FX) 4.0

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von VaporiZed.

    Bild mehrmals speichern

    Hallo,

    der folgende Code scannt über eine Funktion ein Bild und speichert dieses in eine Datei auf die Festplatte. Danach soll dieses Bild in das Programm auf das Arbeitsblatt geöffnet werden. Auf den Ersten Blick sieht das vorherige Speichern unsinnig aus, aber ich habe den Grund, daß die Bilddatei von tesseract 4 auf Text untersucht werden soll. Mein Problem ist nun, daß ich eine Fehlermeldung bekomme, wenn die Datei zum zweitenmal in die gleiche Datei gespeichert werden soll. Ich habe schon viel von "using" oder "stream" gelesen, doch irgendwie will es nicht klappen. Eigenartigerweise funktioniert eine ähnliche Funktion einwandfrei:

    VB.NET-Quellcode

    1. Private Sub BildScannenMenue_Click(sender As Object, e As EventArgs) Handles BildScannenMenue.Click
    2. Scannen()
    3. If Not GescanntesBild Is Nothing Then
    4. Try
    5. 'Bei Bedarf wird das gescannte Bild gedreht
    6. If ScannerAutomatischdrehen = 1 Then
    7. 'Wenn das Querformat ausgewählt ist, wird das Scannergebnis um
    8. '90 Grad nach Rechts gedreht.
    9. If Grafikausrichtung = 1 Then
    10. GescanntesBild.RotateFlip(RotateFlipType.Rotate90FlipNone)
    11. End If
    12. End If
    13. 'Wenn die Bilddatei bereits existiert, wird sie gelöscht.
    14. If My.Computer.FileSystem.FileExists(Userverzeichnis & "\Scanner.png") Then
    15. ' My.Computer.FileSystem.DeleteFile(Userverzeichnis & "\Scanner.png")
    16. End If
    17. 'Falls die Seitenränder berücksichtigt werden müssen, werden diese abgeschnitten.
    18. If SeitenraenderScannen = 1 Then
    19. X1 = GescanntesBild.Width / Seitenbreite * LinkerRand
    20. Y1 = GescanntesBild.Height / Seitenhoehe * ObererRand
    21. Breite = GescanntesBild.Width / Seitenbreite * (Seitenbreite - LinkerRand - RechterRand)
    22. Hoehe = GescanntesBild.Height / Seitenhoehe * (Seitenhoehe - ObererRand - UntererRand)
    23. OriginalbildBitmap.Dispose()
    24. Using OriginalbildBitmap As New Bitmap(Breite, Hoehe)
    25. FokusObjekt = Graphics.FromImage(OriginalbildBitmap)
    26. FokusObjekt.Clear(Color.White)
    27. FokusObjekt.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
    28. FokusObjekt.DrawImage(GescanntesBild, New Rectangle(X1, Y1, Breite, Hoehe))
    29. 'Das gescannte Bild wird in eine Bilddatei exportiert.
    30. OriginalbildBitmap.Save(Userverzeichnis & "\Scanner.png", ImageFormat.Png)
    31. FokusObjekt = Graphics.FromImage(FokusPuffer)
    32. End Using
    33. Else
    34. 'Das gescannte Bild wird in eine Bilddatei exportiert.
    35. GescanntesBild.Save(Userverzeichnis & "\Scanner.png", ImageFormat.Png)
    36. GescanntesBild.Dispose()
    37. End If
    38. Me.Text = Userverzeichnis & "\Scanner.png"
    39. 'Die Funktion "BildLaden" wird aufgerufen.
    40. BildLaden()
    41. OriginalbildAnzeigenMenue_Click(Me, EventArgs.Empty)
    42. BildUebersetzenMenue.Enabled = True
    43. HelligkeitScroll.Value = HelligkeitScroll.Maximum / 2
    44. OriginalbildEntladenMenue.Enabled = True
    45. Catch Fehler As Exception
    46. FrageFormular.Text = "Fehler"
    47. FrageFormular.Label1.Text = "Es ist ein Fehler beim Scannen aufgetreten. Schliessen Sie PunktBilder und starten das Programm erneut. Wenn der Fehler erneut auftritt, starten Sie den Computer neu und wiederholen Sie den Scanvorgang"
    48. FrageFormular.NeinBefehl.Visible = False
    49. FrageFormular.JaBefehl.Text = "OK"
    50. FrageFormular.ShowDialog()
    51. FrageFormular.Dispose()
    52. Exit Sub
    53. End Try
    54. Else
    55. FrageFormular.Text = "Hinweis"
    56. FrageFormular.Label1.Text = "Es wurde kein Bild erkannt"
    57. FrageFormular.NeinBefehl.Visible = False
    58. FrageFormular.JaBefehl.Text = "OK"
    59. FrageFormular.ShowDialog()
    60. FrageFormular.Dispose()
    61. Exit Sub
    62. End If
    63. End Sub


    Nun die Funktion, die ein Bild mehrmals nacheinander speichern kann, ohne wegen eines angeblichen Zugriffs einer anderen Prozedur abzubrechen:

    VB.NET-Quellcode

    1. Public Sub BildSpeichern(Bild As String)
    2. 'Diese Funktion öffnet das Datei-SpeichernDialogfeld. Wurde eine Datei
    3. 'ausgewählt oder angegeben, so wird geprüft, ob die Datei schon vorhanden ist.
    4. 'Wenn dies der Fall ist, wird der Benutzer gefragt, ob diese Datei überschrieben
    5. 'werden soll. Antwortet der Benutzer mit "Ja" so wird die Funktion "BildSpeichern"
    6. 'mit einem entsprechenden Parameter aufgerufen.
    7. DateiSpeichernDialog.Filter = "Bilddateien (*.bmp, *.jpg, *.jpeg, *.gif)|*.bmp;*.jpg;*.jpeg;*.gif"
    8. DateiSpeichernDialog.Title = Bild
    9. If DateiSpeichernDialog.ShowDialog = DialogResult.OK Then
    10. Breite = Seitenbreite - LinkerRand - RechterRand
    11. Hoehe = Seitenhoehe - ObererRand - UntererRand
    12. FokusPuffer.Dispose()
    13. FokusPuffer = New Bitmap(Breite, Hoehe)
    14. FokusObjekt = Graphics.FromImage(FokusPuffer)
    15. FokusObjekt.Clear(Color.White)
    16. If Bild = "Originalbild" Then
    17. FokusObjekt.DrawImage(OriginalbildBitmap, New Rectangle(0, 0, Breite, Hoehe))
    18. Else
    19. 'Ansonsten wird die Braillegrafik auf die zu exportierende Grafik übertragen.
    20. Using Ausgefuellt = New SolidBrush(Color.Black)
    21. Try
    22. X1 = 0
    23. Y1 = 0
    24. Do Until Y1 >= Zeilenzahl
    25. Do Until X1 >= ZeilenPunktzahl
    26. If PunktbildArray(X1, Y1) > HelligkeitScroll.Value Then
    27. FokusObjekt.FillEllipse(Ausgefuellt, New Rectangle((X1 * Punktgroesse) + (Punktgroesse * (Braillepunktgroesse / 10)), (Y1 * Punktgroesse) + (Punktgroesse * (Braillepunktgroesse / 10)), Punktgroesse * (1 - (Braillepunktgroesse / 5)), Punktgroesse * (1 - (Braillepunktgroesse / 5))))
    28. End If
    29. X1 = X1 + 1
    30. Loop
    31. X1 = 0
    32. Y1 = Y1 + 1
    33. Loop
    34. Catch myerror As Exception
    35. End Try
    36. End Using
    37. End If
    38. FokusPuffer.Save(DateiSpeichernDialog.FileName)
    39. FokusPuffer.Dispose()
    40. FokusPuffer = New Bitmap(SichtfensterPicture.ClientSize.Width, SichtfensterPicture.Height)
    41. FokusObjekt = Graphics.FromImage(FokusPuffer)
    42. End If
    43. End Sub


    Wenn Jemand von euch eine Lösung hat, würde ich mich sehr über ein Beispiel freuen.

    Vielen Dank schon mal im Voraus

    *Code-Tag Formatierung korrigiert* ~NoFear23m

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Nofear23m“ ()

    @tron25 OK.
    Sieh Dir mal Deinen Text und Deinen Code an und sage mir, warum ich keine Lust habe, Dir zu helfen...
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hallo,

    ich habe deshalb die kompletten Funktionen geschrieben, um einen Überblick von der Funktionsweise zu bekommen. Der Fehler tritt auf, wenn ich (in der ersten Funktion) die Bitmap speichern möchte:

    VB.NET-Quellcode

    1. Using OriginalbildBitmap As New Bitmap(Breite, Hoehe)
    2. FokusObjekt = Graphics.FromImage(OriginalbildBitmap)
    3. FokusObjekt.Clear(Color.White)
    4. FokusObjekt.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
    5. FokusObjekt.DrawImage(GescanntesBild, New Rectangle(X1, Y1, Breite, Hoehe))
    6. 'Das gescannte Bild wird in eine Bilddatei exportiert.
    7. OriginalbildBitmap.Save(Userverzeichnis & "\Scanner.png", ImageFormat.Png)
    8. FokusObjekt = Graphics.FromImage(FokusPuffer)
    9. End Using


    Abgesehen davon würde ich mir an deiner Stelle die Mühe für eine Antwort sparen, wenn du sowieso nicht helfen möchtest.

    tron25 schrieb:

    wenn du sowieso nicht helfen möchtest.
    Das ist falsch, solltest Du eigentlich erkennen.
    Das, was Du als Code abgibst, sollte zumindest ordentlich formatiert sein. Füge den Code per D&P aus Deiner Entwicklingsumgebung ein und überzeuge Dich, dass er auch so aussieht.
    In welcher Codezeile kommt welcher Fehler?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hallo,

    das Problem hatte ich schon einmal bei einem meiner früheren Beiträge. Ich bin blind und daher die Formatierung nicht so gut nachvollziehen. Ich habe den Text in eckige Klammern und einem "vbnet" eingeklammert. Kann es sein, daß es geschweifte sind?

    Code mit geschweiften Klammern:
    {vbnet}
    Test = test
    {/vbnet}

    Sieht das jetzt besser aus?

    Wenn deine erste Antwort sich tatsächlich nur auf die falsche Formatierung bezogen hat, entschuldige ich mich bei dir.
    @tron25 Die VB-Klammern sind schon die richtigen. Die üblichen Einrückungen zur Strukturierung fehlen, da ist der Code einfach nicht überschaubar.
    Was ist nun mit der Fehlermeldung und in welcher Zeile?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Der von dir verwendete BB-code im ersten beitrag, ist korrekt.
    Das problem ist, das die Einrückung verloren gegangen ist.

    Ohne die möglichkeit, der optischen Kontrolle, weiß ich jetzt aber auch nicht, wie du das bewerkstelligen sollst.
    Vorerst kann ja mal ein Moderator drüber Bügeln.
    War so frei die Code-Tag Formatierung zu bearbeiten.
    Ausnahmsweise schreibe ich dies nur als extra-Beitrag weil doch schon einige Posts dazwischenliegen.

    Grüße
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    In Ordnung. Da werde ich versuchen, den nötigsten Code zu schreiben:

    VB.NET-Quellcode

    1. Using OriginalbildBitmap As New Bitmap(Breite, Hoehe)
    2. FokusObjekt = Graphics.FromImage(OriginalbildBitmap)
    3. FokusObjekt.Clear(Color.White)
    4. FokusObjekt.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
    5. FokusObjekt.DrawImage(GescanntesBild, New Rectangle(X1, Y1, Breite, Hoehe))
    6. 'In der nächsten Zeile taucht die Fehlermeldung auf.
    7. OriginalbildBitmap.Save(Userverzeichnis & "\Scanner.png", ImageFormat.Png)
    8. End Using


    Die Fehlermeldung lautet:
    System.Runtime.InteropServices.ExternalException (0x80004005): Allgemeiner Fehler in GDI+.
    bei System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
    bei System.Drawing.Image.Save(String filename, ImageFormat format)
    bei PunktBilder.PunktbilderFormular.BildScannenMenue_Click(Object sender, EventArgs e) in D:\Programmierung\PunktBilder\PunktBilder 2019\PunktbilderFormular.vb:Zeile 10672.

    Gruß

    tron25 schrieb:

    Allgemeiner Fehler in GDI+.
    Das ist ein echt blöder Fehler, der tief im Framework stattfindet.
    Setz mal einen Haltepunkt drauf und sieh Dir an, ob die Bild-Properties stimmig sind.
    Also einmal den Gut- und einmal den Schlecht-Fall.
    Ansonsten:
    Mach ein kleines Testprojekt und probiere, den Code da reinzupacken, der den Fehler reproduziert.
    ====
    Was ganz genau ist FrageFormular?
    Wo wird das instanziiert?
    Und warum rufst Du diesen Dialog nicht per Using auf?
    Dialoge: Instanziierung von Forms und Aufruf von Dialogen
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Es geht schon bei solchen Sachen los, dass der Zielspeicherpfad nicht stimmt bzw. nicht "erreicht werden kann", also effektiv nicht gültig ist. Dann kommt auch die Exception.

    btw: "bei PunktBilder.PunktbilderFormular.BildScannenMenue_Click(Object sender, EventArgs e) in D:\Programmierung\PunktBilder\PunktBilder 2019\PunktbilderFormular.vb:Zeile 10672."
    Wow. Was ne Datei. Respekt, dass Du da die Übersicht behältst :thumbup: (kein Sarkasmus!)
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    FrageFormular ist eine Form, die ich für Fragen, Hinweise oder Warnungen verwende.
    In einem Modul werden die Formulare instanziiert.
    Ich habe mir den Beitrag über die Aufrufmethoden von Formularen in VB.net angesehen und werde diese in mein Programm einbauen.

    z.B.

    VB.NET-Quellcode

    1. public FrageFormular as new FrageFormular


    Ich bin noch nicht so fit mit "Using"s, daher auch meine Schwierigkeiten damit.

    Das mit dem falschen Zielspeicherort verstehe ich nicht, denn beim ersten Mal funktioniert es immer. Erst ab dem zweiten Mal bricht das Programm ab.

    Gruß
    @tron25 Klar.
    Diese Form wird genau ein Mal instanziiert und nach deren Aufruf wird sie zerstört.
    Bevor Du sie wieder aufrufen kannst, musst Du sie erneut instanziieren.
    Wie gesagt, vestehe dies: Dialoge: Instanziierung von Forms und Aufruf von Dialogen
    ===========
    Mach folgendes, überall:

    VB.NET-Quellcode

    1. public FrageFormular as new FrageFormular
    '=>

    VB.NET-Quellcode

    1. public FrageFormular as FrageFormular
    und

    VB.NET-Quellcode

    1. FrageFormular.Dispose()
    =>

    VB.NET-Quellcode

    1. FrageFormular.Dispose()
    2. FrageFormular = Nothing
    Dann musst Du überall, wo ein Dialog aufgerufen wird, mit New eine neue Instanz erstellen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „RodFromGermany“ ()

    tron25 schrieb:

    warum muß ich es noch auf nothing setzen?
    Damit bei einem nächsten Zugriff eine Null-Pointer-Exception kommt, die Du sofort verstehst und beheben kannst:

    RodFromGermany schrieb:

    mit New eine neue Instanz erstellen
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich habe meine kompletten Quellcode nun an die neue Art, Formulare zu öffnen angepaßt.

    VB.NET-Quellcode

    1. 'Deklaration:
    2. Private FrageFenster As FrageFormular


    Innerhalb der entsprechenden Sub steht:

    VB.NET-Quellcode

    1. If FrageFenster Is Nothing OrElse FrageFenster.IsDisposed Then
    2. FrageFenster = New FrageFormular
    3. End If
    4. FrageFenster.Text = "Info"
    5. FrageFenster.Label1.Text = "Es wurde keine Punktgrafik zum exportieren gefunden"
    6. FrageFenster.JaBefehl.Text = "OK"
    7. FrageFenster.NeinBefehl.Visible = False
    8. FrageFenster.ShowDialog(Me)
    9. FrageFenster.Dispose()
    10. FrageFenster = Nothing


    Beim Ausführen bekomme ich folgende Fehlermeldung:
    Schweregrad Code Beschreibung Projekt Datei Zeile Unterdrückungszustand
    Fehler BC32000 Auf die lokale Variable "FrageFenster" kann nicht verwiesen werden, bevor sie deklariert ist. PunktBilder D:\Programmierung\PunktBilder\PunktBilder 2019\PunktbilderFormular.vb 9656 Aktiv

    Ich habe doch "FrageFenster" ganz oben deklariert?
    Nun, wenn es heißt: Auf die lokale Variable "FrageFenster" kann nicht verwiesen werden, dann scheint es 2 zu geben. Denn Private FrageFenster kann nicht innerhalb einer Prozedur stehen, dies ist also keine lokale Variable, sondern eine Klassenvariable. Doch der Fehler sagt, dass er mit einer lokalen Variable ein Problem hat. Daher vermute ich, dass es 2 Deklarationen gibt. Kann es sein, das diese nach dem hier gezeigten Code noch kommt? Also ein Dim FrageFenster irgendwo noch in dieser Prozedur steht?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @tron25 Ist das eine Shared Prozedur?
    Mach es mit Using:

    VB.NET-Quellcode

    1. Using FrageFenster = New FrageFormular
    2. FrageFenster.Text = "Info"
    3. FrageFenster.Label1.Text = "Es wurde keine Punktgrafik zum exportieren gefunden"
    4. FrageFenster.JaBefehl.Text = "OK"
    5. FrageFenster.NeinBefehl.Visible = False
    6. FrageFenster.ShowDialog(Me)
    7. Emd Using
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Es gab tatsächlich noch eine doppelte Deklaration. Nun funktionieren die Formularaufrufe, wie sie sollen.

    Wegen dem eigentlichen Problem habe ich gestern mal versucht, logisch nachzudenken. Irgendwo hatte ich mal gelesen, daß eine Datei, deren Inhalt in eine Bitmap geladen wird, blockiert ist. In meiner ersten Funktion wird zuerst ein Bild gescannt, dann in eine Datei exportiert und diese dann mit einer schon vorhandenen Funktion in das Programm geladen. Ich habe Heute das gescannte Bild direkt ohne Umwege geladen. Juhu! Es funktioniert.

    Ich danke euch für eure Hilfe.

    Wie kann ich das Thema als gelöst und beendet markieren?
    Ganz oben bei einem selbstgestarteten Thema gibt es 2 Möglichkeiten: auf [Thema bearbeiten] klicken und dann auf "als erledigt markieren" oder mit einem Doppelklick auf das kleine leere Quadrat neben dem Titel Deines Threads.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.