Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
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
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
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
' puntatore all'indirizzo di memoria del primo byte.
Dim ptr As IntPtr = bmpData.Scan0
' un vettore che conterrà tutti i bytes della bitmap.
Dim bytes AsLong= Math.Abs(bmpData.Stride)* immagine.Height' calcolo dei bytes necessari
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
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
PublicClass Form1
PrivateSub Form1_Load(sender AsObject, e As EventArgs)HandlesMyBase.Load
Dim sw AsNew Stopwatch
Dim larghezza As UInt16 =5000' 0...4999, solo positivi
Dim altezza As UInt16 =2500' 0...2499, solo positivi
Dim immagine AsNew Bitmap(larghezza, altezza, Imaging.PixelFormat.Format8bppIndexed)
' creo una palette con 256 livelli di grigio
Dim palette As Imaging.ColorPalette= immagine.Palette
For i = 0 To palette.Entries.Length- 1
palette.Entries(i)= Color.FromArgb(i, i, i)
Next i
' associo la palette creata alla bitmap 8bpp,
' i valori 0...255 ora corrispondono alla scala dal nero al bianco
immagine.Palette= palette
' blocco i bit della bitmap per poter lavorare direttamente su un vettore di bytes
Dim area As Rectangle =New Rectangle(0, 0, immagine.Width, immagine.Height)
Dim bmpData As Imaging.BitmapData= immagine.LockBits(area, Imaging.ImageLockMode.ReadWrite, immagine.PixelFormat)
' puntatore all'indirizzo di memoria del primo byte.
Dim ptr As IntPtr = bmpData.Scan0
' un vettore che conterrà tutti i bytes della bitmap.
Dim bytes AsInteger= Math.Abs(bmpData.Stride)* immagine.Height' calcolo dei bytes necessari
Sub rettangolo(x1 As UInt16, y1 As UInt16, x2 As UInt16, y2 As UInt16, larghezza As UInt32, altezza As UInt16, vettore()AsByte, colore AsByte)
' limite valori
If x1 >= larghezza Then x1 = larghezza - 1
If x2 >= larghezza Then x2 = larghezza - 1
If y1 >= altezza Then y1 = altezza - 1
If y2 >= altezza Then y2 = altezza - 1
For colonna = x1 To x2
For riga = y1 To y2
Dim ind As UInt32 = colonna + riga * larghezza 'calcolo l'indice
vettore(ind)= colore
Next
Next
EndSub
EndClass
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
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
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
PublicClass Form1
PrivateSub Form1_Load(sender AsObject, e As EventArgs)HandlesMyBase.Load
Dim sw AsNew Stopwatch
Dim larghezza As UInt32 =4000' 0...3998, solo positivi, due a due
Dim altezza As UInt32 =130000' 0...129999, solo positivi
Dim immagine AsNew Bitmap(larghezza, altezza, Imaging.PixelFormat.Format4bppIndexed)
' creo una palette con 16 livelli di grigio
Dim palette As Imaging.ColorPalette= immagine.Palette
For i = 0 To palette.Entries.Length- 1
palette.Entries(i)= Color.FromArgb(i * 17, i * 17, i * 17)
Next i
' associo la palette creata alla bitmap 4bpp,
' i valori 0...15 ora corrispondono alla scala dal nero al bianco
immagine.Palette= palette
' blocco i bit della bitmap per poter lavorare direttamente su un vettore di bytes
Dim area As Rectangle =New Rectangle(0, 0, immagine.Width, immagine.Height)
Dim bmpData As Imaging.BitmapData= immagine.LockBits(area, Imaging.ImageLockMode.ReadWrite, immagine.PixelFormat)
' puntatore all'indirizzo di memoria del primo byte.
Dim ptr As IntPtr = bmpData.Scan0
' un vettore che conterrà tutti i bytes della bitmap.
Dim bytes AsInteger= Math.Abs(bmpData.Stride)* immagine.Height' calcolo dei bytes necessari
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