Che bello. La storia è molto più affascinante di quanto pensassi.
1) Intanto ho sbagliato a scrivere questa formula
int truewidth = (int)((Bits * Dim1 + 31) / 32) * 4; (1)
perchè nella formula che mi ha regalato MItaly (vedi allegato, prima formula) ci sono parentesi
quadre che indicano una funzione soffitto e non la semplice parte intera, dunque più che un cast a
Int si tratta di un Math.Ceiling.Sembra che io non abbia sbagliato, a mia insaputa. D'altra parte il metodo GetBmp che usa i SetPixel3) Wikipedia italiana mi dà un'altra formula per il rowsize (vedi allegato) con tanto di funzione di
Heavside....
funziona in tutti i casi ed usa proprio questa formula.
Esistono due versioni per il termine da "arrotondare" nel calcolo della reale dimensione fisica di
una riga della nostra bitmap, ed a questo fatto è dovuta la presenza di due formule nelle Wikipedie
En e It. In parole povere questo vuol dire che
1) o prendiamo la parte intera di (Bits * Dim1 + 31) / 32 che sarebbe il numero intero che precede e
non eccede quel valore float,
2) o prendiamo la funzione soffitto ovvero il Math.Ceiling di Bits * Dim1 / 32 dunque
il numero intero che segue quel valore float. Le due versioni forniscono gli stessi valori.
2) Ci sono bitmap orientate dal basso in alto e bitmap messe "al contrario", ma non c'è traccia
nell'head del file bmp di questa disposizione;Qui sono ancora al buio.4) Nell'Head del file bmp le dimensioni Width e Height sono indicate in 2 byte ma talvolta il primo
byte indica il valore 'basso' altre volte il valore 'alto'. Anche qui non c'è traccia nell'Head di
un indicatore per leggere correttamente questi dati.
Questa è la parte "affascinante" e credo di aver capito quanto segue:5) il valore rowsize che si deduce dalle formule su citate non sempre è in sintonia col valore
bitmapdata.Stride .
Quando si crea una bitmap vengono costruiti due spazi, uno "fisico" e grande ed uno "logico" più
piccolo compreso al suo interno. Questo è dovuto al fatto che una bitmap lavora con 3 byte per pixel
(24 bit) con valori RGB ma ci si riserva sempre la possibilità di "espanderlo" in modo che ad ogni
pixel si possa aggiungere il canale alfa e dunque essere trattato a quattro byte ARGB (es.
conversione bmp -> png, 32 bit) senza dover spostare il file o peggio ancora invadere lo spazio
delle informazioni confinanti.
Lo spazio logico è molto importante perchè è lì che effettivamente si trovano i dati immagine, e la
sua larghezza (byte x riga) dovrebbe essere 3*Width byte senonchè questo valore si arrotonda ad un
prossimo valore multiplo di 4 se non lo è già, ed è qui che entra in gioco il famigerato termine di
cui sopra. L'importanza di questo "truewidth" viene a galla nella formula di associazione tra le
coordinate pixel ed il puntatore nel filestream
sp = Ofs + (Bits / 8) * x + truewidth * (Dim2 - y - 1);
e come si vede non viene usato il valore Dim1 al suo posto.
Lo spazio fisico è quello che potete osservare in risorse del computer dalle dimensioni in byte del
file ed è sempre costituito dai 54 byte dell'intestazione + una matrice di Dim2 righe ognuna larga
4*Dim1 byte ed è questo ultimo valore che rappresenta il famoso Stride.
Invece non riesco a trovare nell'intestazione i byte di riferimento per la grandezza del truewidth,
almeno io non li vedo da nessuna parte, esiste l'indicazione dei byte totali per il file ma non è un
valore affidabile, a meno che non ci siano dei byte aggiunti e riservati oltre lo spazio immagine e
lo spazio dell'intestazione. Dobbiamo pregare che il valore di truewidth coincida con quello
calcolato con la formula (1).....
Ecco di seguito alcuni valori ottenuti costruendo mini-bitmap tutte con 3 righe a larghezza
variabile di pixel:
Dim1 truewidth BitmapData.Stride
5 16 20
6 20 24
7 24 28
8 24 32
9 28 ... ecc. ecc. = 4*Dim1
10 32
11 36
12 36
13 40
14 44
15 48
16 48 .... ecc. ecc.
...
996 2988 3984
997 2992 3988
998 2996 3992
999 3000 3996
1000 3000 4000