Silverlight Image: how to invert or negated image colors?
The problem is how to invert colors of a Silverlight Image element.
There is an Image with a JPG as a source. On a button click I need to invert the colors. Sounds simple, right. Take each pixel, then modify it's value by 2开发者_Go百科55 - pixel value. But when I tried WritableBitmap loaded with the Image source, I got security exception disallowing pixel access. Here is my code:
if (MainLeftImage.Source != null)
{
WriteableBitmap bitmap = new WriteableBitmap((BitmapSource)MainLeftImage.Source);
byte[] pixels = new byte[bitmap.Pixels.Length];
int size = pixels.Count();
for (int i = 0; i < size; i++)
pixels[i] = (byte)(255 - pixels[i]);
bitmap.Invalidate();//redraw and then plug it back on
MainLeftImage.Source = bitmap;
}
}
catch (Exception ex)
{
}
Looks that WritableBitmap is not a solution, right? Any help appreciated. Thanks guys.
Easiest way to invert an image would be to apply a pixel shader effect. I believe that there is an invert colors pixel shader in the WPF Pixel Shader Effects Library.
The reason that you are hitting the Security Exception is that WriteableBitmap prevents pixel access to cross-domain content. To understand why this is important, you can see my explanation of the necessity of client access policy files in this answer. To understand the point for images, just replace "secretaccountdetails.html" with "myPrivatePhoto.jpg" in the example.
If you really want to use a WriteableBitmap to access the pixels of an Image, either:
1. Make sure that the image source is served from the same domain as the application.
or
2. Make sure that the server from which the image is being served provides an appropriate client access policy and download the image file as a Stream. Use BitmapSource.SetSource(Stream) to set the source of the Image instead of setting it to the URL of the image.
In both of the above cases you will be able to access the pixels of an Image in a WriteableBitmap.
Yeah, that seems like a pretty silly restriction on the WritableBitmap. I'm not sure what scenario they're trying to prevent there. I believe that particular exception gets thrown whenever you're accessing cross-domain content, and it might work if the JPEG is coming from exactly the same server that is hosting the Silverlight app. See here:
http://forums.silverlight.net/forums/t/118030.aspx
But I'm honestly not sure of all the possible causes.
One option would be to use the FJCore library to decode the JPEG image to a bitmap, do the pixel flipping on the decoded bitmap, and then load the resulting bitmap into an image directly.
http://code.google.com/p/fjcore/
You need to solve the cross domain access like the other answers proposed. But there's also a failure in your algorithm. The WriteableBitmap.Pixels array stores each pixel as integer value. The 4 bytes of the int represent the alpha, red, green and blue component of the pixel (ARGB). You should implement it like this:
int[] pixels = bitmap.Pixels;
int size = pixels.Length;
for (int i = 0; i < size; i++)
{
// Extract color components
var c = pixels[i];
var a = 0x000000FF & (c >> 24);
var r = 0x000000FF & (c >> 16);
var g = 0x000000FF & (c >> 8);
var b = 0x000000FF & (c);
// Invert
r = 0x000000FF & (0xFF - r);
g = 0x000000FF & (0xFF - g);
b = 0x000000FF & (0xFF - b);
// Set result color
pixels[i] = (a << 24) | (r << 16) | (g << 8) | b;
}
As others proposed, you can use a pixel shader effect instead. But you'll have to show the picture in an Image control in order to apply a shader to it. After that you can render the result into a WriteableBitmap.
var wb = new WriteableBitmap(myImageUiElement, null);
精彩评论