Oppure

Loading
17/07/21 9:06
bernie
Infatti , mi sono incartato nella lettura dei Byte,credo e spero solo li, anche se non è poco.
' clono un file esistente e lo salvo a 4bpp
        Dim originale As New Bitmap("C:\greca.tiff")
        Dim clonerettangolo As New Rectangle(0, 0, originale.Width, originale.Height)
        Dim clone4bpp As Bitmap = originale.Clone(clonerettangolo, Imaging.PixelFormat.Format4bppIndexed)

        clone4bpp.Save("C:clonegreca4bpp.bmp", Imaging.ImageFormat.Bmp)
        clone4bpp.Save("C:clonegreca4bpp.tiff", Imaging.ImageFormat.Tiff)

        ' creo la pallette colori 
        Dim palette As Imaging.ColorPalette = clone4bpp.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
        clone4bpp.Palette = palette

        ' blocco i bit della bitmap per poter lavorare direttamente su un vettore di bytes
        Dim area As Rectangle = New Rectangle(0, 0, clone4bpp.Width, clone4bpp.Height)
        Dim bmpData As Imaging.BitmapData = clone4bpp.LockBits(area, Imaging.ImageLockMode.ReadWrite, clone4bpp.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 Long = Math.Abs(bmpData.Stride) * clone4bpp.Height ' calcolo dei bytes necessari
        Dim colorValues(bytes - 1) As Byte

        ' quello che vorrei fare è andare a leggere il valore del pixel e nel caso che sia diverso dal  bianco  lo coloro come voglio io 
        For ind = 0 To Math.Abs(bmpData.Stride) - 1

            If colorValues(ind) < 14 Then
                colorValues(ind) = 7
            End If
        Next
        System.Runtime.InteropServices.Marshal.Copy(colorValues, 0, ptr, bytes)
        clone4bpp.UnlockBits(bmpData) ' sblocco bit
        clone4bpp.SetResolution(360, 360)
        clone4bpp.Save("C:\clonegreca4bpp.bmp", Imaging.ImageFormat.Bmp)
        clone4bpp.Save("C:\clonegreca4bpp.tiff", Imaging.ImageFormat.Tiff)
        clone4bpp.Dispose()
    End Sub


Ho provato anche a 8bpp , modificando la pallette colori ,il risultato è il medesimo , un bmp completamente nero.
Il problema per me è nel ciclo If colorValues(ind) < 14 , ma non capisco .
Grazie per eventuali suggerimenti .

Allego anche il file che uso per fare le prove.




aaa
17/07/21 16:48
Carlo
Sono molte le cose che non hai considerato.
1) il file che hai allegato ha una palette a 16 colori standard HalfTone:
0=nero, 1=blu,...7=bianco,... 10=rossoscuro, ecc ecc
2) se crei una tua palette con scala di grigio, quello che prima era bianco diventa grigio di livello 7
3) quando blocchi i bit, poi devi mettere i bytes della bitmap nel vettore, altrimenti il vettore conterrà solo zeri
4) il vettore lo devi scorrere tutto, non solo la prima riga
5) quando vai a caccia del colore da variare devi considerare che a 4bpp nel byte ci sono due pixel:
se il livello che cerchi è il 7 (bianco nella tua tiff) in Hex due pixel &H77=119
6) quando hai trovato il livello che vuoi variare, se vuoi mettere un grigio di livello 10, devi inserire &HAA=170

Ora non so se la palette nel tiff ti va bene, o se la devi uniformare ai tuoi livelli di grigio....
Ho correttto il tuo programma che ora sostituisce il 7 (bianco vecchia palette) con il 15 (bianco nuova palette) e mette un 10 dove non c'era il bianco (7)

