Saving Windows.Media.Drawing with BmpBitmapEncoder black image - how to remove alpha?

3.1k views Asked by At

I'm using SVG# (http://sharpvectors.codeplex.com/), to batch convert SVG files to other formats. The SVG images being converted are black line drawings with no background. I've little experience with WPF or the System.Windows.Media namespace, so please excuse me if this is a basic question.

I'm using a modified version of the ImageSvgConverter from SVG#, which accepts a System.Windows.Media.Drawing object, which is then converted using a System.Windows.Media encoder (BmpBitmapEncoder, PngBitmapEncoder etc) to export to the desired file format.

When I export using either a TiffBitmapEncoderor, PngBitmapEncoder or GifBitmap the images are generated as expected. The generated images all have transparent backgrounds.

However, when I export using the JpegBitmapEncoder or BmpBitmapEncoder, all images are coming out black. As the tif, png and gif all have transparent backgrounds, I think that the jpg / bmp images are being drawn correctly, however, as alpha isn't supported in these file formats, having a black output makes sense as the transparency would be interpreted as nothing / black.

I think this is as described in these SO posts Strange bmp black output from BitmapSource - any ideas? , Convert Transparent PNG to JPG with Non-Black Background Color and Background Turns Black When Saving Bitmap - C#.

However, I cannot see a way of applying the solutions is these posts to my problem. Can anyone point me in the right direction?

I have tried applying a white SolidColorBrush to the DrawingContext's PushOpacityMask method, however, this makes no difference.

Really appreciate any pointers.

        private Stream SaveImageFile(Drawing drawing)
    {
        // black output
        BitmapEncoder bitmapEncoder = new BmpBitmapEncoder(); 

        // works
        //bitmapEncoder  = new PngBitmapEncoder();

        // The image parameters...
        Rect drawingBounds = drawing.Bounds;
        int pixelWidth = (int)drawingBounds.Width;
        int pixelHeight = (int)drawingBounds.Height;
        double dpiX = 96;
        double dpiY = 96;

        // The Visual to use as the source of the RenderTargetBitmap.
        DrawingVisual drawingVisual = new DrawingVisual();
        DrawingContext drawingContext = drawingVisual.RenderOpen();

        // makes to difference - still black
        //drawingContext.PushOpacityMask(new SolidColorBrush(System.Windows.Media.Color.FromRgb(255,255,255)));

        drawingContext.DrawDrawing(drawing);
        drawingContext.Close();

        // The BitmapSource that is rendered with a Visual.
        RenderTargetBitmap targetBitmap = new RenderTargetBitmap(pixelWidth, pixelHeight, dpiX, dpiY, PixelFormats.Pbgra32);

        targetBitmap.Render(drawingVisual);

        // Encoding the RenderBitmapTarget as an image file.
        bitmapEncoder.Frames.Add(BitmapFrame.Create(targetBitmap));

        MemoryStream stream = new MemoryStream();
        bitmapEncoder.Save(stream);
        stream.Position = 0;
        return stream;
    }
1

There are 1 answers

1
Clemens On BEST ANSWER

You could draw a filled "background" rectangle with an appropriate size prior to the actual drawing object.

using (var drawingContext = drawingVisual.RenderOpen())
{
    drawingContext.DrawRectangle(Brushes.White, null, new Rect(drawingBounds.Size));
    drawingContext.DrawDrawing(drawing);
}