WPF : how to save stroke collection to bitmap? - c#

I use InkCanvas to implement signature function.
after signed, I can use RenderTargetBitmap class to save the signature-drawing into bitmap.
but RenderTargetBitmap always save InkCanvas itself, means can not save ONLY the signature content.
my question is, how to save StrokeCollection into bitmap?

I think you should use Win2D (Win2D.uwp NuGet package); it is pretty easy.
Here is the code:
async void SaveAsBitmap(object sender, RoutedEventArgs e)
{
//copy from origianl canvas and paste on the new canvas for saving
var strokes = inkCanvas.InkPresenter.StrokeContainer.GetStrokes();
//check if canvas is not empty
if (strokes.Count == 0) return;
//select all the strokes to be copied to the clipboard
foreach (var stroke in strokes)
{
stroke.Selected = true;
}
inkCanvas.InkPresenter.StrokeContainer.CopySelectedToClipboard();
//paste the strokes to a new InkCanvas and move the strokes to the topper left corner
var newCanvas = new InkCanvas();
newCanvas.InkPresenter.StrokeContainer.PasteFromClipboard(new Point(0, 0));
//using Win2D to save ink as png
CanvasDevice device = CanvasDevice.GetSharedDevice();
CanvasRenderTarget renderTarget = new CanvasRenderTarget(device,
(int)inkCanvas.InkPresenter.StrokeContainer.BoundingRect.Width,
(int)inkCanvas.InkPresenter.StrokeContainer.BoundingRect.Height,
96);
using (var ds = renderTarget.CreateDrawingSession())
{
//ds.Clear(Colors.White); //uncomment this line for a white background
ds.DrawInk(newCanvas.InkPresenter.StrokeContainer.GetStrokes());
}
//save file dialog
var savePicker = new Windows.Storage.Pickers.FileSavePicker()
{
SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.DocumentsLibrary
};
savePicker.FileTypeChoices.Add("Image file", new List<string>() { ".jpeg", ".png" });
savePicker.SuggestedFileName = "mysign.png";
var file = await savePicker.PickSaveFileAsync();
if (file != null)
{
using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
await renderTarget.SaveAsync(fileStream, CanvasBitmapFileFormat.Png);
}
}
}

Related

Add Adorner to Image in WPF RichTextBox when loaded

I have a RichTextBox control in an application I am developing which I am using along with a ToolBar to create a rich text editor. One feature I have implemented is the ability for a user to insert an Image, now it worth noting at this point that the output from the RichTextBox is RTF.
When the user inserts the Image I am using the following code to add the image to the Document and then add a ResizeAdorner (example from here RichTextBox Resizing Adorner) to the Image which allows the user to resize. When the user saves and loads the Document the size of the Image is persisted correctly.
private void BtnInsertImage_OnClick(object sender, RoutedEventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Multiselect = false;
ofd.CheckFileExists = true;
ofd.CheckPathExists = true;
ofd.Filter = "Image files (*.png;*.jpg;*.jpeg;*.gif;*.bmp)|*.png;*.jpg;*.jpeg;*.gif;*.bmp";
ofd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
ofd.Title = "Insert Image";
if (ofd.ShowDialog() == true)
{
BitmapImage bitmap = new BitmapImage(new Uri(ofd.FileName, UriKind.RelativeOrAbsolute))
{
CacheOption = BitmapCacheOption.OnLoad
};
Image image = new Image();
image.IsEnabled = true;
image.Source = bitmap;
image.Width = bitmap.Width;
image.Height = bitmap.Height;
image.Loaded += this.ImageOnLoaded;
image.Stretch = Stretch.Uniform;
InlineUIContainer container = new InlineUIContainer(image, this.rtbEditor.Selection.Start);
Paragraph paragraph = new Paragraph(container);
var doc = this.rtbEditor.Document;
doc.Blocks.Add(paragraph);
}
}
private void ImageOnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
var img = sender as Image;
if (img != null)
{
var al = AdornerLayer.GetAdornerLayer(img);
if (al != null)
{
al.Add(new ResizingAdorner(img));
}
}
}
The problem and question is that when the Document is loaded i am unable to figure out how to add the ResizingAdorner to the Images in the document. I am using an attached property to load the document contents, the code below is the part that loads the document:
var stream = new MemoryStream(Encoding.UTF8.GetBytes(GetDocumentXaml(richTextBox)));
var doc = new FlowDocument();
var range = new TextRange(doc.ContentStart, doc.ContentEnd);
range.Load(stream, DataFormats.Xaml);
richTextBox.Document = doc;
Could anyone help with how I can add the ResizingAdorner to any images in the loaded Document please?
So I have worked out a way that I can add the Adorner to the Image in the Document through the SelectionChanged event handler and the following code
var inline = this.rtbEditor.CaretPosition.GetAdjacentElement(LogicalDirection.Forward) as Inline;
if (inline != null)
{
this.AddAdorner(inline.NextInline as InlineUIContainer);
this.AddAdorner(inline.PreviousInline as InlineUIContainer);
}
And this is the AddAdorner method
private void AddAdorner(InlineUIContainer container)
{
if (container != null)
{
var image = container.Child;
if (image != null)
{
var al = AdornerLayer.GetAdornerLayer(image);
if (al != null)
{
var currentAdorners = al.GetAdorners(image);
if (currentAdorners != null)
{
foreach (var adorner in currentAdorners)
{
al.Remove(adorner);
}
}
al.Add(new ResizingAdorner(image));
}
}
}
}
I know this is probably not the most elegant way to achieve this but for me this works so I wanted to post this so that others can choose to use this if appropriate

