Oppure

Loading
05/07/21 15:06
bernie
Salve a tutti
dovrei creare un file bmp , monocanale , 4bpp e fino a qui ci sono
          Dim larghezza As Int16
    Dim altezza As Int16
    larghezza = TextBox1.Text
    altezza = TextBox2.Text
    Dim immagine As New Bitmap(larghezza, altezza, Imaging.PixelFormat.Format4bppIndexed)
    immagine.SetResolution(360, 360)
    immagine.Save("prova.bmp", Imaging.ImageFormat.Bmp)

Quello che dovrei fare adesso è assegnare ad ogni pixel un valore da 0 a 15 .
Avevo pensato a SetPixel , però quello associa un colore , e io sono in monocanale .
Qualche idea ?
Grazie
Ultima modifica effettuata da bernie 05/07/21 15:07
aaa
05/07/21 20:47
Carlo
SetPixel non lo puoi usare su una bmp a pixel indicizzati
I pixel indicizzati significa che l'immagine rispecchia un array di bytes con colori indicizzati e in base al numero dei bpp rappresentano più o meno pixel, per esempio un'immagine da 1bpp sarà composta da un vettore dove ogni byte rappresenta 8 pixel
Nel tuo caso 4bpp, ogni byte rappresenta due pixel adiacenti.
In base alla velocità operativa, hai due strade, una più lenta e facile, creare un'immagine a pixel non indicizzati usare setpixel con valori RGB, creati ad hoc per rispecchiare la tua palette e una volta creata l'immagine, convertirla a 4bpp.

La seconda nettamente più veloce ma più complicata, è usare LockBits e trattare l'immagine come un vettore.
Devi tenere in considerazione che il vettore conterrà tutti i bytes dell'immagine in sequenza, sarà tua cura calcolare quando la riga va accapo.
Ogni byte contiene il colore di due pixel, i colori usabili sono 0...15 o meglio &H0...&HF

Un esempio vale più di mille parole:
Dim larghezza As Int16 = 800
Dim altezza As Int16 = 600

Dim immagine As New Bitmap(larghezza, altezza, Imaging.PixelFormat.Format4bppIndexed)
' blocco i bit della bitmap  
Dim area As Rectangle = New Rectangle(0, 0, immagine.Width, immagine.Height)
Dim bmpData As System.Drawing.Imaging.BitmapData = immagine.LockBits(area, Drawing.Imaging.ImageLockMode.ReadWrite, immagine.PixelFormat)

' puntatore all'indirizzo di memoria del primo byte.
Dim ptr As IntPtr = bmpData.Scan0

' un array che conterrà tutti i bytes della bitmap.
Dim bytes As Integer = Math.Abs(bmpData.Stride) * immagine.Height ' calcolo dei bytes necessari
Dim colorValues(bytes - 1) As Byte
Dim dalbyte As Integer

' nella prima riga dell'immagine scrivo una serie di punti bianchi e verdi
For dalbyte = 0 To 399 ' ogni byte 2 pixel, la prima riga 0 399
     colorValues(dalbyte) = &HFA ' due colori bianco e verde
Next
' nella seconda riga dell'immagine scrivo una serie di punti bianchi e neri
For dalbyte = 400 To 799 ' ogni byte 2 pixel, la seconda riga 400 799
     colorValues(dalbyte) = &HF0 ' due colori bianco e nero
Next

dalbyte = 6800 ' diciottesima riga
For colore = 0 To 15
     For dalbyte = dalbyte To dalbyte + 1199 ' per tre righe consecutive
          colorValues(dalbyte) = colore + colore * 16 ' i 16 colori in un byte con 4bit ripetuti (&H00, &H11, &H22...&HFF)
     Next
Next

' ripristino matrice su immagine
System.Runtime.InteropServices.Marshal.Copy(colorValues, 0, ptr, bytes)
immagine.UnlockBits(bmpData) ' sblocco bit
immagine.Save("prova.bmp", Imaging.ImageFormat.Bmp)
Ultima modifica effettuata da Carlo 19/07/21 8:15
in programmazione tutto è permesso
06/07/21 6:37
bernie
Ciao Carlo
Grazie per l'esempio, purtroppo credo di essermi spiegato male .
Parlando di monocanale , si intende un file dove non c'è colore , ma livelli di grigio ,greyscale . quando apri questo tipo di file in photoshop e vai col cursore sul singolo pixel , ti indica un numero che varia da 0 a 100%. Se il file è a 8bpp il "peso" del pixel varia da 0 a 255 .
Mi dispiace averti fatto perdere del tempo per colpa delle mie incorrette spiegazioni .
aaa
06/07/21 8:40
Carlo
OK, ma l'esempio resta valido.
Ho usato i valori 0...15, che in un file 4bpp di default usano la palette HalfTone, ma la palette la puoi cambiare come vuoi, anche usare 16 livelli di grigio.

Per un aiuto senza ambiguità, vorrei sapere cosa devi fare, se lavori in tandem con Photoshop, oppure hai dei files 4bpp da modificare via codice, cerca di espormi con cosa lavori e cosa vuoi ottenere, le possibilità sono sconfinate, usare quella giusta ti risparmia inutili complicazioni.

