Image-Array wie behandeln?

  • VB.NET
  • .NET (FX) 4.0

Es gibt 42 Antworten in diesem Thema. Der letzte Beitrag () ist von ~blaze~.

    Zwischen dem primären Aufbau des Array und des List... für Images dürfte kein großer Unterschied sein. Beide werden vermutlich über eine Tabelle von Adressverweisen realisiert. Diese Adressverweise zeigen auf die eigentlichen Objekte. Wie sollte es auch anders sein. Der Unterschied beginnt bei den Erweiterungen. Möglicherweise erstreckt er sich auch auf die Behandlung von Löschungen.

    Es scheint kein Speicherproblem zu sein, ein Array in folgendem Sinne zu intialisieren:

    Dim IMG(5000) as Image

    Damit lassen sich auch große Verzeichnisse bedienen und die oben erwähnte Tabelle von Adressen hat im 32-Bit-Adressraum eine Größe von 20.000 Byte. Man könnte also problemlos auch noch größer dimensionieren und dieses Array für unterschiedliche Inhalte und Mengen immer wieder verwenden. Das Problem liegt bei den Images selbst. Da kann nicht einfach ein Image auf den Platz des anderen geschoben werden. Jedes Image braucht einen separaten Speicherbereich. Deshalb muss bei nicht mehr benötigten Array-Images zwingend eine Freigabe stattfinden und wenn man sich nicht auf das System verlassen will und auch nicht weiß, wie das System damit umgeht, dann eben explizit.

    Mich hätte eher die Frage interessiert, ob die Freigabe gleich in Verbindung mit bestimmten Befehlen passiert , wie etwa

    Redim IMG(ANZ-1) oder
    IMG.clear(...) oder
    IMG(i) = Nothing oder
    IMG(i) = IMGNeu

    auf die es aber scheinbar keine sichere Antwort gibt. Hinweis: Ich rede stets von unabhängigen Images, die Ergebnis einer Function sind.
    Wie gesagt Intern hat eine List(Of ) ein Array, der Unterschied besteht hauptsächlch darin, wann dieses vergrößert/verkleinert wird. Arrays zu verwenden ergibt nur noch Sinn, wenn man genau weiß, welche Größe es haben wird und diese sich nicht ändert.

    Die Erstellung eines solch großen Arrays ist natürlich möglich, da dieses erstmal leer ist und noch gar keine Instanzen enthält.
    Der Weg einfach ein riesen Array zu erzeugen(hoffen das es groß genug ist) ist der Weg, den man mit C ging(selbst dort hat man bereits arten von Listen implementiert) und in VB6 eben mit Redim. Aber warum selbst noch einmal machen, wenn es das bereits gibt. Relativ Speicher und Geschwindigkeitseffizient.

    Redim lassen wir einfach mal ganz außen vor, bitte einfach nicht mehr verwenden.
    IMG.Clear(), wenn du eine List(Of) hast, wird die Referenzen auf die Images überschreiben, sobald du dort wieder Dinge reinschiebst. Wenn nun keine Referenz mehr auf die alten Images vorhanden ist wird sich der GC irgendwann darum kümmern, wann das ist kann man nicht vorhersehen.
    IMG(i) = Nothing damit entfernst du ebenfalls die Referenz, wann das Objekt aber gelöscht wird ist wieder dem GC überlassen
    IMG(i) = IMGNeu und hier wiederum ebenso.

    Also wenn du explizit weißt, wann eine Instanz nicht mehr gebraucht wird, kannst du diese einfach mit IMG(i).Dispose entfernen, dann brauchst du dir keine Sorgen darum zu machen, dass der GC dies sonst wann macht/die Thumbnails solange nicht Zugreifbar sind...

    Aber für die Allgemeine Frage: Ja die Instanzen werden irgendwann gelöscht, es ist kein MemoryLeak vorhanden.
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Es hat sich folgende Herangehensweise auf der Basis von Array ergeben:

    VB.NET-Quellcode

    1. Public IMG(5000) As Image
    2. GC.Collect 'Bei Verzeichniswechsel
    3. If Not IMG(i) Is Nothing Then 'Befüllung
    4. IMG(i).Dispose()
    5. IMG(i) = Nothing
    6. End If
    7. IMG(i) = GetThumb(IMGFls(i).FullName)


    Das Array wird immer bis zur Anzahl der Images befüllt. Kein Redim erforderlich. Ich denke, das wars. Demnächst zur Umgewöhnung mit List of. Wird kein großer Unterschied.

    Danke an alle.

    drschef schrieb:

    Umgewöhnung mit List of
    kannst Du schlagartig machen, da die Zugriffe mit denen vom Array gleich sind.

    drschef schrieb:

    VB.NET-Quellcode

    1. If Not IMG(i) Is Nothing Then 'Befüllung
    machst Du

    VB.NET-Quellcode

    1. If IMG(i) IsNot Nothing Then 'Befüllung

    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!
    @RodFromGermany nur interessehalber, warum?
    Ich sehe nur einen Unterschied und das ist ein Leerzeichen das ich mir spare zu tippen.

    Gibt es "im Hintergrund" noch andere Schwerwiegendere Unterschiede?
    There is no CLOUD - just other people's computers

    Q: Why do JAVA developers wear glasses?
    A: Because they can't C#

    Daily prayer:
    "Dear Lord, grand me the strength not to kill any stupid people today and please grant me the ability to punch them in the face over standard TCP/IP."

    ErfinderDesRades schrieb:

    ist leichter aufzufassen.

    Joah, sonst gibt es keinen Hintegrund?
    There is no CLOUD - just other people's computers

    Q: Why do JAVA developers wear glasses?
    A: Because they can't C#

    Daily prayer:
    "Dear Lord, grand me the strength not to kill any stupid people today and please grant me the ability to punch them in the face over standard TCP/IP."

    Schamash schrieb:

    Hintegrund
    Den IsNot-Operator hat sich Microsoft patentieren lassen. :D
    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!
    GC.Collect solltest du übrigens nicht aufrufen. ;) Das diente nur dazu, die Freigabe von Ressourcen zu erzwingen. Ich würde für dein Problem auch eine List(Of Image) verwenden, übrigens.

    Als Hintergrundinfo: Array.Resize kann statt Redim Preserve verwendet werden, eine Neuinstanzierung für Redim.

    Viele Grüße
    ~blaze~
    Ich habe von den Hinweisen einiges verwerten können und auch wieder einen Motivationsschub bekommen. Das heißt, ich kann eigentlich das Ergebnis beiseite legen.

    Und wenn du eine ganze Methode posten könntest


    Danke für das Hilfsangebot. Leider gibt es keine in sich abgegrenzte Methode. Ich habe mir die sehr komplexe Quelle daraufhin angesehen, was man herauslösen könnte. Aber es dürfte sehr mühselig werden, aus den 2000 Zeilen etwas zu separieren, wenn es nicht klar ist, wonach. Die Image-Geschichte dient dazu, gedruckte Fotoarchive bis hin zu Einzeldruck von Fotos mit einer großen Zahl von Steuer-Parametern zu erstellen. Da spielt die mehrseitige Drucksteuerung hinein, der Hintergrundprozeß für die Aufbereitung der Images, eine Menge Registry-Handling und die ganze GDI+-Geschichte für die stark parametrisierte Layout-Gestaltung. Ein Download der Lösung findet sich hier unter der Bezeichnung 'DruckFotoArchiv'.
    da sollte man sich womöglich eine neue Architektur überlegen ;)
    Denn große Projekte haben meist nicht viele Zeilen, sondern viel mehr viele Dateien(zumindest bei Hochsprachen).
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---

    drschef schrieb:

    Leider gibt es keine in sich abgegrenzte Methode.
    Na, dann fang mal an damit - du lieber Himmel!

    Schreib eine Methode BeiVerzeichniswechsel(), und mach dir Gedanken, wie du ihr ein Bild-Array und das Verzeichnis übergibst.

    Vlt. auch Grundlagen: Fachbegriffe hilfreich, was genau eine Methode ist, der man was übergibt.
    da sollte man sich womöglich eine neue Architektur überlegen

    Na, dann fang mal an damit - du lieber Himmel!


    Sorry, ich wollte ausdrücken, dass da viele Dinge ineinandergreifen. Natürlich gibt es eine Architektur und eine Strukturierung. Natürlich gibt es Funktionen und Event-Prozeduren, z.B. die folgende. Dazu ein paar Bilder von der Oberfläche 2 für Bildübersicht und 2 für Fotodruck.

    VB.NET-Quellcode

    1. Public Sub PageGraphic()
    2. Dim HColl, WColl As Integer 'Höhe/Breite Kollektion in Pixel
    3. Dim SColl, ZColl As Integer 'Anzahl Zeilen/Spalten Kollektion
    4. Dim z, s, l As Integer 'Indizes für Zeile, Spalte und laufendes Bild
    5. Dim px, py As Integer 'Zielrechteck für Fingerabdruck
    6. Dim zx, zy As Integer 'Eckpunkte der Zelle für die Markierung
    7. Dim ax, ay As Integer 'Versatz für Druckgrafik
    8. Dim bx, by As Integer 'Versatz für Zellmatrix im Druckbereich
    9. Dim wdh As Integer = 200 'Vergebliche Versuche
    10. Dim fname As String = "" 'Dateiname für einzelne Fotodatei
    11. Dim fn As String = "" 'Dateiname für einzelne Fotodatei ohne Endung
    12. Dim pagefile As String = "" 'Dateiname für Seitenausgabe als jpg
    13. Dim G As Graphics = Nothing 'Hauptgrafik
    14. 'Seitenstatus
    15. ASN += 1
    16. If ASNMax < ASN Then
    17. ASNMax = ASN
    18. vorwärts = True
    19. Else
    20. vorwärts = False
    21. End If
    22. 'Globale Einstellungen
    23. WriteProt("Druckseite " & ASN & "/" & ZSeiten.Text & " wird aufgebaut", , "B")
    24. Me.Cursor = System.Windows.Forms.Cursors.WaitCursor
    25. WZellePX = CInt(BreitePx.Text) + 2 * CInt(RandPx.Text)
    26. HZellePX = CInt(HöhePx.Text) + 2 * CInt(RandPx.Text)
    27. WZelleMM = CDbl(WZellePX / dpmm)
    28. HZelleMM = CDbl(HZellePX / dpmm)
    29. WPic = CInt(BreitePx.Text)
    30. HPic = CInt(HöhePx.Text)
    31. SColl = CInt(ZSpalten.Text)
    32. ZColl = CInt(Math.Ceiling(CDbl(ANZ) / CDbl(SColl)))
    33. WColl = CInt(dpmm * CDbl(Druckbreite.Text)) 'Abmessungen der Kollektion
    34. HColl = CInt(dpmm * CDbl(Druckhöhe.Text))
    35. AnzProS = CInt(ZSpalten.Text) * CInt(ZProS.Text)
    36. BNR = AnzProS * (ASN - 1)
    37. PenSM = New Pen(FarbeSM, StärkeSM) 'Für Schnittmarken
    38. NW = BNR + 1 : NWO = 0
    39. WorkerSleep = False
    40. Try
    41. If Not Drucken Then
    42. 'Bei Vorschau Druckgrafik + Seitenrand
    43. CollImage = New Bitmap(WColl + CInt(MarginsLeft * dpmm) + CInt(MarginsRight * dpmm), HColl + CInt(MarginsTop * dpmm) + CInt(MarginsBottom * dpmm))
    44. ax = CInt(MarginsLeft * dpmm)
    45. ay = CInt(MarginsTop * dpmm)
    46. Else
    47. 'Bei Druck wird Seitenrand autopmatisch erzeugt
    48. CollImage = New Bitmap(WColl, HColl) 'Reine Druckgrafik
    49. ax = 0
    50. ay = 0
    51. End If
    52. 'Verschiebung mittig innerhalb Druckbereich
    53. bx = CInt(0.5 * dpmm * (CDbl(Druckbreite.Text) - CDbl(Grafikbreite.Text)))
    54. by = CInt(0.5 * (dpmm * CDbl(Druckhöhe.Text) - CDbl(ZProS.Text) * HZellePX))
    55. G = Graphics.FromImage(CollImage)
    56. G.PageUnit = GraphicsUnit.Pixel
    57. Catch err As Exception
    58. Kom = "Grafikfehler bei Positionierung" & vbCrLf & err.Message
    59. WriteProt(Kom, , "R")
    60. End Try
    61. Try
    62. 'Hintergrund-Rechteck Seite
    63. Dim rectpg As New Rectangle(0, 0, CollImage.Width, CollImage.Height)
    64. G.FillRectangle(Brushes.White, rectpg)
    65. 'Rechteck Druckbereich
    66. Dim rectdb As Rectangle = New Rectangle(ax, ay, WColl, HColl)
    67. If Simulieren = "J" Then
    68. Dim BrushHS As New SolidBrush(FarbeHS)
    69. G.FillRectangle(BrushHS, rectdb)
    70. Else
    71. Dim BrushHG As New SolidBrush(FarbeHG)
    72. G.FillRectangle(BrushHG, rectdb)
    73. End If
    74. 'Schwarzer Rand außer beim Druck
    75. If Not Drucken Then
    76. Dim p As Pen = New Pen(Brushes.Black, 5)
    77. G.DrawRectangle(p, rectdb)
    78. End If
    79. Catch err As Exception
    80. Kom = "Grafikfehler bei Erzeugung des Hintergrunds" & vbCrLf & err.Message
    81. WriteProt(Kom, , "R")
    82. End Try
    83. 'Reduziertes Zielrechteck, alles in Pixel
    84. z = 1 : s = 0 : l = BNR
    85. For i = 1 To AnzProS
    86. s += 1
    87. If s > SColl Then
    88. s = 1
    89. z += 1
    90. End If
    91. l += 1
    92. If Simulieren = "J" And l <= ANZ Then 'Simulation
    93. Try
    94. If l <= ANZ Then
    95. px = CInt(ax + bx + WZellePX * (s - 1) + RandPx.Value)
    96. py = CInt(ay + by + HZellePX * (z - 1) + RandPx.Value)
    97. Dim BrushSB As New SolidBrush(FarbeSB)
    98. Dim rred As New Rectangle(px, py, WPic, HPic)
    99. G.FillRectangle(BrushSB, rred)
    100. End If
    101. Catch err As Exception
    102. Kom = "Grafikfehler bei simuliertem Bild z/s " & z & " / " & s & vbCrLf & err.Message
    103. WriteProt(Kom, , "R")
    104. End Try
    105. End If
    106. If Schnittmarken = "J" And l <= ANZ Then 'Schnittmarken zeichnen
    107. Try
    108. If l <= ANZ Then
    109. 'LO => Rechts + Unten
    110. zx = CInt(ax + bx + WZellePX * (s - 1))
    111. zy = CInt(ay + by + HZellePX * (z - 1))
    112. G.DrawLine(PenSM, zx, zy, zx + LM, zy)
    113. G.DrawLine(PenSM, zx, zy, zx, zy + LM)
    114. 'RO => Links + Unten
    115. zx = CInt(CDbl(ax) + CDbl(bx) + CDbl(s) * WZellePX)
    116. zy = CInt(CDbl(ay) + CDbl(by) + CDbl(z - 1) * HZellePX)
    117. G.DrawLine(PenSM, zx, zy, zx - LM, zy)
    118. G.DrawLine(PenSM, zx, zy, zx, zy + LM)
    119. 'LU => Rechts + Oben
    120. zx = CInt(CDbl(ax) + CDbl(bx) + CDbl(s - 1) * WZellePX)
    121. zy = CInt(CDbl(ay) + CDbl(by) + CDbl(z) * HZellePX)
    122. G.DrawLine(PenSM, zx, zy, zx + LM, zy)
    123. G.DrawLine(PenSM, zx, zy, zx, zy - LM)
    124. 'RU => Links + Oben
    125. zx = CInt(CDbl(ax) + CDbl(bx) + CDbl(s) * WZellePX)
    126. zy = CInt(CDbl(ay) + CDbl(by) + CDbl(z) * HZellePX)
    127. G.DrawLine(PenSM, zx, zy, zx - LM, zy)
    128. G.DrawLine(PenSM, zx, zy, zx, zy - LM)
    129. End If
    130. Catch err As Exception
    131. Kom = "Grafikfehler bei Schnittmarken z/s " & z & " / " & s & vbCrLf & err.Message
    132. WriteProt(Kom, , "R")
    133. End Try
    134. End If
    135. If ZellenNumerieren = "J" Then 'Laufende Nummern einschreiben
    136. Try
    137. 'Zur größengerechten Positionierung
    138. Dim txtFont As New Font("Arial", 48)
    139. Dim tSize As SizeF = G.MeasureString(l.ToString, txtFont)
    140. Dim txtw As Double = tSize.Width
    141. Dim txth As Double = tSize.Height
    142. 'Numerierung schreiben
    143. Dim xs As Single = CSng(ax + bx + WZellePX * (s - 1) + 0.5 * (WZellePX - txtw))
    144. Dim ys As Single = CSng(ay + by + HZellePX * (z - 1) + 0.5 * (HZellePX - txth))
    145. Dim txtPoint As New PointF(xs, ys)
    146. Dim txtBrush As New SolidBrush(FarbeTX)
    147. G.DrawString(CStr(l), txtFont, txtBrush, txtPoint)
    148. Catch err As Exception
    149. Kom = "Grafikfehler bei Nummern schreiben z/s " & z & " / " & s & vbCrLf & err.Message
    150. WriteProt(Kom, , "R")
    151. End Try
    152. End If
    153. If NameSchreiben = "J" And l <= ANZ Then 'Bildname eintragen
    154. Try
    155. Dim tg As Integer = 16
    156. If NameGröße = "K" Then tg = 16
    157. If NameGröße = "M" Then tg = 20
    158. If NameGröße = "G" Then tg = 24
    159. Dim txtFont As New Font("Arial", tg)
    160. fname = IMGFls(l - 1).ToString
    161. fn = System.IO.Path.GetFileNameWithoutExtension(fname)
    162. Dim tSize As SizeF = G.MeasureString(fn, txtFont)
    163. Dim txtw As Double = tSize.Width
    164. Dim txth As Double = tSize.Height
    165. Dim q As Double = CInt(BreitePx.Text) / txtw
    166. If q < 1 Then
    167. Dim zei As Integer = CInt(q * fn.Length) - 3
    168. fn = "..." & fn.Substring(fn.Length - zei)
    169. txtw = q * txtw
    170. End If
    171. Dim xs As Single = CInt(CDbl(ax) + CDbl(bx) + CDbl(s - 0.5) * WZellePX - 0.5 * txtw)
    172. Dim ys As Single = CInt(CDbl(ay) + CDbl(by) + CDbl(z) * HZellePX - 0.5 * txth)
    173. Dim txtPoint As New PointF(xs, ys)
    174. Dim txtBrush As New SolidBrush(Color.Black)
    175. G.DrawString(fn, txtFont, txtBrush, txtPoint)
    176. Catch err As Exception
    177. Kom = "Grafikfehler bei Text zu Bild " & fn & vbCrLf & err.Message
    178. WriteProt(Kom, , "R")
    179. End Try
    180. End If
    181. If Simulieren = "N" And l <= ANZ Then 'Einzelbilder einschreiben
    182. Try
    183. px = CInt(ax + bx + WZellePX * (s - 0.5) - 0.5 * WPic)
    184. py = CInt(ay + by + HZellePX * (z - 0.5) - 0.5 * HPic)
    185. Dim pt As New Point(px, py)
    186. Dim ng As Integer = 0
    187. ng = 0
    188. For n = 1 To wdh
    189. If IMG(l - 1) Is Nothing Then
    190. ng += 1
    191. Threading.Thread.Sleep(25)
    192. Else
    193. G.DrawImage(IMG(l - 1), pt)
    194. Exit For
    195. End If
    196. Application.DoEvents()
    197. Next
    198. If ng < wdh Then
    199. 'WriteProt("Geladen Bild / ng = " & i + 1 & " / " & ng)
    200. Else
    201. WriteProt("Nicht geladen Bild / ng = " & i + 1 & " / " & ng, , "R")
    202. End If
    203. Catch err As Exception
    204. Kom = "Grafikfehler bei Zeichnen von Bild " & fname & vbCrLf & err.Message
    205. WriteProt(Kom, , "R")
    206. End Try
    207. End If
    208. Next
    209. Try
    210. If LIZLEVEL = "H" Then
    211. If vorwärts Then
    212. If Not Drucken And DateiAusgeben = "J" Then
    213. Dim zk As String = Now.ToString("yy/MM/dd/HH/mm/ss")
    214. Dim spl As String() = Split(zk, ".")
    215. Dim zk2 As String = Join(spl, "")
    216. pagefile = AusgabePfad & "Koll" & zk2 & ".jpg"
    217. CollImage.Save(zfile, ImageFormat.Jpeg)
    218. WriteProt("Gespeichert als " & pagefile, , "G")
    219. End If
    220. End If
    221. End If
    222. G.Dispose()
    223. Catch err As Exception
    224. Kom = "Fehler bei der Ausgabe der Seitengrafik." & vbCrLf & _
    225. "Überprüfen Sie Ihre Rechte für das Ausgabeverzeichnis" & CRLF & _
    226. "der Seitengrafik und korrigieren Sie es gegebenenfalls."
    227. WriteProt(Kom, 1, "R")
    228. MessageBox.Show(Kom, My.Application.Info.Title, MessageBoxButtons.OK, MessageBoxIcon.Error)
    229. End Try
    230. Me.Cursor = System.Windows.Forms.Cursors.Default
    231. End Sub
    Bilder
    • DFA01.jpg

      222,3 kB, 787×630, 110 mal angesehen
    • DFA02.jpg

      274,72 kB, 808×599, 106 mal angesehen
    • DFA03.jpg

      198,69 kB, 787×630, 106 mal angesehen
    • DFA4.jpg

      299,04 kB, 808×599, 103 mal angesehen
    Ich bin gerade erst dazu gestoßen (jetzt ists wahrscheinlich schon zu spät), möchte aber noch die ​ImageList vorschlagen: Die ist hierfür geschaffen worden und nimmt dir eigentlich die ganze Arbeit ab: Du füllst deine Bilder in die ImageList (anstatt eines Arrays oder einer List) und disposed sie dann, wenn du die Bilder nicht mehr benötigst. Dabei werden auch alle Bilder mit-disposed.
    Außerdem ist sie gut in WinForms integriert, die Nutzung ist also noch einfacher.
    Jo - miese Architektur. Vollkommen unklar ist, welche Aufgabe die Methode PageGraphic() hat. Was ist deren Aufgabe?

    Und wo ist die Methode BeiVerzeichniswechsel(). Die unklare Aufgabe der Methode PageGraphic() kann ja nicht der Grund dafür sein, dasses keine Methode BeiVerzeichniswechsel() gibt,deren Aufgaben hoffentlich klar umrissen sein wird. ;)
    Jo - miese Architektur

    Schade, dann habe ich 40 Jahre in der Programmierung nur Mist gebaut. Du hast 10 % von dem Programm gesehen. Es ist nicht Aufgabe des Forums, eine ganze Programmstruktur zu hinterfragen, nachdem ich eine Frage zu einem Array gestellt hatte. Ich werde mich mal aus dem Thema auskoppeln.

    drschef schrieb:

    Es ist nicht Aufgabe des Forums, eine ganze Programmstruktur zu hinterfragen
    Warum nicht?
    Stell Deine Fragen so, dass daneben kein Raum bleibt für solche Ausschweifungen. :/
    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!