Welcome to Pete Brown's 10rem.net

First time here? If you are a developer or are interested in Microsoft tools and technology, please consider subscribing to the latest posts.

You may also be interested in my blog archives, the articles section, or some of my lab projects such as the C64 emulator written in Silverlight.

(hide this)

Silverlight 3 – The Bitmap API / WriteableBitmap

Pete Brown - 18 March 2009

Silverlight 3 introduces the new Bitmap API useful for accomplishing three primary goals:

  • Creation of a bitmap completely from scratch, pixel-by-pixel
  • Client-side manipulation of an image loaded from your server or the local machine
  • Rendering of a portion of the visual tree to bitmap to perform screen-shot like functionality (or improve performance by pre-rendering and caching elements in certain situations)

Creating a Bitmap From Scratch

The key to generating a bitmap is the WriteableBitmap class found in System.Windows.Media.Imaging. You use that class to create a source which is assigned to a normal Image element.

    <Grid x:Name="LayoutRoot">
        <Image x:Name="MyBitmap"
               Width="200"
               Height="200" />
    </Grid>

Here’s the code to generate a funky image

private void BuildBitmap()
{
    const int imageWidth = 200;
    const int imageHeight = 200;

    WriteableBitmap b = 
        new WriteableBitmap(imageWidth, imageHeight, 
                            PixelFormats.Bgr32);

    b.Lock();


    for (int x = 0; x < imageWidth; x++)
    {
        for (int y = 0; y < imageHeight; y++)
        {
            // generate a color in Pbgra32 format
            byte[] components = new byte[4];
            components[0] = (byte)(x % 255);        // blue
            components[1] = (byte)(y % 255);        // green
            components[2] = (byte)(x * y % 255);    // red
            components[3] = 0;      // unused

            // you could certainly do your own masking here
            int pixelValue = BitConverter.ToInt32(components, 0);

            // set the pixel value
            b[y * imageWidth + x] = pixelValue;
        }
    }

    b.Invalidate();
    b.Unlock();

    MyBitmap.Source = b;

}

The code generates this bitmap:

image

The order of operations: Lock, Write, Invalidate, Unlock is significant. As of this writing, they are required in that order for WPF compatibility.

You can also manipulate a current bitmap and render the contents of a control to a bitmap. I’ll cover those in a future post as they aren’t 100% baked as I write this.

   
posted by Pete Brown on Wednesday, March 18, 2009
filed under:    

