Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
C# / VB.NET - File bmp
Forum - C# / VB.NET - File bmp - Pagina 2

Pagine: [ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ] Precedente | Prossimo
Avatar
bernie (Normal User)
Pro


Messaggi: 164
Iscritto: 23/10/2019

Segnala al moderatore
Postato alle 9:36
Giovedì, 08/07/2021
Ciao Carlo
Abbastanza chiaro.
Sicuramente avere file a 4bpp invece che a 8 , significherebbe salvare spazio e considerando che i files che vanno gestiti sono grandi , questo non guasterebbe . Ho provato a pensarci,ma non sono arrivato a niente di fatto .
Ti ricorderai che tempo fa avevo aperto un post dove chiedevo supporto per fare il paste di due files .
Visto che i due files sono uno bianco e il secondo un campo pieno , credo che con questo sistema che mi hai mostrato e spiegato posso "colorare" direttamente il file senza bisogno di incollarne due . Fatto ciò , guarderò anche come fare i file a 4bpp.
Grazie


PM Quote
Avatar
Carlo (Member)
Guru


Messaggi: 1370
Iscritto: 29/01/2018

Segnala al moderatore
Postato alle 14:08
Giovedì, 08/07/2021
Prova, prendendo il mio primo esempio postato, devi aggiungere la creazione della palette con 16 livelli di grigio e modificare il for per riempire il vettore, per inserire il valore usa l'esadecimale, così eviti il calcolo per i due pixel uguali per ogni byte, es. vuoi il livello5: &H55, vuoi il livello 15: &HFF,  se non riesci posta il tentativo.

Farei anche una prova senza impostare la palette, non è detto che il sistema grafico che usi ne tenga conto.

Ricordo la richiesta, se avessi spiagato cosa ti serviva, forse ti avrei risparmiato il codice per la fusione, ma comunque valido per imparare.

Ultima modifica effettuata da Carlo il 08/07/2021 alle 14:12


in programmazione tutto è permesso
PM Quote
Avatar
bernie (Normal User)
Pro


Messaggi: 164
Iscritto: 23/10/2019

Segnala al moderatore
Postato alle 15:52
Giovedì, 08/07/2021
Hai ragione, ma purtroppo la necessità di modificare la palette è venuta in seguito.
Adesso provo a 4bpp.
Grazie

PM Quote
Avatar
bernie (Normal User)
Pro


Messaggi: 164
Iscritto: 23/10/2019

Segnala al moderatore
Postato alle 10:03
Lunedì, 12/07/2021
Ho modificato l'esempio di Carlo per adattarlo alle mie necessità, creare un file bmp con le caratteristiche volute .
A questo punto vorrei provare ad alzare l'asticella, consideriamo di avere un file 100X100 pixel ,che il file debba essere completamente di colore bianco e poi disegnare un rettangolo 70X70 pixel con origine in x=30 y=30 di dimensioni note e di colore voluto .

Avevo pensato una cosa del genere , funziona , però penso che si potrebbe ottimizzare.

