Bliting two WriteableBitmap with WriteableBitmapEx - c#

I tried to blit two writeablebitmap.
However, the debugger prompted a error message stating the followings:
The input WriteableBitmap needs to have the Pbgra32 pixel format. Use the BitmapFactory.ConvertToPbgra32Format method to automatically convert any input BitmapSource ?to the right format accepted by this class.
Here is my code.
Rect cRect =new (320,240);
WriteableBitmap _bitmap = new WriteableBitmap(320, 240, 96, 96, PixelFormats.Bgr32, null);
_bitmap.WritePixels(new Int32Rect(0, 0, 320, 240), _image, 320*240, 0); //_image is a image stream
_bitmap.Blit(cRect, _imageFrame, cRect); //_imageFrame is another writeablebitmap
Actually _imageFrame is a WriteableBitmap from a canvas which will change its content at regular time. Is there a more effective way to blit a writeablebitmap and a canvas?

Can you change to this line:
WriteableBitmap _bitmap = new WriteableBitmap(320, 240, 96, 96, PixelFormats.Pbgra32, null);
and something similiar on the _imageFrame WriteableBitmap

Related

WPF thumbnail image is blurry

I have a WPF app which saves out a thumbnail image as png. The code works well enough but when I open the image is very blurry. The image that it grabs comes from the canvas itself. The canvas changes its width and height depending on the image I'm loading. The desired thumbnail size will be 200 x 200 (pixels).
Here is my code
public void CreateThumbail(Canvas canvas, string filename)
{
RenderTargetBitmap rtb = new RenderTargetBitmap(
(int)canvas.ActualWidth,
(int)canvas.ActualHeight,
96, //dip X
96, //dpi Y
PixelFormats.Pbgra32);
rtb.Render(canvas);
PngBitmapEncoder pngImage = new PngBitmapEncoder();
pngImage.Frames.Add(CreateResizedImage(rtb, 200, 200, 0));
using (var filestream = System.IO.File.Create(filename))
{
pngImage.Save(filestream);
}
}
private static BitmapFrame CreateResizedImage(ImageSource source, int width, int height, int margin)
{
var rect = new Rect(margin, margin, width, height);
var group = new DrawingGroup();
RenderOptions.SetBitmapScalingMode(group, BitmapScalingMode.HighQuality);
group.Children.Add(new ImageDrawing(source, rect));
var drawingVisual = new DrawingVisual();
using (var drawingContext = drawingVisual.RenderOpen())
drawingContext.DrawDrawing(group);
var resizedImage = new RenderTargetBitmap(
(int)rect.Width, (int)rect.Height,// Resized dimensions
96, 96, // Default DPI values
PixelFormats.Pbgra32); // Default pixel format
resizedImage.Render(drawingVisual);
return BitmapFrame.Create(resizedImage);
}
I saved out the image before I resize it and it looks crisp and sharp. yet when I save out the thumbnail it's ugly and blurry. What am I doing wrong? Am I over-engineering this? Many thanks in advance.
Probably you need to respect the original dimensions of the image. For instance an image that is 400x400 will downscale to 200x200 quite nicely, but an image that is 235x235 will not.
This doesn't consider images that are not square to begin with.
You might try reducing the image height and width by a good factor (I would start by halving) repeatedly until the image is smaller than 200x200 and then padding it with white or transparent.
Image processing can be quite hard. It's not something I'm an expert in either so I'd probably try a 3rd party library like this one I just found on google: https://imageprocessor.org/

Rotate writeable bitmap without creating a new bitmap

Ok so here's how this works:
camera sends me an image as a writeable bitmap
client.WhenMasterFrameCaptured().ObserveOn(SynchronizationContext.Current).Subscribe(frame => UpdateMasterCameraPreview(frame));
I set that pointer to an image source(wpf Image control) in the method that this is subscribed to
if (cameraOneBitmap != null)
{
frame.Image.CopyTo(cameraOneBitmap);
}
else
{
cameraOneBitmap = frame.Image.ToWriteableBitmap();
}
cameraOneBitmap.Lock();
cameraOneBitmap.AddDirtyRect(new Int32Rect(0, 0, cameraOneBitmap.PixelWidth, cameraOneBitmap.PixelHeight));
cameraOneBitmap.Unlock();
cameraOneImage.Source = cameraOneBitmap;
The Problem: The method feeds me a bitmap that isn't the correct angle and i have no way of changing that. I must rotate it. I'm currently using a render transform in xaml. the problem is it shapes the image all weird in certain window sizes it hangs over the grid into the bottom of the window so i don't want to use that. I've tried using writeablebitmapex library but it creates a new bitmap and that gives me an out of memory exception in about 10 seconds... Is there a way to rotate this bitmap with out have to make a new one every time? Somehow the render transform does it without giving me problems. I was doing this to set the source but it still gives me an exception because it makes a new one.
public static RenderTargetBitmap RotateImage(double angle, WriteableBitmap sourceBitmap)
{
TransformedBitmap tb = new TransformedBitmap(sourceBitmap, new RotateTransform(angle));
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
drawingContext.DrawImage(tb, new Rect(0, 0, tb.PixelWidth, tb.PixelHeight));
//drawingContext.PushTransform(new RotateTransform(270, .5, .5));
drawingContext.Close();
System.Windows.Media.Imaging.RenderTargetBitmap bmp = new System.Windows.Media.Imaging.RenderTargetBitmap(tb.PixelWidth, tb.PixelHeight, 96, 96, PixelFormats.Pbgra32);
bmp.Render(drawingVisual);
return bmp;
}