33 comments for “Silverlight 3 – The Bitmap API / WriteableBitmap”

  1. Jon Davissays:
    I wonder, how fast is it for display? If you were to populate the pixels of an 800x600 rectangle (assume the generation algorithm is instant), how fast would it render for display? I'm thinking in terms of frames per second.
  2. Enversays:
    Hi Pete Brown, Before my question I want to thank you very much for this article, I need proccess an exist image on the server, is it possible whit this techic ? and what can I do that, thanks again.
  3. Pete Brownsays:
    @RB

    Can you tell me what you'd use that for?

    The new bitmap API in Silverlight will let you render a branch of the visual tree to a bitmap, so that may cover some/all of your use cases.

    Otherwise, let me know what you'd like to do with it and I'll pass the feedback along to the team.

    Pete
  4. Tim Greenfieldsays:
    Thanks for the article! Do you know if there is any way to get pixel values from an existing image? I see WritableBitmap has an overloaded constructor to take an existing ImageSource but trying to retreive pixel values from it throws an exception.
  5. Pete Brownsays:
    @Tim

    The current beta has a limitation where you can't get pixels once the image is rendered.

    That limitation should be lifted by RTW. Note that there will continue to be limitations on Cross-Domain or DRM content and reading pixels from them.

    Pete
  6. Dave Harveysays:
    @Pete

    You asked for potential uses....here's the one I need. I need to be able to render medical images (typically 12-16 bits) via a complicated non-linear transform to end up with 8 bit images (source format is industry standard DICOM), so unless I'm missing something, this is the only way to do it.

    So - on my wish list would be a REALLY efficient and simple method to "blt" content from a standard byte or uint array into a section of a WriteableBitmap, rather than having to pole values one at a time.

    Unless/until that gets into the next version, can anyone suggest a better way of putting arbitrary pixel data out onto a sliverlight screen?

    Dave
  7. Brauliosays:
    The third point that you commented:

    Rendering of a portion of the visual tree to bitmap to perform screen-shot like...

    Is quite interesting, in my case (I have develop a DBSchema editor), to export the diagram to a jpeg I need to go to the server and repaint everything using GDI+, if WriteableBitmap works as you commented I would only have to grab the canvas parent and export it to a bitmap, then show a Save as File dialog and let the user save it to his hard disk.

    Is it so easy? or does it have any hidden trick? Right now I have only seen fractal samples applied to this class and no real XAML snapshots.

    Thanks
    Braulio
  8. Pete Brownsays:
    @Braulio

    I can't say if the file format will be correct or if you'll need to write the bitmap header yourself. Not much effort if you have to, either way.

    Gotchas generally revolve around the source of the image (cross-domain, drm'd content on screen etc.). Also, the beta has some issues in that area as I recall, so I wouldn't recommend playing that specific feature too much until RTW.

    That all said, yes, you can take some branch of the visual tree and render it to an image.

    Pete
  9. Cranksays:
    <p>I would also like to backup Braulio post. The Graphics abilities of Silverlight suck compared to Java Applets or Flash - period.</p><p>Without a way to efficently BLIT colors to a Writable Bitmap it is practically useless, because it is it increadibly slow - especially at high fill rates.</p><p>In fact the lack of immediate rendering of any type in Silverlight and WPF is a huge problem for both platforms and just makes the tasks of building commercial realtime applications impossible (or at least preserves third parties to do so - I assume MS will have an internal immediate API, if they decide to port the Office to Silverlight - right? The question is why do we bother support these frameworks then?</p><p>In Silverligth 3.0 beta the only way to make something like immediate rendering is to render UI elements in a writable bitmap, but this is simply ridiculous, because they have dependency properties, which are very heavy to get/set and probably build offsceen visual trees to reduce overdraw - blah blah blah. Such rendering will also make the GC choke after a while. The problems with retained rendering is that it is only good for animations where overlaps can occur - which is not the case for many box model applications (like display of text for example) where overdraw is not a problem or for high level of detail applications where to retain everything will need tons of RAM. The same is the story with the WPF rendering context - I have never seen a worse rendering API.</p><p>What was the problem to port something like GDI software renderer to Silverlight? GDI is bad too, but at least is immediate and semi light-weight. Take Java for example - if you wrote something in the 90ths it will run today - everywhere. If you wrote something for .NET in 2003 - it will now not run anywhere.</p><p>The hype around Silverlight and WPF (Vista) however does its job well and that why my clients want WPF/Silverlgiht applications. Otherwise I would not spend my time researching them any more... This however does not change the fact that the overlap graphics design of WPF/Silverlight is bad.</p>
  10. Pete Brownsays:
    @Crank

    Braulio was asking about rendering scene content out to a bitmap to store elsewhere. That's not at all what you are arguing.

    What you are arguing is retained mode vs. immediate mode graphics systems. Each have their own uses and target application types. You can't say one is "better" than the other because that is a very scenario-specific decision.

    Why would something like Office need an immediate-mode API? Tell me the scenario you have (or office has) which requires the immediate mode model. Heck, I wrote a C64 emulator that uses Silverlight's MediaStreamSource API. You don't get much more real-time than an emulator. I'm definitely not saying you don't need immediate mode, I just want to better understand *why* you want it, and whether or not there are other ways Silverlight can currently support it.

    Note that the new JavaFX plug-in is also a retained mode graphics systems. SVG is a retained-mode scene API.

    Your 2003 .NET code generally works fine in the full .net runtime we have available today. It probably will not work without change in Silverlight or Windows Mobile (compact framework) as those are different variations of the framework. Similarly, your 90s Java code isn't going to work in JavaFX.

    I'm also not sure why WPF is confused with Vista. Vista and WPF share some of the same low-level presentation code, but Vista doesn't run on WPF and WPF is not tied to Vista. WPF runs on Windows XP, Vista, Windows 7, Windows Server 2003/2008 etc. Silverlight runs on Win2k, WinXP, Vista, Win7, Server 2008 (probably also on server 2003), Mac OSX and (through moonlight) Linux.
  11. Pete Brownsays:
    @Crank

    Re-reading your post, you must be interested in developing frame-based games. You were all over the place, so let me know if that's the correct assessment of what you want to d.

    If that's the case, then yes, Silverlight and WPF are not optimized for that. You can do it, but you won't eek out the performance you probably really want. On Windows, you probably wouldn't use WPF; you'd use XNA.

    On the web, well, you can eek perf out of most of the available plug-ins, but none of them reach the level of performance expected by users of desktop-based hardware-accelerated games.

    Pete
  12. Pure Kromesays:
    Hi Pete,

    Is there any way you can now save the generated image to a byte array? (so we could then send it over the wire to a webservice or to isolated storage, etc..)

    -PK-
  13. Pete Brownsays:
    @Pure Krome

    As I recall, the beta had some issues where you couldn't access the pixels once rendered.

    However, you should be able (at least by RTW) to get the individual pixels and do whatever you want with them, including sending to a web service or to isolated storage.

    In the mean time, if you're generating the pixels yourself, you can mirror changes to the image in an in-memory array by writing to both at the same time, and send that access the wire.

    Pete
  14. RBsays:
    Pete, the reason for needing a "real" drawing API in Silverlight is that in applications that have a large # of dynamically created visual elements (e.g. a time series chart with 50000 data points, or a complex animated graphic of an energy distribution network), creating such a visual representation using shape elements performs terribly, in terms of memory and speed. The ability to enable developers to invoke lower level drawCircle, drawRect, drawText and other APIs that function closer to the metal and do not require a complex visual tree - just more code.

    All of these types of applications I've described are very easily do-able in Flash (ActionScript's drawing API), Java (Java2D), or even WPF and GDI+.

    There *must* be a layer in Silverlight that does all this work but that isn't exposed. All I'm suggesting is that it should be exposed and supported.

  15. Pete Brownsays:
    @RB and others

    I've passed this feedback and the mentioned scenarios on to the Silverlight team for consideration. No guarantees, but at least it gets on the list of requested features to be prioritized.

    Pete
  16. Brauliosays:
    Hey Pete !

    Sorry I just revisited your blog and found that you answered my question, thanks.

    I'm looking for some post where it explains how to export a canvas as a bitmap, but right now only found mandlebrot and random pixel drawing stuff.

    About the format, you are right I was thinking about GDI+ and in SL you don't have a way to save a JEPG (well.. .except adaptaing a free library or writing one by yout self... pain in the neck).

    Thanks
    Braulio
  17. Brauliosays:
    Pete,

    Just found the sample:

    http://www.wintellect.com/CS/blogs/jprosise/archive/2009/03/25/more-on-silverlight-3-s-new-writeable-bitmap.aspx

    And the limitation on current beta :-(

    In SL3 beta, you can "Render" any control to a WriteableBitmap, but such bitmap can only be used as an image source due to security restriction.

    http://silverlight.net/forums/p/105680/240986.aspx#240986

    Let's see if in RTW this is finally relaxed it would be a major improvement.
  18. Brauliosays:
    Compiled info from several post / forums in a library, Export Canvas to PNG:

    http://geekswithblogs.net/braulio/archive/2009/07/12/export-canvas-to-png-and-save-it-in-your-local.aspx

    thanks a lot for your help Pete
  19. Krissays:
    This pains me:

    // generate a color in Pbgra32 format
    byte[] components = new byte[4];
    components[0] = (byte)(x % 255); // blue
    components[1] = (byte)(y % 255); // green
    components[2] = (byte)(x * y % 255); // red
    components[3] = 0; // unused

    // you could certainly do your own masking here
    int pixelValue = BitConverter.ToInt32(components, 0);

    // set the pixel value
    b[y * imageWidth + x] = pixelValue;

    Why not this (which should be 100 times faster):


    b[y * imageWidth + x] = (x % 255) << 16 | (y % 255) << 8 | (x * y % 255);

  20. Herresays:
    to create the color represented as an integer you might also consider using:

    private static int FromArgb(byte a, byte r, byte g, byte b)
    {
    return a << 24 | r << 16 | g << 8 | b;
    }


    cheers.
    Herre
  21. Andresays:
    Hi

    I have trouble building this code for Silverlight 3.

    Specifically:

    PixelFormats type is unknown.
    WriteableBitmap.Lock() method is undefined.
    WriteableBitmap.Unlock() is undefined.
    WriteableBitmap[] operator is undefined.

    To me these look like WPF-specific types/methods?

    Am I missing a particular assembly, SDK or toolkit version perhaps?

    I am using Visual Studio 2008 SP1 with:
    Silverlight 3 SDK (3.0.40818.0)
    Silverlight 3 Tools Visual Studio 2008 SP1 (9.0.30730.126)


  22. Andresays:
    Answer to my previous comment questions found here [http://www.wintellect.com/CS/blogs/jprosise/archive/2009/03/23/silverlight-3-s-new-writeablebitmap.aspx] :
    --------------------------------------------------------------------------
    Thursday, July 16, 2009 7:17 AM by jprosise
    Delete the calls to Lock and Unlock. Remove the third parameter from the WriteableBitmap constructor. And change bitmap[...] to bitmap.Pixels[...]. Then it will work.
    ---------------------------------------------------------------------------

Comment on this Post

Remember me

4 trackbacks for “Silverlight 3 – The Bitmap API / WriteableBitmap”

  1. DotNetShoutoutsays:
    Thank you for submitting this cool story - Trackback from DotNetShoutout