Codice sorgente - presumibilmente VB.NET

  1. ' puntatore all'indirizzo di memoria del primo byte.
  2.         Dim ptr As IntPtr = bmpData.Scan0
  3.  
  4.         ' un vettore che conterrà tutti i bytes della bitmap.
  5.         Dim bytes As Long = Math.Abs(bmpData.Stride) * immagine.Height        ' calcolo dei bytes necessari
  6.  
  7.         Dim colorValues(bytes - 1) As Byte
  8.         Dim ind As Long
  9.         Dim app As Long
  10.         Dim app2 As Long
  11.  
  12.         app = (larghezza *(altezza-altezza1)                             ' calcolo l'area bianca superiore
  13.  
  14.         For ind = 0 To app - 1                                                  ' coloro di bianco l'area bianca superiore
  15.             colorValues(ind) = 255
  16.         Next
  17.         For app2 = app To bytes Step Math.Abs(bmpData.Stride)
  18.             For ind = app2 To app2 + (larghezza-larghezza1) - 1         ' coloro di bianco la fascia sinistra
  19.                 colorValues(ind) = 255
  20.             Next
  21.         For ind = app2 + (larghezza-larghezza1) - 1 To (app2 + larghezza) - 1  
  22.                 colorValues(ind) = 255 - (32 * livello)                          ' a ogni pixel scrivo il valore di profondità per avere il livello voluto
  23.  
  24.             Next
  25.  
  26.         Next
  27.         ' ripristino vettore su immagine
  28.         System.Runtime.InteropServices.Marshal.Copy(colorValues, 0, ptr, bytes)
  29.         immagine.UnlockBits(bmpData) ' sblocco bit
  30.         immagine.SetResolution(360, 360)
  31.         immagine.Save("C:\Users\bernie\test8bpp_livello.bmp", Imaging.ImageFormat.Bmp)
  32.  
  33.     End Sub



larghezza è la larghezza del file , larghezza1 è la larghezza del rettangolo.
altezza è l'altezza del file ,altezza1 è l'altezza del rettangolo.
Visto che i file che devo trattare sono abbastanza grandi ,si può ottimizzare qualcosa per rendere il processo più veloce?
Grazie



Ultima modifica effettuata da bernie il 12/07/2021 alle 10:06
PM Quote
Avatar
Carlo (Member)
Guru


Messaggi: 1370
Iscritto: 29/01/2018

Segnala al moderatore
Postato alle 13:26
Lunedì, 12/07/2021
Buono ma se devi scrivere rettangoli, è utile una sub che si incarica di farlo, ignorando i valori fuori scala.
Nell'esempio puoi definire un'immagine larga alta come vuoi, considera che poi si parte da 0, le coordinate di un'immagine larga 277 vanno da 0 a 276.

La routine che traccia rettangoli pieni accetta le coordinate dell'angolo superiore sinistro e l'angolo inferiore destro di un rettangolo, la larghezza dell'immagine (estratta da .stride che include anche i caratteri di escape), l'altezza, il vettore che contiene l'immagine, e il colore del rettangolo.

Per darti l'idea della velocità di esecuzione ho aggiunto Stopwatch che uso per mostrare sulla barra del titolo i millisecondi impiegati per scrivere i bytes nel vettore.

Codice sorgente - presumibilmente VB.NET

  1. Public Class Form1
  2.     Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
  3.         Dim sw As New Stopwatch
  4.         Dim larghezza As UInt16 = 5000 ' 0...4999, solo positivi
  5.         Dim altezza As UInt16 = 2500 ' 0...2499, solo positivi
  6.         Dim immagine As New Bitmap(larghezza, altezza, Imaging.PixelFormat.Format8bppIndexed)
  7.  
  8.         ' creo una palette con 256 livelli di grigio
  9.         Dim palette As Imaging.ColorPalette = immagine.Palette
  10.         For i = 0 To palette.Entries.Length - 1
  11.             palette.Entries(i) = Color.FromArgb(i, i, i)
  12.         Next i
  13.         ' associo la palette creata alla bitmap 8bpp,
  14.         ' i valori 0...255 ora corrispondono alla scala dal nero al bianco
  15.         immagine.Palette = palette
  16.         ' blocco i bit della bitmap per poter lavorare direttamente su un vettore di bytes
  17.         Dim area As Rectangle = New Rectangle(0, 0, immagine.Width, immagine.Height)
  18.         Dim bmpData As Imaging.BitmapData = immagine.LockBits(area, Imaging.ImageLockMode.ReadWrite, immagine.PixelFormat)
  19.  
  20.         ' puntatore all'indirizzo di memoria del primo byte.
  21.         Dim ptr As IntPtr = bmpData.Scan0
  22.  
  23.         ' un vettore che conterrà tutti i bytes della bitmap.
  24.         Dim bytes As Integer = Math.Abs(bmpData.Stride) * immagine.Height ' calcolo dei bytes necessari
  25.         Dim colorValues(bytes - 1) As Byte
  26.  
  27.         sw.Restart() ' avvio il conteggio del tempo
  28.  
  29.         rettangolo(0, 0, 4999, 299, Math.Abs(bmpData.Stride), altezza, colorValues, 255) ' rettangolo bianco superiore
  30.         rettangolo(0, 300, 299, 2499, Math.Abs(bmpData.Stride), altezza, colorValues, 100) ' rettanglo grigioscuro sinistro
  31.         rettangolo(300, 300, 4999, 2499, Math.Abs(bmpData.Stride), altezza, colorValues, 200) ' rettangolo grigio
  32.  
  33.         Me.Text = "Scrittura Bytes in: " & sw.ElapsedMilliseconds & "ms." ' mostro il tempo impiegato
  34.  
  35.         ' ripristino vettore su immagine
  36.         System.Runtime.InteropServices.Marshal.Copy(colorValues, 0, ptr, bytes)
  37.         immagine.UnlockBits(bmpData) ' sblocco bit
  38.         immagine.Save("prova8bpp.bmp", Imaging.ImageFormat.Bmp)
  39.     End Sub
  40.  
  41.    Sub rettangolo(x1 As UInt16, y1 As UInt16, x2 As UInt16, y2 As UInt16, larghezza As UInt32, altezza As UInt16, vettore() As Byte, colore As Byte)
  42.         ' limite valori
  43.         If x1 >= larghezza Then x1 = larghezza - 1
  44.         If x2 >= larghezza Then x2 = larghezza - 1
  45.         If y1 >= altezza Then y1 = altezza - 1
  46.         If y2 >= altezza Then y2 = altezza - 1
  47.  
  48.         For colonna = x1 To x2
  49.             For riga = y1 To y2
  50.                 Dim ind As UInt32 = colonna + riga * larghezza 'calcolo l'indice
  51.                 vettore(ind) = colore
  52.             Next
  53.         Next
  54.  
  55.     End Sub
  56.  
  57. End Class



Il programma traccia 3 rettangoli con tre livelli di grigio (per identificarli), naturalmente i rettangoli tracciati dopo, se occupano le coordinate dei rettangoli tracciati prima, li sovrascrivono.
Considerato che scrivi Bytes direttamente in memoria, in VB.Net hai la massima velocità, anche se non paragonabile a GDI+.

Ultima modifica effettuata da Carlo il 12/07/2021 alle 17:27


in programmazione tutto è permesso
PM Quote
Avatar
bernie (Normal User)
Pro


Messaggi: 164
Iscritto: 23/10/2019

Segnala al moderatore
Postato alle 9:04
Mercoledì, 14/07/2021
Buon Giorno
Ho provato l'esempio di Carlo e ovviamente funziona. Poi ho iniziato a modificarlo in base alle mie esigenze. Fino qui tutto ok, quando inserisco le dimensioni del bmp che mi servono , iniziano le cose strane , mi crea il file , ma non è possibile aprire il file , nei dettagli non sono indicate le dimensioni , la profondità , niente . Per scriverlo , impiega circa 60 secondi.
Stavo cercando di processare un file da 4000X250000 pixel( forse devo arrivare anche oltre ) . Rispetto l'esempio di Carlo , ho cambiato alcune variabili da UInt16 a Long.
Forse devo passare a  GDI+?
Grazie

PM Quote
Avatar
Carlo (Member)
Guru


Messaggi: 1370
Iscritto: 29/01/2018

Segnala al moderatore
Postato alle 13:54
Mercoledì, 14/07/2021
Duecentocinquantamila pixel?
Da Windows non ti aspettare di avere info su file BMP che superano i 130.000 pixel in altezza o larghezza.
Il file viene correttamente creato ma poi per maneggiarlo dovrai ricorrere a sistemi prioritari, il tuo sitema grafico che dice quando gli passi una BMP da 1GB?

Con GDI+ la velocità di tracciamento di un rettangolo pieno è circa 10 volte più veloce che riempire di bytes la memoria con i cicli per un'immagine a 8bpp e 5 volte più veloce che riempire per un'immagine a 4bpp.
Purtroppo con GDI+ un'immagine bitmap a pixel non indicizzati non può superare i 260.000 pixel, e se l'immagine è grande come le tue 1GB e più, poi la conversione da 16bpp a 4 bpp si rimangia il tempo guadagnato.

Sei sicuro di percorrere una strada giusta?

Per il momento ti propongo lo stesso sistema ma a 4bpp, avrai un raddoppio della velocità e un dimezzamento della grandezza del file.
Non ho messo il calcolo per distinguere due pixel adiacenti, che saranno trattati come fossero un unico pixel.

Codice sorgente - presumibilmente VB.NET

  1. Public Class Form1
  2.     Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
  3.         Dim sw As New Stopwatch
  4.         Dim larghezza As UInt32 = 4000 ' 0...3998, solo positivi, due a due
  5.         Dim altezza As UInt32 = 130000 ' 0...129999, solo positivi
  6.  
  7.         Dim immagine As New Bitmap(larghezza, altezza, Imaging.PixelFormat.Format4bppIndexed)
  8.  
  9.         ' creo una palette con 16 livelli di grigio
  10.         Dim palette As Imaging.ColorPalette = immagine.Palette
  11.         For i = 0 To palette.Entries.Length - 1
  12.             palette.Entries(i) = Color.FromArgb(i * 17, i * 17, i * 17)
  13.         Next i
  14.         ' associo la palette creata alla bitmap 4bpp,
  15.         ' i valori 0...15 ora corrispondono alla scala dal nero al bianco
  16.         immagine.Palette = palette
  17.         ' blocco i bit della bitmap per poter lavorare direttamente su un vettore di bytes
  18.         Dim area As Rectangle = New Rectangle(0, 0, immagine.Width, immagine.Height)
  19.         Dim bmpData As Imaging.BitmapData = immagine.LockBits(area, Imaging.ImageLockMode.ReadWrite, immagine.PixelFormat)
  20.  
  21.         ' puntatore all'indirizzo di memoria del primo byte.
  22.         Dim ptr As IntPtr = bmpData.Scan0
  23.  
  24.         ' un vettore che conterrà tutti i bytes della bitmap.
  25.         Dim bytes As Integer = Math.Abs(bmpData.Stride) * immagine.Height ' calcolo dei bytes necessari
  26.         Dim colorValues(bytes - 1) As Byte
  27.         sw.Restart() ' avvio il conteggio del tempo
  28.  
  29.         rettangolo(0, 0, 4000, 299, Math.Abs(bmpData.Stride), altezza, colorValues, 15) ' rettangolo bianco superiore
  30.         rettangolo(0, 300, 298, 130000, Math.Abs(bmpData.Stride), altezza, colorValues, 8) ' rettanglo grigioscuro sinistro
  31.         rettangolo(300, 300, 4000, 130000, Math.Abs(bmpData.Stride), altezza, colorValues, 10) ' rettangolo grigio
  32.  
  33.         Me.Text = "Scrittura Bytes in: " & sw.ElapsedMilliseconds & "ms." ' mostro il tempo impiegato
  34.  
  35.         ' ripristino vettore su immagine
  36.         System.Runtime.InteropServices.Marshal.Copy(colorValues, 0, ptr, bytes)
  37.         immagine.UnlockBits(bmpData) ' sblocco bit
  38.         immagine.Save("prova4bpp.bmp", Imaging.ImageFormat.Bmp)
  39.     End Sub
  40.  
  41.     Sub rettangolo(x1 As UInt32, y1 As UInt32, x2 As UInt32, y2 As UInt32, larghezza As UInt32, altezza As UInt32, vettore() As Byte, colore As Byte)
  42.         ' limite valori
  43.         x1 = Math.Truncate(x1 / 2)
  44.         x2 = Math.Truncate(x2 / 2)
  45.         If x1 >= larghezza Then x1 = larghezza - 1
  46.         If x2 >= larghezza Then x2 = larghezza - 1
  47.         If y1 >= altezza Then y1 = altezza - 1
  48.         If y2 >= altezza Then y2 = altezza - 1
  49.         ' a 4bpp scrivo 2 pixel adiacenti alla volta
  50.         colore = colore + colore * 16 ' valore per due pixel uguali
  51.         For colonna As UInt32 = x1 To x2
  52.             For riga As UInt32 = y1 To y2
  53.                 Dim ind As UInt32 = colonna + riga * larghezza  'calcolo l'indice
  54.                 vettore(ind) = colore
  55.             Next
  56.         Next
  57.     End Sub
  58.  
  59. End Class


Ultima modifica effettuata da Carlo il 15/07/2021 alle 12:15


in programmazione tutto è permesso
PM Quote
Avatar
bernie (Normal User)
Pro


Messaggi: 164
Iscritto: 23/10/2019

Segnala al moderatore
Postato alle 17:09
Giovedì, 15/07/2021
Ciao Carlo

L'esempio funziona e ho iniziato ad adattarlo alle  mie necessità .
Sfortunatamente sono sicuro che la strada è corretta, almeno per quello che riguarda l'altezza del bmp. per quanto riguarda la larghezza li sono in un dubbio.
Considerando che alla fine vado ad utilizzare solo file di 1000pixel di larghezza , però per comodità mi risulta più facile fare un file da n000pixel di larghezza e poi tagliarlo. A questo punto la domanda è , risulta meglio usare una funzione "crop " tagliando da 0 a 999, poi da 1000 a 1999 e via fino alla fine salvando i vari crop , oppure clonare un area del file da 0 a 999 e poi incollare il clone su un altro file ?
Altra domanda, dove potrei studiare la parte riguardo la grafica in VB.Net?
Grazie

PM Quote
Pagine: [ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ] Precedente | Prossimo