Create WriteableBitmap from UIControl WPF

I am currently converting a Silverlight application into WPF. In my silverlight application I have the code
WriteableBitmap sceneBitmap = new WriteableBitmap(scene, new TranslateTransform() { Y = 10 });
WriteableBitmap newone = TimelineMainHelper.CropImage(sceneBitmap, 0, 0, sceneBitmap.PixelWidth, sceneBitmap.PixelHeight - 25);
newone.Invalidate();
img.Source = newone;
Where scene is a control.
When putting this into WPF there are no overloads for the writeablebitmap class which take UIElement and Transform as the parameters. Firstly I was wondering why this is? and secondly I was wondering if there was a way getting a control to a writeablebitmap
Instead you will want to use RenderTargetBitmap and CroppedBitmap I believe:
RenderTargetBitmap rtb = new RenderTargetBitmap((int)scene.ActualWidth, (int)scene.ActualHeight, 96, 96, System.Windows.Media.PixelFormats.Pbgra32);
rtb.Render(this.sceneBitmap);
CroppedBitmap crop = new CroppedBitmap(sceneBitmap, new Int32Rect(0, 0, (int)sceneBitmap.ActualWidth, (int)sceneBitmap.ActualHeight));
Then you can do something like:
System.Windows.Controls.Image img = new Image();
img.Source = crop;
And go from there.
Disclaimer:
You may need to use different overloads and what not to do exactly what you wish. I just took a shot guessing what parameters to pass given your snippet.

WriteableBitmap crashes program with no message?

I create a WriteableBitmap object, draw a line and try to set it as the source to an Image control. For some reason, the program stops responding and then closes 5 seconds later when I try to set the Source. Anyone have any idea what's wrong? (I am also using WriteableBitmapEx)
WriteableBitmap bit = new WriteableBitmap(400, 400, 96, 96, PixelFormats.Bgr32, null);
WriteableBitmapExtensions.DrawLine(bit, 10, 10, 300, 300, Core.PrimaryColor.ColorValue);
ImageCanvas.Source = bit; // Sets the image to our bitmap, but program crashes for some reason!
When I try your code, it throws an ArgumentException saying
The input WriteableBitmap needs to have the Pbgra32 pixel format. Use
the BitmapFactory.ConvertToPbgra32Format method to automatically
convert any input BitmapSource to the right format accepted by this
class.\r\nParametername: writeableBitmap
Hence this works:
var bitmap = new WriteableBitmap(400, 400, 96, 96, PixelFormats.Pbgra32, null);
WriteableBitmapExtensions.DrawLine(bitmap, 10, 10, 300, 300, Colors.Black);
image.Source = bitmap;
UPDATE: As noted by Anders, you should perhaps use the portable bitmap factory method provided by WriteableBitmapEx to create your bitmap:
var bitmap = BitmapFactory.New(400, 400);
WriteableBitmapExtensions.DrawLine(bitmap, 10, 10, 300, 300, Colors.Black);
image.Source = bitmap;

Get images from DrawingGroup

Maybe it's a stupid question, but I have some problems with finding the proper answer:S
How to get frames as Bitmap's or Image's (or something similar) from DrawingGroup? I don't actually know how to bite it. I tried to look for it in the Internet, but had problems with finding something useful.
If you need an image to be used as the Source of an Image control, you could simply put the drawing into a DrawingImage:
var drawing = ...
var drawingImage = new DrawingImage(drawing);
image.Source = drawingImage;
If the question is about creating a BitmapSource (i.e. something that can be encoded by a BitmapEncoder via a BitmapFrame), there is no direct conversion. You have to put the image into an intermediate Image control and render that control into a RenderTargetBitmap, which is a BitmapSource:
var drawing = ...
var drawingImage = new DrawingImage(drawing);
var image = new Image { Source = drawingImage };
var bitmap = new RenderTargetBitmap(100, 100, 96, 96, PixelFormats.Pbgra32);
image.Arrange(new Rect(0, 0, bitmap.Width, bitmap.Height));
bitmap.Render(image);

Categories

Resources