While Rendering Canvas control in Png I lost the background image - c#

My application is a windows 8 store app . It takes a photo with the camera, then i draw over the image, and i want to save both the image and the drawing. What i have come result is only the drawing. i lost the background image.
Below you have my implementation :
XAML code:
(in place of having an Image control for the photo taken and a canvas for the drawing, i binded the photo = CurrentPicture as the background of the canvas)
<Canvas Grid.Row="1"
Grid.Column="0"
x:Name="InkCanvas"
Background="{Binding CurrentPicture, Converter={StaticResource WPhotoToCanvasBackgroundConverter}}"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="0"
Width="1024"
Height="768" />
C# :
private async Task<IPhoto> RenderCanvasToPNG()
{
MemoryStream stream = await WriteableBitmapRenderExtensions.RenderToPngStream(InkCanvas);
var bitmap = new BitmapImage();
await bitmap.SetSourceAsync(System.IO.WindowsRuntimeStreamExtensions.AsRandomAccessStream(stream));
byte[] byteme = stream.ToArray();
var photo = new WPhotos(null, byteme, bitmap.PixelWidth, bitmap.PixelHeight, bitmap);
return photo;
}
Thank you a lot for your time :)

There isn't a direct way to extract the pixels from a BitmapImage or ImageBrush. I believe WriteableBitmapEx fakes this by finding the image's source URI and looking that up, but this method works only if the image was loaded from a URI. If it was streamed into the image then there is no way to extract it.
Instead, you can use RenderTargetBitmap to render your UIElements to a bitmap. Since this uses the Xaml rendering engine it has access to the ImageBrush used for the Canvas' background and should completely render the Canvas and its contents (barring non-renderable contents such as a MediaElement or SwapChainPanel).

Related

No bitmapimage in uwp?

