zetar
zetar

Reputation: 1233

How to copy an Image into a section of a WriteableBitmap (C# & WPF)

Many apologies if this is a duplicate. I am writing a number of BitmapImages onto a specific portion of a canvas like this (snippet). It works fine:

  TreeFile = "pack://application:,,,/Images/" + TreeFile;

                        var image = new Image
                        {
                            Source = new BitmapImage(new Uri(TreeFile))
                        };
                        image.Width = 10;
                        image.Height = 10;

                        Canvas.SetLeft(image, x );
                        Canvas.SetTop(image, y );
                        MainCanvas.Children.Add(image);

What I want to do is to also copy imageto a WriteableBitmap BlankMap;at the same time and in the same location (MainCanvas and the BlankMap are the same size). This is to create an 'undo'. Then, assuming the user wants to keep the new composite image copy BlankMapto the final BitmapImage WorkingMap;Lastly, I will need to save the now completed WorkingMapto disk.

So my questions are:

  1. Is using WriteableBitmaps the correct way to go for this?
  2. How would I write imageto BlankMap?
  3. How would I write BlankMapto WorkingMap(though #2 and #3 are probably the same question/answer.

Thanks! And, again, apologies if this is some form of a duplicate question.

Upvotes: 0

Views: 1537

Answers (2)

Mark Miller
Mark Miller

Reputation: 985

This works for me:

    public static void CopyImageTo(Image sourceImage, int x, int y, WriteableBitmap target)
    {
        BitmapSource source = sourceImage.Source as BitmapSource;

        int sourceBytesPerPixel = GetBytesPerPixel(source.Format);
        int sourceBytesPerLine = source.PixelWidth * sourceBytesPerPixel;

        byte[] sourcePixels = new byte[sourceBytesPerLine * source.PixelHeight];
        source.CopyPixels(sourcePixels, sourceBytesPerLine, 0);

        Int32Rect sourceRect = new Int32Rect(x, y, source.PixelWidth, source.PixelHeight);
        target.WritePixels(sourceRect, sourcePixels, sourceBytesPerLine, 0);
    }

    public static int GetBytesPerPixel(PixelFormat format)
    {
        return format.BitsPerPixel / 8;
    }

Upvotes: 0

Berin Loritsch
Berin Loritsch

Reputation: 11463

Based on my experience with a mapping tool, I'm concerned that you are applying a thought process that makes sense in WinForms and causes problems in WPF. Please be careful with generated images in WPF as they can easily leak memory due to a long standing bug deep in the framework.

Question #1

Is this the right way to do "undo" functionality? No. However, WPF allows you to add, move, and remove elements quite easily.

I believe it was envisioned that you would implement your changes using commands, and then repeal a command from the stack when you want to undo it. However, I have yet to see an example of this in any meaningful way.

Question #2

When you initialize a WriteableBitmap with an existing ImageSource, you simply initialize it by passing it in the constructor:

var BlankMap = new WriteableBitmap(image);

After that, you would follow the code example listed in the class documentation.

Question #3

You would reverse the process.


The bottom line is that it sounds like you are wanting to do some graphical editing of some sort. Bitmaps work great in WinForms so it's easy to get suckered into believing they will work just as great in WPF. They do not. If you limit your use of bitmaps to display only then you will have a much easier time dealing with memory leaks and such.

Upvotes: 1

Related Questions