Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Expand canvas/transparent background in BitmapImage in a WPF app

Tags:

c#

.net

wpf

c#-4.0

This is a follow up question on Save image to file keeping aspect ration in a WPF app

I know howto scale the image, but how do I expand the canvas size, to ensure the image still has the requested width and height. In this example its 250x250 but its dynamic.

I have created this illustration to show what I'm trying to accomplice. alt text

I can't find any way of expanding the canvas of an BitmapImage, nor a way to create an in memory image in the correct size, with a transparent background, and then merging the two images together.

like image 353
gulbaek Avatar asked Jan 13 '11 14:01

gulbaek


1 Answers

CroppedBitmap doesn't seem to support adding space around an image so instead you can create a transparent image the correct size using WriteableBitmap. If the input is smaller than the target size this method will enlarge it, but that is easy to alter.

public static BitmapSource FitImage(BitmapSource input, int width, int height)
{
    if (input.PixelWidth == width && input.PixelHeight == height)
        return input;

    if(input.Format != PixelFormats.Bgra32 || input.Format != PixelFormats.Pbgra32)
        input = new FormatConvertedBitmap(input, PixelFormats.Bgra32, null, 0);

    //Use the same scale for x and y to keep aspect ratio.
    double scale = Math.Min((double)width / input.PixelWidth, height / (double)input.PixelHeight);

    int x = (int)Math.Round((width - (input.PixelWidth * scale))/2);
    int y = (int)Math.Round((height - (input.PixelHeight * scale))/2);


    var scaled = new TransformedBitmap(input, new ScaleTransform(scale, scale));
    var stride = scaled.PixelWidth * (scaled.Format.BitsPerPixel / 8);

    var result = new WriteableBitmap(width, height, input.DpiX, input.DpiY, input.Format,null);

    var data = new byte[scaled.PixelHeight * stride];
    scaled.CopyPixels(data, stride, 0);
    result.WritePixels(new Int32Rect(0,0,scaled.PixelWidth,scaled.PixelHeight), data, stride,x,y);
    return result;
}

If you are already rendering content using RenderTargetBitmap you could wrap it in a ViewBox to do the scaling but if you're just working with normal images I'd use the above method.

like image 72
Kris Avatar answered Oct 19 '22 00:10

Kris