Perché BitmapSource.Create lancia un'ArgumentException?
-
22-09-2019 - |
Domanda
Sto cercando di ottenere una bitmap creata da dati grezzi da mostrare in WPF, utilizzando un'immagine e un BitmapSource:
Int32[] data = new Int32[RenderHeight * RenderWidth];
for (Int32 i = 0; i < RenderHeight; i++)
{
for (Int32 j = 0; j < RenderWidth; j++)
{
Int32 index = j + (i * RenderHeight);
if (i + j % 2 == 0)
data[index] = 0xFF0000;
else
data[index] = 0x00FF00;
}
}
BitmapSource source = BitmapSource.Create(RenderWidth, RenderHeight, 96.0, 96.0, PixelFormats.Bgr32, null, data, 0);
RenderImage.Source = source;
Tuttavia, la chiamata a BitmapSource.Create genera un'ArgumentException, dicendo che "Il valore non rientra nell'intervallo previsto".Non è questo il modo per farlo?Non sto effettuando quella chiamata correttamente?
Soluzione
Il tuo passo non è corretto.Stride è il numero di byte assegnati per una linea di scansione della bitmap.Pertanto, utilizzare quanto segue:
int stride = ((RenderWidth * 32 + 31) & ~31) / 8;
e sostituire l'ultimo parametro (attualmente 0
) con stride
come sopra definito.
Ecco una spiegazione per la misteriosa formula del passo:
Fatto:Le linee di scansione devono essere allineate sui limiti a 32 bit (riferimento).
La formula ingenua per il numero di byte per linea di scansione sarebbe:
(width * bpp) / 8
Ma questo potrebbe non darci una bitmap allineata su un limite di 32 bit e (larghezza * bpp) potrebbe non essere nemmeno divisibile per 8.
Quindi, quello che facciamo è forzare la nostra bitmap ad avere almeno 32 bit di fila (supponiamo che width > 0
):
width * bpp + 31
e poi diciamo che non ci interessano i bit di ordine inferiore (bit 0--4) perché stiamo cercando di allinearci sui limiti di 32 bit:
(width * bpp + 31) & ~31
e poi dividere per 8 per tornare ai byte:
((width * bpp + 31) & ~31) / 8
L'imbottitura può essere calcolata da
int padding = stride - (((width * bpp) + 7) / 8)
La formula ingenua sarebbe
stride - ((width * bpp) / 8)
Ma width * bpp
potrebbe non allinearsi su un limite di byte e in caso contrario questa formula conterebbe eccessivamente il riempimento di un byte.(Pensa a una bitmap larga 1 pixel che utilizza 1 bpp.Il passo è 4 e la formula ingenua direbbe che il riempimento è 4 ma in realtà è 3.) Quindi aggiungiamo un po' per coprire il caso che width * bpp
non è un limite di byte e quindi otteniamo la formula corretta indicata sopra.