简体   繁体   中英

Simple Image Processing in WinRT

I'm working on a WinRT app that should require some image processing. I've done something similar so far but in Java, I would like to do some simple things in WinRT app also... But I can't seem to manage my way with the API...

Long story short, I have in xaml, on my page, an image that obtains an image with a file picker. Then when I click a "negativate" button, the image should get negativated.

Now, the method for the negativation button, I thought to look like this :

private void OnNegativateButtonClick(object sender, RoutedEventArgs e)
    {
        var imageToNegativate = ImagePanel.Source as WriteableBitmap ;

        if (imageToNegativate == null) //Actually is ALWAYS null :(
        {
            //Wrong code here...
            var bitmapSource = ImagePanel.Source as BitmapSource;
            imageToNegativate = new WriteableBitmap(imageToNegativate.PixelWidth, imageToNegativate.PixelHeight);
        }
        imageToNegativate = ImageUtil.Negativate(imageToNegativate);
        ImagePanel.Source = imageToNegativate;
    }

This is very similar to this sample I found here but that sample project won't even load so I tried to open the files individually... My code is that method for negativation only there is something wrong with wb = new WriteableBitmap(bs); in his if (wb==null) { ... } .

What is the approach to take a WriteableBitmap from an image , do some pixel manipulation, and then set the source of the image with the new WriteableBitmap...

I'm saying about WriteableBitmap because my method for negativation uses one for input, does some processing and outputs it. (same type, WriteableBitmap .

Any suggestions or help is greatly appreciated, thank you!

The first problem is these lines of code:

var imageToNegativate = ImagePanel.Source as WriteableBitmap ;
if (imageToNegativate == null) //Actually is ALWAYS null :(

The null is telling you that ImagePanel.Source is not of type WriteableBitmap ; your typecast failed. This is expected; the picker is going to give you something read-only, because read-only images are more performant (WinRT can do some optimizations if it knows the image's content isn't going to change). You only get a WriteableBitmap when you explicitly create one.

The body of your if block also doesn't make much sense -- you're trying to create a new, empty WriteableBitmap with the same size as the original image, and then you try to do an inverse-video on that empty image. Even if you got that far, you'd just get another empty image. You're not doing anything to keep the pixels from the original image.

You do need a WriteableBitmap to get access to the pixel buffer, but you need to make one that's a copy of the original image. Get rid of your cast and if block, and try this instead:

var imageToNegativate = new WriteableBitmap(ImagePanel.Source);

Joe is right in saying what is wrong with your code, but while his answer would probably work in WPF - the constructor he mentions indeed doesn't exist in WinRT/XAML. There is in fact no way to create a WriteableBitmap from a BitmapImage and the only way to attack it is to create a WriteableBitmap from the source of your BitmapImage.

One approach then would be to create a new 1x1-sized WriteableBitmap, then use its SetSource method on the source of your BitmapImage. Since the BitmapImage.UriSource property is a Uri and WriteableBitmap.SetSource() requires a Stream - you need to play with it a bit to find or download the actual image file and open a stream to read it. My toolkit has some extension methods ( WriteableBitmap.FromBitmapImage() ) to help you with it in case your images come from your application package and you could fairly easy expand it to also work with downloaded images.

The problem is - you get some inefficiencies that way - one is that you need to open and decode the file twice (which might be slow with large images on an ARM device - been there, done that), second is that you might need to re-download the file if it came from the network and third that there is a bug in WinRT/XAML that causes the UriSource property of a BitmapImage to become null if you set CacheMode of an associated Image control to BitmapCache, so you might need to track your sources separately anyway.

The best solution in many ways is to simply make sure you open the source image as a WriteableBitmap from the beginning, so you don't even have to create another bitmap if you want to change it anyway. In your case the user selects the image file, so there is only one file and it seems to have a pretty big chance of being processed afterwards so opening it as a WriteableBitmap sounds like the right thing to do.

Perhaps even if you want to keep both the original and processed version of the image - creating a new WriteableBitmap of same size and copying the pixels of the original might be faster (especially on an ARM device) than decoding a big image file twice.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM