2009-12-31 27 views
7

Je suis en train d'obtenir un bitmap créé à partir des données brutes à afficher dans WPF, à l'aide d'une image et un BitmapSource:Pourquoi BitmapSource.Create lance-t-il une ArgumentException?

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; 

Cependant l'appel à BitmapSource.Create lance un ArgumentException, en disant « valeur ne tomber dans la fourchette attendue ". N'est-ce pas le moyen de le faire? Est-ce que je ne fais pas cet appel correctement?

Répondre

35

Votre foulée est incorrecte. Stride est le nombre d'octets alloués pour une ligne de balayage du bitmap . Ainsi, utilisez ce qui suit:

int stride = ((RenderWidth * 32 + 31) & ~31)/8; 

et remplacer le dernier paramètre (actuellement 0) avec stride tel que défini ci-dessus.

Voici une explication de la formule mystérieuse de foulée:

Fait: Scanlines doivent être alignés sur les limites 32 bits (reference).

La formule naïve pour le nombre d'octets par ligne de balayage serait:

(width * bpp)/8 

Mais cela pourrait ne pas nous donner une image bitmap aligné sur une limite de 32 bits et (largeur * BPP) pourrait ne pas même avoir été divisible par 8.

alors, ce que nous faisons est que nous forcer notre bitmap d'avoir au moins 32 bits dans une rangée (nous supposons que width > 0):

width * bpp + 31 

et nous dire que nous ne nous soucions pas les bits de poids faible (bits 0 à -4) parce que nous essayons d'aligner sur les limites 32 bits:

(width * bpp + 31) & ~31 

puis diviser par 8 pour revenir à octets:

((width * bpp + 31) & ~31)/8 

Le rembourrage peut être calculée par

int padding = stride - (((width * bpp) + 7)/8) 

La formule naïve serait

stride - ((width * bpp)/8) 

Mais width * bpp peut ne pas s'aligner sur une limite d'octet et, dans le cas contraire, cette formule surpasserait le remplissage par un octet. (Pensez à un bitmap de 1 pixel en utilisant 1 bpp. La foulée est 4 et la formule naïve dirait que le padding est 4 mais en réalité il est 3.) Donc, nous ajoutons un peu pour couvrir le cas que width * bpp n'est pas un octet limite, puis nous obtenons la formule correcte donnée ci-dessus.

+0

Merci, mais comment diable avez-vous trouvé cette expression? Pourquoi n'est-ce pas simplement RenderWidth * 4? N'est-ce pas le nombre d'octets pour une ligne? –

+1

Désolé, j'aurais dû fournir des détails. Dans votre cas, vous avez 'bpp = 32' donc oui la formule se réduit à' RenderWidth * 4'. Mais il y a des cas bizarres (les LCD bon marché utilisent 18 bpp) et le fait que les lignes de balayage doivent être alignées sur des frontières de 32 bits. J'ai fourni la formule générale et une explication de la façon d'en arriver là-dessus. J'espère que ça éclaire. – jason

+1

Merci. Encore une question. Que fait le tilde sur un entier comme ça? –