Copying from BitmapSource to WritableBitmap
Asked Answered
B

1

9

I am trying to copy a part of a BitmapSource to a WritableBitmap.

This is my code so far:

var bmp = image.Source as BitmapSource;
var row = new WriteableBitmap(bmp.PixelWidth, bottom - top, bmp.DpiX, bmp.DpiY, bmp.Format, bmp.Palette);
row.Lock();
bmp.CopyPixels(new Int32Rect(top, 0, bmp.PixelWidth, bottom - top), row.BackBuffer, row.PixelHeight * row.BackBufferStride, row.BackBufferStride);
row.AddDirtyRect(new Int32Rect(0, 0, row.PixelWidth, row.PixelHeight));
row.Unlock();

I get "ArgumentException: Value does not fall within the expected range." in the line of CopyPixels.

I tried swapping row.PixelHeight * row.BackBufferStride with row.PixelHeight * row.PixelWidth, but then I get an error saying the value is too low.

I couldn't find a single code example using this overload of CopyPixels, so I'm asking for help.

Thanks!

Brandonbrandt answered 3/5, 2011 at 9:37 Comment(0)
C
20

What part of the image are trying to copy? change the width and height in the target ctor, and the width and height in Int32Rect as well as the first two params (0,0) which are x & y offsets into the image. Or just leave if you want to copy the whole thing.

BitmapSource source = sourceImage.Source as BitmapSource;

// Calculate stride of source
int stride = source.PixelWidth * (source.Format.BitsPerPixel + 7) / 8;

// Create data array to hold source pixel data
byte[] data = new byte[stride * source.PixelHeight];

// Copy source image pixels to the data array
source.CopyPixels(data, stride, 0);

// Create WriteableBitmap to copy the pixel data to.      
WriteableBitmap target = new WriteableBitmap(
  source.PixelWidth, 
  source.PixelHeight, 
  source.DpiX, source.DpiY, 
  source.Format, null);

// Write the pixel data to the WriteableBitmap.
target.WritePixels(
  new Int32Rect(0, 0, source.PixelWidth, source.PixelHeight), 
  data, stride, 0);

// Set the WriteableBitmap as the source for the <Image> element 
// in XAML so you can see the result of the copy
targetImage.Source = target;
Coquito answered 3/5, 2011 at 10:54 Comment(6)
Thanks! I kind of hoped that I could copy directly from the BitmapSource to WritableBitmap... Now I wonder what this overload of CopyPixels is really meant to do...Brandonbrandt
The rectangle overload will copy the bitmap image to a Int32Rect so not so useful to pass that to WriteableBitmap. If you want something really short and you want to copy the whole image: WriteableBitmap target = new WriteableBitmap(Pic1.Source as BitmapSource); Pic2.Source = target;Coquito
And if I want only a part of the BitmapSource (I need a rectangle with a relatively small height and same width)?Brandonbrandt
If you're using a single byte per pixel, this will break. Correct stride calculation of "bytes per pixel" is (bitsPerPixel + 7) / 8Kashmiri
In the answer there is width * (bitsPerPixel + 7) / 8. Should it not instead be width * ((bitsPerPixel + 7) / 8) ?Selby
To add to my confusion, learn.microsoft.com/en-us/dotnet/framework/wpf/… uses (width * pf.BitsPerPixel + 7) / 8Selby

© 2022 - 2024 — McMap. All rights reserved.