Avevo capito che il file 4bpp lo vuoi creare ex novo, e l'esempio è l'inizio per fare questo, ma poi bisogna sapere che esigenze di scrittura hai, se il file è uno è non devi variarne il contenuto dinamicamente e velocemente, la strada più semplice resta quella di partire con una bmp a pixel non indicizzati, usare una tua scala di 16 grigi, disegnare quello che vuoi con setpixel o tutte le istruzioni grafiche disponibili e poi convertire il file a 4bpp prima di salvare, la palette grayscale viene creata automaticamente.
Ultima modifica effettuata da Carlo 06/07/21 8:42
in programmazione tutto è permesso
06/07/21 10:12
bernie
Vorrei creare dei files da passare ad un sistema grafico .
Questo sistema accetta bmp monocanale( quindi solo 1 colore) 4 bpp ,8bpp scala di grigio .
Se creo il file
 Dim immagine As New Bitmap(larghezza, altezza, Imaging.PixelFormat.Format4bppIndexed)

il sistema lo accetta senza problemi , anche se uso 8bpp.
Allego una immagine che il sistema accetta dove il gradiente va dal 100% allo 0% .
Quello che vorrei fare è riuscire a creare immagini decidendo il gradiente dell'immagine ( tutta l'immagine deve avere lo stesso valore di gradiente ) .
L'immagine una volta creata non necessita di essere modificata al volo, viene solo caricata in una cartella e il sistema la va a leggere.
Spero di essere stato più chiaro questa volta . Ti ringrazio per l'aiuto e scusa se a volte non riesco a spiegarmi bene .


Ultima modifica effettuata da bernie 06/07/21 10:13
aaa
06/07/21 21:29
Carlo
Usare 4bpp, considerato che un byte contiene i valori di due pixel, complica i calcoli, se 8bpp va bene invece tutto è in discesa perché ogni byte rappresenta un pixel e il valore contenuto nel byte rappresenta un livello di grigio da 0 a 255 (sfumature ottime). :rofl:
Per il lavoro che vuoi fare tu credo che LockBit e lavorare sui bytes dell'immagine sia il metodo con il risultato migliore, perché lavorare su sfumature usando bmp a 16 o più bit, quando poi si converte a 8bpp, per matenere la qualità bisogna lavorare su l'ottimizzazione della palette o introdurre un dither (complicazioni inutili).

Nell'esempio ho usato una bmp a 8bpp larga 256 pixel, così la sfumatura corrisponde con le colonne.
Poi sarai tu che deciderai come ottenere le sfumature, è sufficiente che nel vettore inserisci al giusto indice i valori 0...255.
La riga 31, calcola l'indice del pixel alla coordinata di colonna e riga che vuoi scrivere.
Imports System.Drawing.Imaging

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
  
        Dim larghezza As Int16 = 255 ' 256 colonne per semplificare la creazione della sfumatura
        Dim altezza As Int16 = 200 ' a piacere
        Dim immagine As New Bitmap(larghezza, altezza, Imaging.PixelFormat.Format8bppIndexed)

        ' creo una palette con 256 livelli di grigio
        Dim palette As 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 System.Drawing.Imaging.BitmapData = immagine.LockBits(area, Drawing.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 As Integer = Math.Abs(bmpData.Stride) * immagine.Height ' calcolo dei bytes necessari
        Dim colorValues(bytes - 1) As Byte
        ' disegno delle righe vericali, ogni riga un grigio progressivo
        For colonna = 0 To 255
            For riga = 0 To immagine.Height - 1
                Dim ind As Integer = colonna + riga * (larghezza + 1) 'calcolo l'indice
                ' per semplificare l'esempio, la bitmap è larga 256 pixel,
                ' la colonna viene usata anche per impostare il colore
                colorValues(ind) = colonna ' il valore di colonna come valore del byte di grigio 0...255
            Next
        Next

        ' ripristino vettore su immagine
        System.Runtime.InteropServices.Marshal.Copy(colorValues, 0, ptr, bytes)
        immagine.UnlockBits(bmpData) ' sblocco bit
        immagine.Save("prova8bpp.bmp", Imaging.ImageFormat.Bmp)
    End Sub

End Class


Fai sapere se l'immagine è accettata e se riesci a creare le sfumature che vuoi. :k:
Ultima modifica effettuata da Carlo 06/07/21 21:57
in programmazione tutto è permesso
07/07/21 10:21
bernie
Ciao Carlo
ho provato il tuo esempio e il sistema riconosce il bmp valido.
Ho poi modificato in maniera da avere tutto il bmp con lo stesso valore di "colorValues" scusa ma riesco sempre a spiegarmi da schifo e il file di esempio che ho postato è stato ancora più fuorviante ....scusa.
Comunque il bmp deve essere flat , colore solido. Per ottenere ciò , ho semplicemente messo un valore fisso in "colorValues(ind)", fino qui tutto ok .
Adesso ho provato ad ingrandire il bmp e mi va sempre in errore "System.IndexOutOfRangeException: 'Indice oltre i limiti della matrice.'"nella riga di "colorValues(ind)=200"
dovrebbe significare che l'indice "ind" è oltre i limiti della matrice, quello che non capisco è perchè con dimensioni del bmp di 255X200pixel non ho problemi , mentre con 3000X200 si .
Effettivamente ind raggiunge il valore di 9603200 mentre i bytes necessari sono solo 600000.
Ho fatto varie prove modificando la forma di calcolare ind , non mi da più nessun errore , purtroppo , anche cambiando il valore di colorValue , il bmp non cambia .










Ultima modifica effettuata da bernie 07/07/21 10:23
aaa
07/07/21 12:11
bernie
Credo di aver risolto , probabilmente non è elegante , ma dopo varie prove sembra funzionare .
Ho lasciato il calcolo di ind come nel tuo esempio.
Prima di andare a scrivere il il valore nel pixel indicizzato , controllo che ind non sia maggiore del numero totale di pixel , se maggiore lo setto come il numero dei pixel.
Forse non elegante , ma sembra funzionare .
aaa