Spero di non averti confuso le idee, ma purtroppo quando si lavora su bytes che rappresentano immagini, bisogna impegnarsi un po'

        Dim originale As New Bitmap("C:\greca.tiff")
        Dim clonerettangolo As New Rectangle(0, 0, originale.Width, originale.Height)
        Dim clone4bpp As Bitmap = originale.Clone(clonerettangolo, Imaging.PixelFormat.Format4bppIndexed)

        clone4bpp.Save("C:clonegreca4bpp.bmp", Imaging.ImageFormat.Bmp)
        clone4bpp.Save("C:clonegreca4bpp.tiff", Imaging.ImageFormat.Tiff)

        'creo la palette scala di grigio
        Dim palette As Imaging.ColorPalette = clone4bpp.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
        clone4bpp.Palette = palette

        ' blocco i bit della bitmap per poter lavorare direttamente su un vettore di bytes
        Dim area As Rectangle = New Rectangle(0, 0, clone4bpp.Width, clone4bpp.Height)
        Dim bmpData As Imaging.BitmapData = clone4bpp.LockBits(area, Imaging.ImageLockMode.ReadWrite, clone4bpp.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 Long = Math.Abs(bmpData.Stride) * clone4bpp.Height ' calcolo dei bytes necessari
        Dim colorValues(bytes - 1) As Byte
        ' nel vettore colorValues metto i dati dalla locazione ptr che rappresentano clone4bpp
        System.Runtime.InteropServices.Marshal.Copy(ptr, colorValues, 0, bytes)

        'se è ex bianco(7) lo trasformo in bianco(15) altrimenti grigio(10)
        For ind = 0 To bytes - 1
            If colorValues(ind) = 119 Then ' &H77
                colorValues(ind) = 255 ' &HFF
            Else
                colorValues(ind) = 170 ' &HAA
            End If
        Next
        System.Runtime.InteropServices.Marshal.Copy(colorValues, 0, ptr, bytes)
        clone4bpp.UnlockBits(bmpData) ' sblocco bit
        clone4bpp.SetResolution(360, 360)
        clone4bpp.Save("C:\clonegreca4bpp.bmp", Imaging.ImageFormat.Bmp)
        clone4bpp.Save("C:\clonegreca4bpp.tiff", Imaging.ImageFormat.Tiff)
        clone4bpp.Dispose()


La risoluzione orizzontale usando questo metodo è di due pixel, nel senso che il pixel 0 e 1, saranno sempre dello stesso livello, lo stesso per il pixel 2 e 3, 4 e 5, e così via.
Per ovviare, bisogna ogni volta che si legge un byte, spezzarlo in due semibyte, modificare il semibyte voluto e risalvare la coppia modificata...
Ultima modifica effettuata da Carlo 17/07/21 18:46
in programmazione tutto è permesso
18/07/21 7:42
bernie
No , non mi hai fatto confusione , anzi ....
Per quanto riguarda il punto 4 , quella è stata una dimenticanza....
Quello che non ho capito è "System.Runtime.InteropServices.Marshal.Copy(ptr, colorValues, 0, bytes)" bisogna che me lo studio.
Anche il colore del pixel , ma quello inizio a capirlo ( spero )
Ovviamente adesso inizierò ad adattare la tua correzione alle mie necessità e poi staremo a vedere se ho capito .
Per il momento grazie .
Se volessi alzare l'asticella , continuo a postare qui o devo aprire un altro post?
Grazie

aaa
18/07/21 8:53
bernie
Marshal.Copy , in base a come vengono disposti i parametri copia i dati della memoria in un vettore oppure li copia dal vettore alla memoria.
Quindi la prima chiamata , copia dalla memoria a partire dal prt ,nel vettore dove effettuare la copia , inizio,lunghezza dei dati da copiare

Nella seconda chiamata, copia i dati dal vettore iniziando da 0, nella memoria iniziando da prt , per la lunghezza dei dati .

Inizio a capire , bisogna vedere se sarò in grado di utilizzarlo al meglio ....

Nel caso che volessi provare a farlo "Ora non so se la palette nel tiff ti va bene, o se la devi uniformare ai tuoi livelli di grigio...."
considerando che potrei non sapere che file mi arriva , io pensavo ( probabilmente sbagliando) che clonarlo a 4bpp a prescindere da come mi arriva il file , mi doveva uniformare , ma così non è . Ho fato prove con 3 differenti tipi di file ,bitmap, greyscale 4bpp e greyscale 8bpp. il bitmap funziona , il greyscale 8bpp funziona ( e io mi aspettavo di no ) mentre il greyscale 4 bpp mi riempie completamente il bmp. Questo non lo capisco, in teoria doveva funzionare , essendo a 4bpp.
Non capisco.



aaa
18/07/21 23:20
Carlo
Postato originariamente da bernie:

Marshal.Copy , in base a come vengono disposti i parametri copia i dati della memoria in un vettore oppure li copia dal vettore alla memoria.
Quindi la prima chiamata , copia dalla memoria a partire dal prt ,nel vettore dove effettuare la copia , inizio,lunghezza dei dati da copiare

Nella seconda chiamata, copia i dati dal vettore iniziando da 0, nella memoria iniziando da prt , per la lunghezza dei dati .

Inizio a capire , bisogna vedere se sarò in grado di utilizzarlo al meglio ....


Forse ti ha portato fuori strada che negli esempi precedenti il primo Marshal.Copy non c'era.
Ma non serviva perché l'immagine veniva creata ex novo, si partiva con una bitmap vuota e un vettore con tutti zeri.
Invece nell'ultimo esempio parti da un'immagine caricata da HDD, quando dichiari il vettore è vuoto, ci devi mettere i dati della bitmap caricata se vuoi modificare leggendo i valori.
Marshal.Copy, permette di scrivere o leggere byte o blocchi di bytes in memoria e copiarli in vettori o in altre zone di memoria, ma tutto rigorosamente managed (gestito), non puoi fare danni.
Postato originariamente da bernie:
Nel caso che volessi provare a farlo "Ora non so se la palette nel tiff ti va bene, o se la devi uniformare ai tuoi livelli di grigio...."
considerando che potrei non sapere che file mi arriva , io pensavo ( probabilmente sbagliando) che clonarlo a 4bpp a prescindere da come mi arriva il file , mi doveva uniformare , ma così non è . Ho fato prove con 3 differenti tipi di file ,bitmap, greyscale 4bpp e greyscale 8bpp. il bitmap funziona , il greyscale 8bpp funziona ( e io mi aspettavo di no ) mentre il greyscale 4 bpp mi riempie completamente il bmp. Questo non lo capisco, in teoria doveva funzionare , essendo a 4bpp.
Non capisco.


Non capisco cosa ti sfugge, ma mi sembra di capire che non hai chiara la funzione della palette
Le immagini indicizzate, hanno un numero ridotto di colori, ma i colori visualizzabili sono scelti comunque da una collezione di 16.777.216 colori.
prendiamo un'immagine 4bpp, per un pixel si possono definire valori 0...15, ma questi valori non si sa che colore rappresentano, finquando non vai a leggere la palette che contiene i valori RGB associati ai valori 0...15.
Ho scritto due righe che ti fanno aprire files BMP, TIF, TIFF, leggono la palette e la usa per disegnare dei quadratini colorati, il risultato viene mostrato su una picturebox. Con questo programma (progetto VS allegato) puoi scoprire la palette dei file che ti vengono inviati.

Una volta che conosci la palette sei in grado di sapere che valore RGB ha un colore, per esempio il bianco (255,255,255), che nella palette HalfTone è assegnato al 7.
In base alle tue esigenze, devi decidere quanto automatizzare l'interpretazione della palette, tutto è fattibile.

Domande:
Sai come sono memorizzati i dati in ram e cosa sono i bit?
Sai quanti bit ci sono in un byte?
Sai cos'è una word, dword, qword?
Sai cos'è il sistema numerico binario?
Sai cos'è il sistema numerico esadecimale?
Sai come sono codificati i colori RGB e ARGB?

Se a una qualsiasi di queste domande rispondi, no, prima di proseguire devi studiarle, sono concetti molto semplici e è sufficiente una conoscenza di base per proseguire, puoi anche chiedere qui, ti risponderò con piacere.

Per quanto riguarda cambiare post, per ora mi sembra che siamo in tema, anzi se guardi il mio primo esempio della mia prima risposta, vedrai che ci siamo mossi di poco o niente... :rotfl:
Ultima modifica effettuata da Carlo 19/07/21 11:16
in programmazione tutto è permesso
19/07/21 20:42
bernie
Grazie Carlo
Alle domande direi che rispondo sì.
Al momento la situazione è questa, il mio sistema accetta bitmap a 1 bpp, a 8 bpp e a 4 bpp. Lui però usa una "palette" da 3bpp. Quando gli arrivano 8bpp li converte lui, quando gli arriva 1bpp, lo prende così. A questo punto anche se lo accetta non so bene come si comporta con 4bpp. Per me è più comodo lavorare a 4bpp, in quanto il bmp rimane più piccolo. Devo capire cosa succede se gli mando un bmp a 4bpp, lo rimappa come fosse un 8bpp o lo tiene così ? Questo è il dubbio adesso.
aaa
20/07/21 13:09
Carlo
Postato originariamente da bernie:

Grazie Carlo
Alle domande direi che rispondo sì.

Bene.
Postato originariamente da bernie:
Al momento la situazione è questa, il mio sistema accetta bitmap a 1 bpp, a 8 bpp e a 4 bpp. Lui però usa una "palette" da 3bpp. Quando gli arrivano 8bpp li converte lui, quando gli arriva 1bpp, lo prende così. A questo punto anche se lo accetta non so bene come si comporta con 4bpp. Per me è più comodo lavorare a 4bpp, in quanto il bmp rimane più piccolo. Devo capire cosa succede se gli mando un bmp a 4bpp, lo rimappa come fosse un 8bpp o lo tiene così ? Questo è il dubbio adesso.

Ribene, mentre ti togli il dubbio, ti propongo un aggiornamento al codice che divide il byte in semibyte e modifica i pixel contenuti singolarmente. Ho scelto il metodo matematico, ma la stessa cosa si può fare mascherando i bit oppure facendo scorrere i bit>>4 a destra per ricavare il semibyte a sinistra, facendo scorrere i bit<<4 a sinistra poi bit>>4 a destra per ricavare il semibyte a destra, è più veloce, se ti interessa prova o chiedi..

'---------------------- carica e cambia palette, sostituisce colori 4bpp -----------------
        Dim clone4bpp As New Bitmap("C:\greca.tiff")
        'Dim clonerettangolo As New Rectangle(0, 0, originale.Width, originale.Height)
        'Dim clone4bpp As Bitmap = originale.Clone(clonerettangolo, Imaging.PixelFormat.Format4bppIndexed)

        'creo la palette scala di grigio
        Dim palette As Imaging.ColorPalette = clone4bpp.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
        clone4bpp.Palette = palette

        ' blocco i bit della bitmap per poter lavorare direttamente su un vettore di bytes
        Dim area As Rectangle = New Rectangle(0, 0, clone4bpp.Width, clone4bpp.Height)
        Dim bmpData As Imaging.BitmapData = clone4bpp.LockBits(area, Imaging.ImageLockMode.ReadWrite, clone4bpp.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 Long = Math.Abs(bmpData.Stride) * clone4bpp.Height ' calcolo dei bytes necessari
        Dim colorValues(bytes - 1) As Byte
        ' nel vettore metto i dati che rappresentano clone4bpp
        System.Runtime.InteropServices.Marshal.Copy(ptr, colorValues, 0, bytes)

        'se è ex bianco(7) lo trasformo in bianco(15) altrimenti grigio(10)
        For ind = 0 To bytes - 1
            ' scompongo il byte con i due pixel
            Dim primosemibyte As Byte = colorValues(ind) \ 16
            Dim secondosemibyte As Byte = colorValues(ind) - primosemibyte * 16
            If primosemibyte = 7 Then ' pixel a sinistra
                primosemibyte = 15
            Else
                primosemibyte = 10
            End If
            If secondosemibyte = 7 Then ' pixel a destra
                secondosemibyte = 15
            Else
                secondosemibyte = 10
            End If
            colorValues(ind) = primosemibyte * 16 + secondosemibyte ' ricompongo il byte con i due pixel
        Next
        System.Runtime.InteropServices.Marshal.Copy(colorValues, 0, ptr, bytes)
        clone4bpp.UnlockBits(bmpData) ' sblocco bit
        clone4bpp.SetResolution(360, 360)
        clone4bpp.Save("C:\clonegreca4bpp.bmp", Imaging.ImageFormat.Bmp)
        clone4bpp.Save("C:\clonegreca4bpp.tiff", Imaging.ImageFormat.Tiff)
        clone4bpp.Dispose()


Per saggiare la precisione, nel tuo file: greca.tiff, ci sono dei pixel grigi con valore=9
Il codice seguente sostituisce il valore 9 (grigio) con il valore 4 (rosso), senza cambiare la palette.

        '---------------------- carica senza cambiare palette, sostituisce 1 colore 4bpp -----------------
        Dim clone4bpp As New Bitmap("C:\greca.tiff")
        'Dim clonerettangolo As New Rectangle(0, 0, originale.Width, originale.Height)
        'Dim clone4bpp As Bitmap = originale.Clone(clonerettangolo, Imaging.PixelFormat.Format4bppIndexed)

        ''creo la palette scala di grigio
        'Dim palette As Imaging.ColorPalette = clone4bpp.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
        'clone4bpp.Palette = palette

        ' blocco i bit della bitmap per poter lavorare direttamente su un vettore di bytes
        Dim area As Rectangle = New Rectangle(0, 0, clone4bpp.Width, clone4bpp.Height)
        Dim bmpData As Imaging.BitmapData = clone4bpp.LockBits(area, Imaging.ImageLockMode.ReadWrite, clone4bpp.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 Long = Math.Abs(bmpData.Stride) * clone4bpp.Height ' calcolo dei bytes necessari
        Dim colorValues(bytes - 1) As Byte
        ' nel vettore metto i dati che rappresentano clone4bpp
        System.Runtime.InteropServices.Marshal.Copy(ptr, colorValues, 0, bytes)

        'se è grigio(9) lo trasformo in rosso(4) 
        For ind = 0 To bytes - 1
            ' scompongo il byte con i due pixel
            Dim primosemibyte As Byte = colorValues(ind) \ 16
            Dim secondosemibyte As Byte = colorValues(ind) - primosemibyte * 16
            If primosemibyte = 9 Then ' pixel a sinistra
                primosemibyte = 4
            End If
            If secondosemibyte = 9 Then ' pixel a destra
                secondosemibyte = 4
            End If
            colorValues(ind) = primosemibyte * 16 + secondosemibyte ' ricompongo il byte con i due pixel
        Next
        System.Runtime.InteropServices.Marshal.Copy(colorValues, 0, ptr, bytes)
        clone4bpp.UnlockBits(bmpData) ' sblocco bit
        clone4bpp.SetResolution(360, 360)
        clone4bpp.Save("C:\GrayToRed4bpp.bmp", Imaging.ImageFormat.Bmp)
        clone4bpp.Dispose()


Il file è grande per vedere il risultato va zoomato.
Ultima modifica effettuata da Carlo 20/07/21 15:02
in programmazione tutto è permesso
20/07/21 19:48
bernie
Grazie Carlo
Purtroppo non avrò accesso al mio PC fino a fine settimana.
Sembra che il sistema riconosca i bmp a 4 bit e non li rimappa come fa con quelli a 8 bpp.
A questo punto non mi resta che eliminare il quarto bit in maniera da avere una palette da 8 livelli.

aaa