Search code examples
c#wpfbitmapimagesource

read jpg, resize, save as png in WPF application c# or vb.net


Going bonkers here trying to do this in WPF (with all the new image manipulation tools), but can't seem to find a working solution. So far, all the solutions are drawing them on the screen or making multiple saves, but I need to do this completely in memory.

Basically, I want to load a large jpeg into memory, resize it smaller (in memory), save as a small PNG file. I can load the jpeg file into a BitMap object, fine. after that, I'm stumped.

I found this function that looks like it does the trick but it requires an ImageSource (unfortunately, I can't find a way to convert my in-memory BitMap object to an ImageSource that does not yield a NULL exception.)

private static BitmapFrame CreateResizedImage(ImageSource source, int width, int height, int margin)
{
    dynamic rect = new Rect(margin, margin, width - margin * 2, height - margin * 2);

    dynamic @group = new DrawingGroup();
    RenderOptions.SetBitmapScalingMode(@group, BitmapScalingMode.HighQuality);
    @group.Children.Add(new ImageDrawing(source, rect));

    dynamic drawingVisual = new DrawingVisual();
    using (drawingContext == drawingVisual.RenderOpen()) 
    {
        drawingContext.DrawDrawing(@group);
    }

    // Resized dimensions
    // Default DPI values
    dynamic resizedImage = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Default);
    // Default pixel format
    resizedImage.Render(drawingVisual);

    return BitmapFrame.Create(resizedImage);
}

Solution

  • With WPF it's as easy as this:

    private void ResizeImage(string inputPath, string outputPath, int width, int height)
    {
        var bitmap = new BitmapImage();
    
        using (var stream = new FileStream(inputPath, FileMode.Open))
        {
            bitmap.BeginInit();
            bitmap.DecodePixelWidth = width;
            bitmap.DecodePixelHeight = height;
            bitmap.CacheOption = BitmapCacheOption.OnLoad;
            bitmap.StreamSource = stream;
            bitmap.EndInit();
        }
    
        var encoder = new PngBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(bitmap));
    
        using (var stream = new FileStream(outputPath, FileMode.Create))
        {
            encoder.Save(stream);
        }
    }
    

    You may consider to only set one of DecodePixelWidth and DecodePixelHeight in order to preserve the original image's aspect ratio.