I'm creating an application for windows 8 metro, I need to render a framework control into an image and save it to hard disk but do not know how. Can I use SharpDX for this? How can I do? Thanks in advance for the help
justin.m.chase's approach certainly works if you do not mind adding dependencies to SharpDX assemblies. The RenderTargetBitmap class might be a good fit for what you are trying to accomplish.
// Render XAML to bitmap
var bitmap = new RenderTargetBitmap();
await bitmap.RenderAsync(elementToRender);
// get the pixels
IBuffer pixelBuffer = await bitmap.GetPixelsAsync();
byte[] pixels = pixelBuffer.ToArray();
// write the pixels to a InMemoryRandomAccessStream
var stream = new InMemoryRandomAccessStream();
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.BmpEncoderId, stream);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, (uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight, 96, 96, pixels);
await encoder.FlushAsync();
stream.Seek(0);
If you follow through this thread the limitations of Metro and the reasons why it won't work are explained. The essence of it is:
Sorry, but rendering Xaml to an element or capturing a screenshot of
your own app did not make it into the release version. It is by design
that an app cannot capturing a screenshot of another app.
A workaround mentioned is:
What I meant was - you can draw shapes, text and images using
Direct2D. The same shapes that you would otherwise draw with XAML UI.
I did not mean to imply that you can render XAML controls - just that
you can use Direct2D as an alternative to achieve same results albeit
with somewhat more effort.
I apologize that this is not possible. The WritableBitmap class' Render() method is current insufficient to accomplish what you are wanting. For the same reason a screenshot cannot be created at this time. But these are the things that are on the backlog! But, now you know.
Because I think this is a more correct answer I would like to reiterate the comment that Zeeshan made in the original question.
There is a extension method for that in winrt xaml toolkit.
http://winrtxamltoolkit.codeplex.com/.../WriteableBitmapRenderExtensions.cs
Install via nuget:
> Install-Package WinRTXamlToolkit.Composition
Add the using:
using WinRTXamlToolkit.Composition;
Render your xaml:
var bitmap = await element.Render();
Related
I'm developing custom control on .Net MAUI. For my case, I have to update 100's of points at each invalidate. So I'm going for native rendering. Here for Android, I have rendered points on bitmap and rendered the bitmap once and this performance is fine for me and the same had to dine with MU+
I'm new to IOS native's, and I tried to achieve the same as above using ImageContext as below,
UIGraphics.BeginImageContextWithOptions(image.Size, false, 0);
image.Draw(new CGPoint(0, 0));
//Drawn needed shapes here using Image Context
image = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
Finally drawn the stored images to screen. But this doesn't look performance effective on my case.
My case is store the existing rendering to one object and render current points with the existing one. Please suggest if it can be achieved using some cases too..
Does anyone know the solution to layering PNG images for windows UWP app?
While preserving the transparency?
(this solution does not work in UWP application)
Merge two png images with transparency and retain transparency
End goal is to merge the PNG files to an Image object so it can be added to a Grid control.
One possible solution is using Blit method in WriteableBitmapEx. This method copies (blits) the pixels from the WriteableBitmap source to the destination WriteableBitmap (this) and following is a simple sample.
var writeableBmp = new WriteableBitmap(1, 1);
var image1 = await writeableBmp.FromContent(new Uri("ms-appx:///Assets/image1.png"));
var image2 = await writeableBmp.FromContent(new Uri("ms-appx:///Assets/image2.png"));
image1.Blit(new Rect(0, 0, image1.PixelWidth, image1.PixelHeight), image2, new Rect(0, 0, image2.PixelWidth, image2.PixelHeight));
//BlendedImage is a Image control in XAML
BlendedImage.Source = image1;
I think you may use the two image control in Grid in Xaml and both have bind the transparency in viewModel.But I see the link and I also can't use it.May MS change the API.I also interesting in this.
Lumia Imaging SDK doing just what you want. It can blend 2 ore more images together.
You can find sample code here
I tried searching around but I couldn't find an answer to this question: are there performance improvements in using an ImageBrush to fill a rectangle rather than creating a BitmapImage and setting its source property?
I have to render an high number of images (we are trying to push over 5000), and for now I'm creating them this way:
<Image x:Name="img" RenderOptions.BitmapScalingMode="LowQuality"
Source="{Binding Path, Converter={StaticResource StringToImageConverter}, ConverterParameter={StaticResource string}}" >
</ext:IdImage>
and in the converter:
System.Windows.Media.Imaging.BitmapImage image = new System.Windows.Media.Imaging.BitmapImage();
image.BeginInit();
image.UriSource = new Uri(value as String);
image.DecodePixelWidth = int.Parse((String)parameter);
image.CacheOption = System.Windows.Media.Imaging.BitmapCacheOption.OnLoad;
image.EndInit();
return image;
NB: I have to use the converter to set the DecodePixelWidth property.
Using an ImageBrush I could freeze the brush thus, according to what I read, increasing the performance so I was wondering if I should change the way I build the images.
P.S. The Images are not static but are translated around.
I think that the problem is not in the code but in the architecture WPF.
If your problem is performance, for my personal experience developing XAML is necessary that the pc is preferably provided with a dedicated video card. However, many times even in very old pc with windows XP to thin the program I did install the updates direct X library
http://support.microsoft.com/kb/179113/en
XAML is based on directX
Try it and let me know
I am trying to let a user capture an image and add it onto the screen using an Image. However, I also need to resize this image down to about half size due to memory restrictions (12x 5MP images is never good on a phone...)
I am launching the camera task fine and it calls the Completed event. However, when I try and use DecodeJpeg I get a "The parameter is incorrect." exception.
Here is my code for resizing, where mx and my are int for dimensions. I have verified that there is something in the e.ChosenPhoto with a length of about ~5500:
WriteableBitmap bitmap = PictureDecoder.DecodeJpeg(e.ChosenPhoto, mx, my);
Image img = new Image();
img.Source = bitmap;
The first line is where the app crashes. Any ideas?
EDIT:
This also occurs with the result from the PhotoChooserTask....
Try using the System.Windows.Media.Imaging - Extensions.LoadJpeg method instead of PictureDecoder.DecodeJpeg. Also make sure that the stream is positioned at the beginning of the stream. If you have already used the stream you will need to reset it using:
MyImageStream.Seek(0, System.IO.SeekOrigin.Begin)
I had a lot of problems trying to get access to the original image, especially since BitmapImage automatically resizes images over 2000x2000. If you want an image larger than 2000x2000 you have to have access to the original stream and load it into a WriteableBitmap object
If you want to see some more complex image handling code including detecting resolution from image stream using ExifLib and rotating stream using the WriteableBitmap Extensions check out the BarcodeCaptureResult class for the Silverlight ZXing Library.
UPDATE: Since all you want is to resize an image given the e.ChosenPhoto result I pulled the code from The Silverlight ZXing library. This should work:
WriteableBitmap wbBarcodeImage = new WriteableBitmap(mx, my);
Extensions.LoadJpeg(wbBarcodeImage, e.ChosenPhoto);//Load JPEG from stream into our re-sized writeable bitmap
Note that you will need to use the correct height/width ratio, otherwise you will have a black bar at the bottom or side of the image. You can use ExifLib to detect the original image size and use that to scale (see GetWriteableBitmap method in BarcodeCaptureResult linked above)
I've got a situation where I need to resize a large number of images. These images are stored as .jpg files on the file system currently, but I expect to just have byte[] in memory later on in the project. The source image size is variable, but the output should be 3 different predetermined sizes. Aspect ratios should be preserved, padding the original image with white space (ie, a really tall image would be resized to fit within the square target image size, with large areas of white on the left and right).
I initially built the project targeting .NET 2.0, and using System.Drawing classes to perform the load/resize/save. Relevant code includes:
original = Image.FromFile(inputFile); //NOTE: Reused for each of the 3 target sizes
Bitmap resized = new Bitmap(size, size);
//Draw the image to a new image of the intended size
Graphics g = Graphics.FromImage(resized);
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.Clear(Color.White);
g.DrawImage(original, center - width / 2f, center - height / 2f, width, height);
g.Dispose();
//Save the new image to the output path
resized.Save(outputFile, ImageFormat.Jpeg);
I wanted to port this project to .NET 3.5, so tried using the System.Windows.Media classes to perform the same function. I got it working, however performance is terrible; processing time per image is about 50x longer. The vast majority of the time is spent loading the image. Relevant code includes:
BitmapImage original = new BitmapImage(); //Again, reused for each of the 3 target sizes
original.BeginInit();
original.StreamSource = new MemoryStream(imageData); //imageData is a byte[] of the data loaded from a FileStream
original.CreateOptions = BitmapCreateOptions.None;
original.CacheOption = BitmapCacheOption.Default;
original.EndInit(); //Here's where the vast majority of the time is spent
original.Freeze();
// Target Rect for the resize operation
Rect rect = new Rect(center - width / 2d, center - height / 2d, width, height);
// Create a DrawingVisual/Context to render with
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
drawingContext.DrawImage(original, rect);
}
// Use RenderTargetBitmap to resize the original image
RenderTargetBitmap resizedImage = new RenderTargetBitmap(
size, size, // Resized dimensions
96, 96, // Default DPI values
PixelFormats.Default); // Default pixel format
resizedImage.Render(drawingVisual);
// Encode the image using the original format and save the modified image
SaveImageData(resizedImage, outputFile);
Am I doing something wrong here, to take so much time? I've tried just using the constructor on BitmapImage that takes a URI, same performance issue there. Anyone done anything like this before, know if there's a more performance-minded way to do this? Or am I just going to need to use System.Drawing still? Thanks!
And after typing all that up, it occurred to me that I could load the symbols from MS for the System.Windows.Media classes, and step through where it was slow. Immediately found the cause, and the solution. The input images were saved with a color profile, and it was attempting to load that color profile (from the file system) of each image. By switching from BitmapCreateOptions.None to BitmapCreateOptions.IgnoreColorProfile in the code above, it no longer does that, and performs just as fast as System.Drawing did.
Hope this helps anyone else that runs into this problem!
You appear to be doing this the hard way. You can let WPF do the work for you by just setting DecodePixelHeight and DecodePixelWidth. This will cause the resize to happen during the image load:
BitmapImage resizedImage = new BitmapImage
{
StreamSource = new MemoryStream(imageData),
CreateOptions = BitmapCreateOptions.IgnoreColorProfile,
DecodePixelHeight = height,
DecodePixelWidth = width,
}
resizedImage.BeginInit(); // Needed only so we can call EndInit()
resizedImage.EndInit(); // This does the actual loading and resizing
imageSaveImageData(resizedImage, outputFile);
I also included the IgnoreColorProfile solution you found in my code.
Update I reread your question and realized the reason you're using DrawingVisual is that you need whitespace around your image to make it square. DecodePixelHeight and DecodePixelWidth would not accomplish that goal, so my solution does not answer your question.
I will leave my answer here in case someone who just needs a resize without whitespace comes across this question.
I think this from the System.Drawing page on MSDN might be relevant:
The System.Drawing namespace provides access to GDI+ basic graphics functionality. More advanced functionality is provided in the System.Drawing.Drawing2D, System.Drawing.Imaging, and System.Drawing.Text namespaces.
The Graphics class provides methods for drawing to the display device. Classes such as Rectangle and Point encapsulate GDI+ primitives. The Pen class is used to draw lines and curves, while classes derived from the abstract class Brush are used to fill the interiors of shapes.
By using System.Drawing you are closer to the actual basic graphics functionality than if you go via System.Windows.Media which:
Defines objects that enable integration of rich media, including drawings, text, and audio/video content within Windows Presentation Foundation (WPF) applications.
System.Drawing is still supported, so I'd stick with that.
I found an interesting situation in your code. Remove using from following line:
using(DrawingContext drawingContext = drawingVisual.RenderOpen())
I'm not sure why this speed up code, but you can give it a try.