Reputation: 800
I have an ItemsControl
which contains a Canvas
(800x800px) and a collection of Rectangles
at certain coordinates.
I can save the ItemsControl
as a RenderTargetBitmap
which is fine, but I need to crop it at a specified X,Y,W,H and then save it which I can't seem to figure out how to do.
I've tried clipping the Canvas
using Canvas.Clip
and then saving it afterwards but that makes my Rectangles
move out of their specified coordinates (CollageX, CollageY), so the Canvas needs to be 800x800px.
EDIT: Or is there some way to Clip
a canvas without it affecting the X and Y positions of its child elements?
Here's what my current code looks like.
C#
private async void SaveDesignBtn_Tapped(object sender, TappedRoutedEventArgs e)
{
//Images
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(MaskArea, (int)PrintW, (int)PrintH);
var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
var pixels = pixelBuffer.ToArray();
var displayInformation = DisplayInformation.GetForCurrentView();
var file = await ApplicationData.Current.LocalFolder.CreateFileAsync("Canvas1" + ".png", CreationCollisionOption.ReplaceExisting);
using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied, (uint)renderTargetBitmap.PixelWidth, (uint)renderTargetBitmap.PixelHeight, displayInformation.RawDpiX, displayInformation.RawDpiY, pixels);
await encoder.FlushAsync();
}
}
XAML
<ItemsControl Name="MaskArea" ItemsSource="{Binding Path=CollageGrid}" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,0,0,0" Width="800" Height="800">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas x:Name="CollageArea"
Background="Transparent"
Width="800"
Height="800"
HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,0,0,0">
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="local:CollageGrid">
<Rectangle Name="MaskBounds" Width="{Binding CollageW}" Height="{Binding CollageH}" AllowDrop="True" CanDrag="True"
Drop="Mask_Drop"
DragOver="Mask_DragOver"
ManipulationMode="All" Stroke="Black" StrokeThickness="2" DragEnter="Mask_DragEnter" DragLeave="Mask_DragLeave" Tapped="Tap_Collage"
RenderTransformOrigin="0.5, 0.5"
Canvas.Left="{Binding CollageX}" Canvas.Top="{Binding CollageY}" Fill="Transparent">
<Rectangle.RenderTransform>
<TranslateTransform X="{Binding CollageX}" Y="{Binding CollageY}"/>
</Rectangle.RenderTransform>
</Rectangle>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Upvotes: 1
Views: 1244
Reputation: 462
ok, so i am not sure if this helps, but people looking up how to crop an image will sure enjoy this answer as its really clean and fast.
private async void GetCanvasBitmapRegion(Rect RegionToCopy)
{
try
{
CanvasDevice Cdevice = CanvasDevice.GetSharedDevice();
var croppedwidth = (int)RegionToCopy.Width;
var croppedheight = (int)RegionToCopy.Height;
//create a new empty image that has the same size as the desired crop region
var softwareBitmap = new SoftwareBitmap(BitmapPixelFormat.Bgra8, croppedwidth, croppedheight,
BitmapAlphaMode.Premultiplied);
//based on this empty software bitmap we create a new CanvasBitmap
var croppedimage = CanvasBitmap.CreateFromSoftwareBitmap(Cdevice, softwareBitmap);
// this is the image we want to crop from, CanvasBitmap has lots of static initializers that like CanvasBitmap.LoadAsync
//or CanvasBitmap.CreateFromBytes
CanvasBitmap initialimage = _image;
if (initialimage != null)
{
//this function does the cropped region copy.
croppedimage.CopyPixelsFromBitmap(_image, 0, 0, (int)RegionToCopy.Left, (int)RegionToCopy.Top, (int)RegionToCopy.Width, (int)RegionToCopy.Height);
//you can now do whatever you like with croppedimage, including using its .SaveAsync or replace the old one with it.
}
}
catch (Exception Ex)
{
}
}
Upvotes: 0
Reputation: 21919
Don't clip it before you save: clip it when you save.
The BitmapEncoder has a BitmapTransform property which you can use to control how it is encoded, including scaling, flipping, rotating, and clipping.
Upvotes: 1