Take a ScreenShot of my Control - Winform

I want to take a screenshot of my control on Winform. I use this function - find in this site :
public void GetImage()
{
var bm = new Bitmap(display1.Width, display1.Height);
display1.DrawToBitmap(bm, display1.ClientRectangle);
bm.Save(#"c:\whatever.gif", ImageFormat.Gif);
}
But when I'm using it, i have a error about 'System.Runtime.InteropServices.ExternalException' in System.Drawing.dll : A generic error occurred in GDI +.
Do you have any idea aboout that ?
Thanks !
----------------------EDIT---------------------------
Ok I have change my function like this :
public void GetImage()
{
var bm = new Bitmap(display1.Width, display1.Height);
display1.DrawToBitmap(bm, display1.ClientRectangle);
var dlg = new SaveFileDialog { DefaultExt = "png", Filter = "Png Files|*.png" };
var res = dlg.ShowDialog();
if (res == DialogResult.OK) bm.Save(dlg.FileName, ImageFormat.Png);
}
and it's works but I have now an empty picture :/
Try the following:
assuming display1 is a Rectangle that bounds the area of the display you wish to capture.
public void GetImage()
{
Rectangle display1 = this.Bounds; // winforms control bounds
// for full screen use "= Screen.GetBounds(Point.Empty);
var bm = new Bitmap(display1.Width, display1.Height);
//display1.DrawToBitmap(bm, display1.ClientRectangle);
Graphics g = Graphics.FromImage(bm);
g.CopyFromScreen(new Point(display1.Left, display1.Top), Point.Empty, display1.Size);
var dlg = new SaveFileDialog { DefaultExt = "png", Filter = "Png Files|*.png" };
var res = dlg.ShowDialog();
if (res == DialogResult.OK) bm.Save(dlg.FileName, ImageFormat.Png);
}

how save image to folder from Image control Win 8 apps

I have a Image control
<Image Name="img" HorizontalAlignment="Left" Height="400" Margin="499,155,0,0" VerticalAlignment="Top" Width="400"/>
And I capture photo from Camera
private async void TakePhoto_Click(object sender, RoutedEventArgs e)
{
CameraCaptureUI camera = new CameraCaptureUI();
camera.PhotoSettings.CroppedAspectRatio = new Size(4, 3);
var photo = await camera.CaptureFileAsync(CameraCaptureUIMode.Photo);
if (photo != null)
{
BitmapImage image = new BitmapImage();
image.SetSource(await photo.OpenAsync(FileAccessMode.Read));
img.Source = image;
}
}
And now I want to save this image from img control to folder, but I don't know how decode image from img control to StorageFile
private async void SaveFile_Click(object sender, RoutedEventArgs e)
{
FileSavePicker savePicker = new FileSavePicker();
savePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
savePicker.FileTypeChoices.Add("jpeg image", new List<string>() { ".jpeg" });
savePicker.SuggestedFileName = "New picture";
StorageFile ff = await savePicker.PickSaveFileAsync();
if (ff != null)
{
await photo.MoveAndReplaceAsync(ff);
}
}
this is a save method, which i want to save image from Image control
The
var photo = await camera.CaptureFileAsync(CameraCaptureUIMode.Photo); returns a StorageFile. All you have to do is save it to the location you want.
You can accomplish this in may ways.
Example:
StorageFolder localFolder = ApplicationData.Current.LocalFolder; // the app's local storage folder
await photo.MoveAsync(localFolder); //move the file to a new location
2.
//Create a new copy in a new location
await photo.CopyAsync(localFolder);
Note that var photo == StorageFile photo. This means that the after the photo was captured, a copy of it was already saved to a temporary location(The App's TempState directory) on the local storage.

How do I get an image to save after rotation at runtime?

I am working with WPF and I have an application that the user loads an image file into a RichTextBox and they can rotate the image and print it. I am not sure as to why the image after it has been rotated will not print as it is displayed on the screen. Instead it prints the original. I am new to this so any help would be greatly appreciated!
The following is the code for my application. Code when the retrieve file Button is clicked:
private void retrieve_button_Click(object sender, RoutedEventArgs e)
{
//Retrieve the file or image you are looking for
OpenFileDialog of = new OpenFileDialog();
of.Filter = "Formats|*.jpg;*.png;*.bmp;*.gif;*.ico;*.txt|JPG Image|*.jpg|BMP image|*.bmp|PNG image|*.png|GIF Image|*.gif|Icon|*.ico|Text File|*.txt";
var dialogResult = of.ShowDialog();
if (dialogResult == System.Windows.Forms.DialogResult.OK)
{
try
{
System.Windows.Controls.RichTextBox myRTB = new System.Windows.Controls.RichTextBox();
{
Run myRun = new Run();
System.Windows.Controls.Image MyImage = new System.Windows.Controls.Image();
MyImage.Source = new BitmapImage(new Uri(of.FileName, UriKind.RelativeOrAbsolute));
InlineUIContainer MyUI = new InlineUIContainer();
MyUI.Child = MyImage;
rotateright_button.IsEnabled = true;
print_button.IsEnabled = true;
Paragraph paragraph = new Paragraph();
paragraph.Inlines.Add(myRun);
paragraph.Inlines.Add(MyUI);
FlowDocument document = new FlowDocument(paragraph);
richTextBox.Document = document;
}
}
catch (ArgumentException)
{
System.Windows.Forms.MessageBox.Show("Invalid File");
}
}
}
When the rotate right button is clicked the following code is executed:
RotateTransform cwRotateTransform;
private void rotateright_button_Click(object sender, RoutedEventArgs e)
{
richTextBox.LayoutTransform = cwRotateTransform;
if (cwRotateTransform == null)
{
cwRotateTransform = new RotateTransform();
}
if (cwRotateTransform.Angle == 360)
{
cwRotateTransform.Angle = 0;
}
else
{
cwRotateTransform.Angle += 90;
}
}
After the Image has been loaded and rotated the user can use the following code to print:
private void InvokePrint(object sender, RoutedEventArgs e)
{
System.Windows.Controls.PrintDialog printDialog = new System.Windows.Controls.PrintDialog();
if ((bool)printDialog.ShowDialog().GetValueOrDefault())
{
FlowDocument flowDocument = new FlowDocument();
flowDocument = richTextBox.Document;
flowDocument.ColumnWidth = printDialog.PrintableAreaWidth;
flowDocument.PagePadding = new Thickness(65);
IDocumentPaginatorSource iDocPag = flowDocument;
printDialog.PrintDocument(iDocPag.DocumentPaginator, "Print Document");
}
}
Try this (substitute yourImageControl in the first line, specify which RotateFlipType you want and be sure to reference the System.Drawing dll):
System.Drawing.Bitmap bitmap = BitmapSourceToBitmap((BitmapSource)YourImageControl.Source);
bitmap.RotateFlip(System.Drawing.RotateFlipType.Rotate90FlipNone);
public static System.Drawing.Bitmap BitmapSourceToBitmap(BitmapSource bitmapsource)
{
System.Drawing.Bitmap bitmap;
using (MemoryStream outStream = new MemoryStream())
{
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bitmapsource));
enc.Save(outStream);
bitmap = new System.Drawing.Bitmap(outStream);
}
return bitmap;
}
Another option for conversion...
P.S. You would get a better answer in less time if you posted some code and told us more about what you have tried.