I need to enter an image source from the code in C#. In my previous projects (not in uwp) I would do the following:
imagename.Source=new BitmapImage(new Uri(stringPath));
but in UWP the BitmapImage class seems not to exist.
Is there something similar to use or any solution for this problem?
MSDN reckons BitmapImage is still a thing.
See here: MSDN help document
Its usage is a little different though:
<Image Loaded="Image_Loaded"/>
And the C#:
void Image_Loaded(object sender, RoutedEventArgs e)
{
Image img = sender as Image;
BitmapImage bitmapImage = new BitmapImage();
img.Width = bitmapImage.DecodePixelWidth = 80;
// Natural px width of image source.
// You don't need to set Height; the system maintains aspect ratio, and calculates the other
// dimension, as long as one dimension measurement is provided.
bitmapImage.UriSource = new Uri(img.BaseUri,"Images/myimage.png");
}
There is a BitmapImage API within UWP. Microsoft has a guide for its use too.
This is the code sample taken directly from the guide for the C# segment:
// Create Image Element
Image myImage = new Image();
myImage.Width = 200;
// Create source
BitmapImage myBitmapImage = new BitmapImage();
// BitmapImage.UriSource must be in a BeginInit/EndInit block
myBitmapImage.BeginInit();
myBitmapImage.UriSource = new Uri(#"C:\Documents and Settings\All Users\Documents\My Pictures\Sample Pictures\Water Lilies.jpg");
// To save significant application memory, set the DecodePixelWidth or
// DecodePixelHeight of the BitmapImage value of the image source to the desired
// height or width of the rendered image. If you don't do this, the application will
// cache the image as though it were rendered as its normal size rather then just
// the size that is displayed.
// Note: In order to preserve aspect ratio, set DecodePixelWidth
// or DecodePixelHeight but not both.
myBitmapImage.DecodePixelWidth = 200;
myBitmapImage.EndInit();
//set image source
myImage.Source = myBitmapImage;
And this is the XAML segment:
<!-- Simple image rendering. However, rendering an image this way may not
result in the best use of application memory. See markup below which
creates the same end result but using less memory. -->
<Image Width="200"
Source="C:\Documents and Settings\All Users\Documents\My Pictures\Sample Pictures\Water Lilies.jpg"/>
<Image Width="200">
<Image.Source>
<!-- To save significant application memory, set the DecodePixelWidth or
DecodePixelHeight of the BitmapImage value of the image source to the desired
height and width of the rendered image. If you don't do this, the application will
cache the image as though it were rendered as its normal size rather then just
the size that is displayed. -->
<!-- Note: In order to preserve aspect ratio, only set either DecodePixelWidth
or DecodePixelHeight but not both. -->
<BitmapImage DecodePixelWidth="200"
UriSource="C:\Documents and Settings\All Users\Documents\My Pictures\Sample Pictures\Water Lilies.jpg" />
</Image.Source>
</Image>
Especially if you come from WPF you have to add the using directive
using Windows.UI.Xaml.Media.Imaging;
What was next in going from WPF to UWP is the image source string. It needs the absolute path:
imagename.UriSource = new Uri("ms-appx:/your_path");

How to blur for background of grid on uwp?

grid background="white"
Now, I want to blur it that such as blur on ios.
Use Blur by UWPCommunityToolkit.
<Grid>
<Grid>
<interactivity:Interaction.Behaviors>
<behaviors:Blur x:Name="BlurBehavior" Value="25" Duration="0"
Delay="0" AutomaticallyStart="True"/>
</interactivity:Interaction.Behaviors>
</Grid>
<Grid>
<!-- Your Content -->
</Grid>
</Grid>
If you want to increase or decrease the amount of blur then change the value in behaviours.
If you want any code sample, check out this GitHub project.
UWP Hamburger Menu with Frosted glass effect and Swipe to Open/Close.
Opacity is not a blur effect.
To make a pure blur effect, you will can use the RendertargetBitmap or Win2D.
I prefere to use Win2D because the gaussian blur effect is explicit and can be more precisely configured :
using (var stream = await Content.RenderToRandomAccessStream())
{
var device = new CanvasDevice();
var bitmap = await CanvasBitmap.LoadAsync(device, stream);
var renderer = new CanvasRenderTarget(device,
bitmap.SizeInPixels.Width,
bitmap.SizeInPixels.Height, bitmap.Dpi);
using (var ds = renderer.CreateDrawingSession())
{
var blur = new GaussianBlurEffect();
blur.BlurAmount = 5.0f;
blur.Source = bitmap;
ds.DrawImage(blur);
}
stream.Seek(0);
await renderer.SaveAsync(stream, CanvasBitmapFileFormat.Png);
BitmapImage image = new BitmapImage();
image.SetSource(stream);
paneBackground.ImageSource = image;
}
If you want to read more about it, here is the MSDN page.
You can apply a blur using the Composition APIs with the Windows 10 Anniversary update. However, if you're trying to blur things that are behind the window or app, that won't be possible. On the other hand, if you have something like a picture behind your grid and want the picture be blurred then this will work.
I wrote an answer to a similar question here.

When reading from a file stream image get flipped -90

I'm trying to load an image in a local path to a Silverlight image control. This is an out of browser application. When I load the image using a stream it's always flipped upside down.
Any idea why? This happens for large images only.
FileName here gives the full path to local file system, like C:\imageFullPath\image.jpg.
Please help. Following is the code.
------ In Model side------------------------
public BitmapImage DisplayImage
{
get
{
if (!string.IsNullOrWhiteSpace(FileName))
{
var b = new BitmapImage();
b.SetSource(System.IO.File.OpenRead(FileName));
return b;
}
return null;
}
}
------ In Silverlight View side------------------------
<Image Source="{Binding DisplayImage, Mode=TwoWay}" Width="450" Height="250" Margin="0,0,0,0"/>
What i see when debugging
BMP are normally stored "upside-down" with the pixels in reverse order from bottom to top, but can use a negative height in the file header to indicate the image is stored top-to-bottom, so perhaps you have such an image.
Does this happen with all images, or just that one?
You could try changing the way the image is loaded, using a Uri in the constructor instead of calling SetSource() with a Stream, as it may account for the header and read the file differently:
var b = new BitmapImage(new Uri(FileName));
return b;
Or, if that doesn't help, you can apply a transform to flip every image, but that doesn't solve the underlying problem:
<Image Source="{Binding DisplayImage, Mode=TwoWay}" Width="450" Height="250" Margin="0,0,0,0">
<Image.RenderTransform>
<ScaleTransform ScaleY="-1" />
</Image.RenderTransform>
</Image>

Saving Bitmap Moves The Canvas

I'm trying to save a canvas drawing as a bitmap. The code works fine, however once the drawing has been saved the canvas moves to the top left of the parent application. My code is as follows:
public void SaveBitmap()
{
Size size = new Size(canvas.ActualWidth, canvas.ActualHeight);
canvas.Measure(size);
canvas.Arrange(new Rect(size));
RenderTargetBitmap renderBitmap =
new RenderTargetBitmap(
(int)size.Width,
(int)size.Height,
96d,
96d,
PixelFormats.Pbgra32);
renderBitmap.Render(canvas);
using (FileStream outStream = new FileStream("C:\\Users\\Darren\\Desktop\\test.bmp", FileMode.Create))
{
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
encoder.Save(outStream);
}
}
The line that caused the problem is canvas.Arrange. Anybody shed any light?
Thanks.
The reason is that you’re not specifying any position in your Rect constructor, which therefore defaults to a position of (0,0).
My suggestion for using RenderTargetBitmap is to place your Canvas inside a Grid, and then perform any explicit positioning required by your UI on this outer Grid, letting your inner Canvas naturally assume a position of (0,0) within this parent Grid.
For example, if you have:
<Window>
<Canvas Left="10" Top="30" />
</Window>
Change it to:
<Window>
<Grid Left="10" Top="30">
<Canvas />
</Grid>
</Window>
Then, you could eliminate your calls to Measure and Arrange altogether. However, make sure that you still pass the child Canvas to your RenderTargetBitmap.Render method, not the parent Grid.

Taking bitmap of Canvas is incorrectly based on top left corner of Window

I have a canvas in my Window and occasionally I want to take snapshots of the content.
I have the following method to do so:
private PngBitmapEncoder captureVisual(Visual v)
{
RenderTargetBitmap bmp = new RenderTargetBitmap(546, 410, 120, 96, PixelFormats.Pbgra32);
bmp.Render(v);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Interlace = PngInterlaceOption.On;
encoder.Frames.Add(BitmapFrame.Create(bmp));
return encoder;
}
I call this method with the following method which is called by a press button action(the idea is to add the picture to another canvas which will display the "photo":
private void take_photo(Object sender, RoutedEventArgs e)
{
System.Windows.Controls.Image photoImg = new System.Windows.Controls.Image();
BitmapEncoder enc = captureVisual(videoCanvas);
photoImg.Source = enc.Frames[0];
photoCanvas.Children.Add(photoImg);
}
The problem:
When I take the photo the origin of the photo/bitmap is not the origin of the canvas but the origin of the window. So the Canvas appears in the bitmap translated towards bottom/right in the same position as it is in relation to the top-left corner of the window. I have no idea why this is happening.
As an example see the pic below: There is white space to the top left and the actual content is translated to the bottom right. The origin should be where the actual image is located. I will try to put around a border to make it easier to visualize the problem(sorry I don't know how to put a border around the image if anyone knows please tell me or edit it yourself. Thanks).
Thanks to the comment of dowhilefor I got the answer from this link:
The problem is WPF implicitly adds the margins of the Canvas in relation to the parent container. In my case the parent container was a Grid and I didn't define any margins, the canvas was filling a specific cell. Nevertheless this somehow gets incorporated in the bitmap.
The solution, wrap the Canvas around another Canvas. That's stupid but it works. IMHO this is a bug in WPF:
<Canvas
Name="outerCanvas"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Grid.Row="1" Grid.Column="1">
<Canvas
Name="videoCanvas"
Canvas.Left="0"
Canvas.Top="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
/>
</Canvas>

Categories

Resources