Calculating the required buffer size for the WriteableBitmap.WritePixels method
Asked Answered
E

6

19

How do I calculate the required buffer size for the WriteableBitmap.WritePixels method?

I am using the overload taking four parameters, the first is an Int32Rect, the next is a byte array containing the RGBA numbers for the colour, the third is the stride (which is the width of my writeable bitmap multiplied by the bits per pixel divided by 8), and the last is the buffer (referred to as the offset in Intellisense).

I am getting the Buffer size is not sufficient runtime error in the below code:

byte[] colourData = { 0, 0, 0, 0 };

var xCoordinate = 1;
var yCoordinate = 1;

var width = 2;
var height = 2;

var rect = new Int32Rect(xCoordinate, yCoordinate, width, height);

var writeableBitmap = new WriteableBitmap(MyImage.Source as BitmapSource);

var stride = width*writeableBitmap.Format.BitsPerPixel/8;

writeableBitmap.WritePixels(rect, colourData, stride,0);

What is the formula I need to use to calculate the buffer value needed in the above code?

Elver answered 19/12, 2012 at 13:43 Comment(3)
When you say RGBA, you certainly have 32 bits per pixel. That makes 4 bytes per pixel. In a 2x2 rect the total is 16 bytes (4 pixels * 4 bytes/per pixel). Your coulorData is obviously too small.Marcellamarcelle
@Marcellamarcelle Do you mean my Stride is too small? If not could you explain how the colourData is too small, as I don't understand. ThankyouElver
Stride is simply the number of bytes per line in the buffer. You have 4 bytes per pixel at 2 pixels per line (i.e. the width of the write rectangle), resulting in a stride of 8.Marcellamarcelle
M
16

The stride value is calculated as the number of bytes per "pixel line" in the write rectangle:

var stride = (rect.Width * bitmap.Format.BitsPerPixel + 7) / 8;

The required buffer size is the number of bytes per line multiplied by the number of lines:

var bufferSize = rect.Height * stride;

Provided that you have a 2x2 write rectangle and a 32-bits-per-pixel format, e.g. PixelFormats.Pbgra32, you get stride as 8 and bufferSize as 16.

Marcellamarcelle answered 19/12, 2012 at 13:55 Comment(0)
S
4

Although user Clemens answered the question concerning the buffer size, the questioner was not aware that he calculated the buffer size already correct and the problem was somewhere else.

While details are given and discussed in comments there is lacking one comprehensive snippet (and complete usage example of .WritePixels (without .CopyPixels) as well). Here it is (I scanned similar questions, but this has been the best place):

var dpiX = 96;

var writeableBitmap = new WriteableBitmap(width, height, dpiX, dpiX, PixelFormats.Bgra32, null); // Pixelformat of Bgra32 results always in 4 bytes per pixel
int bytesPerPixel = (writeableBitmap.Format.BitsPerPixel + 7) / 8; // general formula
int stride = bytesPerPixel * width; // general formula valid for all PixelFormats

byte[] pixelByteArrayOfColors = new byte[stride * height]; // General calculation of buffer size

// The numbers in the array are indices to the used BitmapPalette, 
//     since we initialized it with null in the writeableBitmap init, they refer directly to RGBA, but only in this case.
// Choose a light green color for whole bitmap (for not easy to find commented MSDN example with random colors, see https://msdn.microsoft.com/en-us/library/system.windows.media.imaging.writeablebitmap(VS.85).aspx
for (int pixel = 0; pixel < pixelByteArrayOfColors.Length; pixel += bytesPerPixel)
{
    pixelByteArrayOfColors[pixel] = 0;        // blue (depends normally on BitmapPalette)
    pixelByteArrayOfColors[pixel + 1] = 255;  // green (depends normally on BitmapPalette)
    pixelByteArrayOfColors[pixel + 2] = 0;    // red (depends normally on BitmapPalette)
    pixelByteArrayOfColors[pixel + 3] = 50;   // alpha (depends normally on BitmapPalette)
}

writeableBitmap.WritePixels(new Int32Rect(0, 0, width, height), pixelByteArrayOfColors, stride, 0);
Skirret answered 22/1, 2018 at 19:9 Comment(0)
S
3

The stride is simply the width in bytes of your input buffer. It is called stride, because sometimes there is extra memory behind each line of an image, which makes it impossible to use the width of the image to read each line of an image.

So in your example, this is 2. You do not need to calculate anything with the bits per pixel of the bitmap, the WritePixels method knows all this information. You need to provide the information about how your input data is structured.

However, as mentioned in the other answer, your example won't work if the bitmap is also 2x2. Then the starting coordinate would be 0,0.

EDIT:

When I look closer at your example, I see the mistake. You say the colourData is the input color. But this is input per pixel. So if you want to change a rect of 2x2, you need the following inputdata:

byte[] colourData = { 0, 0, 0, 0, 0, 0, 0, 0,
                      0, 0, 0, 0, 0, 0, 0, 0 };

And then the bytes per pixel is equal to that of the bitmap, so that is 4, times the width of each line (2), makes total 8.

Sisterhood answered 20/12, 2012 at 10:11 Comment(4)
"So in your example, this is 2" is wrong. The stride is 2 (pixels) * 4 (bytes per pixel) == 8 (bytes) instead.Marcellamarcelle
"You do not need to calculate anything with the bits per pixel of the bitmap" is also wrong. To calculate the stride from the width of the write rectangle, you need the number of bytes per pixel.Marcellamarcelle
In his example I clearly see that he has 4 bytes in his input data, so 1 byte per pixel. It is not about the bytes per pixel of the bitmap, but the bytes per pixel of the input data.Sisterhood
His buffer was too small. That's why he got an exception and asked a question here. Think about it, please. A general solution to calculate the stride and total buffer size would always have to take the bits per pixel into account.Marcellamarcelle
M
3

Here's Microsoft's reflected code that performs the check within CopyPixels

        int num = ((sourceRect.Width * this.Format.BitsPerPixel) + 7) / 8;
        if (stride < num)
        {
            throw new ArgumentOutOfRangeException("stride", MS.Internal.PresentationCore.SR.Get("ParameterCannotBeLessThan", new object[] { num }));
        }
        int num2 = (stride * (sourceRect.Height - 1)) + num;
        if (bufferSize < num2)
        {
            throw new ArgumentOutOfRangeException("buffer", MS.Internal.PresentationCore.SR.Get("ParameterCannotBeLessThan", new object[] { num2 }));
        }
Magnific answered 20/3, 2014 at 13:44 Comment(0)
R
1

I am work with this. 60z fs

   this.playerOpacityMaskImage.WritePixels(
                new Int32Rect(0, 0, this.depthWidth, this.depthHeight),
                this.greenScreenPixelData,
                this.depthWidth * ((this.playerOpacityMaskImage.Format.BitsPerPixel + 7) / 8),
                0);
Retharethink answered 13/9, 2013 at 6:36 Comment(0)
G
-1

I am not sure but try this works for 24 bit rgb

  {
     //your code
       var stride = width * 3;
       WriteableBitmap bmp = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgr24, null);
       bmp.WritePixels(new System.Windows.Int32Rect(0, 0, width , height),byte[],stride,0));

   }
Gremial answered 19/12, 2012 at 13:56 Comment(2)
The question is about how to calculate the buffer size.Marcellamarcelle
And that code won't compile since you write byte[] for the pixels parameter.Marcellamarcelle

© 2022 - 2024 — McMap. All rights reserved.