Windows 8 c# save a camera's picture on local storage

I'm new to C# and I want to create an application metro who can take picture and save themself in localstorage. I know, i need to use isolated storage but i really don't understand how to use it for image. I saw a lot of examples for string but not for picture.
If anyone know how to do it ? Actually i take a picture and i ask the user to record it where he wants. But I want an auto record after the user take the picture. This my code for the moment :
private async void Camera_Clicked(object sender, TappedRoutedEventArgs e)
{
CameraCaptureUI camera = new CameraCaptureUI();
camera.PhotoSettings.CroppedAspectRatio = new Size(16, 9);
StorageFile photo = await camera.
CaptureFileAsync(CameraCaptureUIMode.Photo);
if (photo != null)
{
BitmapImage bmp = new BitmapImage();
IRandomAccessStream stream = await photo.
OpenAsync(FileAccessMode.Read);
bmp.SetSource(stream);
ImageSource.Source = bmp;
ImageSource.Visibility = Visibility.Visible;
appSettings[photoKey] = photo.Path;
FileSavePicker savePicker = new FileSavePicker();
savePicker.FileTypeChoices.Add
("jpeg image", new List<string>() { ".jpeg" });
savePicker.SuggestedFileName = "New picture";
StorageFile ff = await savePicker.PickSaveFileAsync();
if (ff != null)
{
await photo.MoveAndReplaceAsync(ff);
}
}
}
All what you need to do is to replace File Picker logic with retrieving of StorageFile object in Local folder, for example like this:
private async void Camera_Clicked(object sender, TappedRoutedEventArgs e)
{
CameraCaptureUI camera = new CameraCaptureUI();
camera.PhotoSettings.CroppedAspectRatio = new Size(16, 9);
StorageFile photo = await camera.
CaptureFileAsync(CameraCaptureUIMode.Photo);
if (photo != null)
{
var targetFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("some_file_name.jpg");
if (targetFile != null)
{
await photo.MoveAndReplaceAsync(targetFile);
}
}
}

Categories