How to share a screenshot? - c#

I want to share the screenshot of the app on Twitter, Facebook, etc. This is my code: it saves the picture, but doesn't open the share media task. I know the problem is in the path :{
var wb = new WriteableBitmap(LayoutRoot, new TranslateTransform());
using (var mediaLibrary = new MediaLibrary()) {
using (var stream = new MemoryStream()) {
var fileName = string.Format("{0}.jpg", DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss"));
wb.SaveJpeg(stream, wb.PixelWidth, wb.PixelHeight, 0, 100);
stream.Seek(0, SeekOrigin.Begin);
mediaLibrary.SavePicture(fileName, stream);
shareMediaTask = new ShareMediaTask();
shareMediaTask.FilePath = fileName;
shareMediaTask.Show();
}
}
How can I get the saved picture's path?
Isn't it possible to just simply take a screenshot and share it without saving it on the phone?

To get the real path for the MediaLibrary file, you'll need to use the GetPath() extension method, something like;
using Microsoft.Xna.Framework.Media.PhoneExtensions;
...
var picture = mediaLibrary.SavePicture(fileName, stream);
shareMediaTask = new ShareMediaTask();
shareMediaTask.FilePath = picture.GetPath();
shareMediaTask.Show();

For sharing the screen shot it is not required to save the image , in windows 8.1 it is very easy.
Here is the code, enjoy!
async void dataTransferMgr_DataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
DataRequest request = args.Request;
request.Data.Properties.Title = "Title";
request.Data.Properties.Description = "brief description";
request.Data.SetText("detailed information");
RandomAccessStreamReference imageStreamRef = await ScreenshotToStreamReferenceAsync(yourChartControlName);
request.Data.Properties.Thumbnail = imageStreamRef;
request.Data.SetBitmap(imageStreamRef);
}
private async Task ScreenshotToStreamAsync(FrameworkElement element, IRandomAccessStream stream)
{
var renderTargetBitmap = new Windows.UI.Xaml.Media.Imaging.RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(element);
var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
var dpi = Windows.Graphics.Display.DisplayInformation.GetForCurrentView().LogicalDpi;
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)renderTargetBitmap.PixelWidth,
(uint)renderTargetBitmap.PixelHeight,
dpi,
dpi,
pixelBuffer.ToArray());
await encoder.FlushAsync();
}
private async Task<RandomAccessStreamReference> ScreenshotToStreamReferenceAsync(FrameworkElement element)
{
var ms = new InMemoryRandomAccessStream();
await ScreenshotToStreamAsync(element, ms);
ms.Seek(0);
return RandomAccessStreamReference.CreateFromStream(ms);
}

Related

how to convert StorageFile (png image) to transparent PNG Bitmap in c#?

I am making a UWP app where i want to pick a user signature scanned by the user and make the picture transparent.
now first things first:
I am using FileOpenPicker to pick the storage file.
Work tried by me
public async void Button_AddSign_Click(object sender, RoutedEventArgs e)
{
try
{
var _filePicker = new FileOpenPicker();
_filePicker.SuggestedStartLocation = PickerLocationId.Desktop;
_filePicker.ViewMode = PickerViewMode.Thumbnail;
_filePicker.FileTypeFilter.Add(".png");
IStorageFile _file = await _filePicker.PickSingleFileAsync();
StorageFolder storageFolder = await ApplicationData.Current.LocalFolder.GetFolderAsync(CurrentUser);
if (_file != null)
{
StorageFile storageFile = await _file.CopyAsync(storageFolder, "Signature.png");
await MakeSignTransparentAsync(storageFile);
}
}
catch{Exception ex}
}
public static async Task MakeSignTransparentAsync(StorageFile Inputfile)
{
var memStream = new InMemoryRandomAccessStream();
using (IRandomAccessStream fileStream = await Inputfile.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream);
BitmapEncoder encoder = await BitmapEncoder.CreateForTranscodingAsync(memStream, decoder);
encoder.BitmapTransform.ScaledWidth = 600;
encoder.BitmapTransform.ScaledHeight = 200;
await encoder.FlushAsync();
memStream.Seek(0);
fileStream.Seek(0);
fileStream.Size = 0;
await RandomAccessStream.CopyAsync(memStream, fileStream);
memStream.Dispose();
}
Bitmap bmp;
using (MemoryStream ms = new MemoryStream(memStream)) //Getting an error at this line
{
bmp = new Bitmap(ms);
}
bmp.MakeTransparent();
bmp.Save(bmpInput.Path + "test.png", ImageFormat.Png);
}
Error:
Argument 1: cannot convert from 'Windows.Storage.Streams.InMemoryRandomAccessStream' to 'byte[]
Any help is appreciated.
If there is another way around other than this that is also appreciated.
Found a solution using a library ImageMagick
using ImageMagick;
public static async Task MakeSignTransparentAsync(StorageFile bmpInput)
{
using (var img = new MagickImage(bmpInput.Path))
{
// -fuzz XX%
img.ColorFuzz = new Percentage(10);
// -transparent white
img.Transparent(MagickColors.White);
img.Write(bmpInput.Path);
}
}

Save Photo in media library windows phone 8.1

I'm getting photo path from a list view and showing image in detail screen.
Detail page Code is here.
//Imaged is my image control in Xaml.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var imagePath = e.Parameter as string;
imaged.Source = new BitmapImage(new Uri(imagePath, UriKind.RelativeOrAbsolute));
var imgsource = imaged.Source;
}
I want to save this picture in media Library, by clicking save button event.
Here is my Save button event code.
private async void ApplicationBarIconButton_Click_SaveToPictures(object sender, RoutedEventArgs e)
{
FileSavePicker picker = new FileSavePicker();
// picker.FileTypeChoices.Add("PNG File", new List<string>() { ".png" });
picker.FileTypeChoices.Add("JPEG image", new string[] { ".jpg" });
picker.FileTypeChoices.Add("PNG image", new string[] { ".png" });
picker.FileTypeChoices.Add("BMP image", new string[] { ".bmp" });
picker.DefaultFileExtension = ".png";
picker.SuggestedFileName = "bomdiaimg";
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
StorageFile file = await picker.PickSaveFileAsync();
// StorageFile file = await picker.PickSaveFileAndContinue();
if (file != null)
{
RenderTargetBitmap renderTargetBitMap = new RenderTargetBitmap();
await renderTargetBitMap.RenderAsync(imaged, (int)imaged.Width, (int)imaged.Height);
var pixels = await renderTargetBitMap.GetPixelsAsync();
using (IRandomAccessStream randomAccessStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, randomAccessStream);
byte[] bytes = pixels.ToArray();
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)renderTargetBitMap.PixelWidth, (uint)renderTargetBitMap.PixelHeight, 96, 96, bytes); await encoder.FlushAsync();
}
}
}
I'm not able to save picture the error is that
Here the error is an exception.
StorageFile file = await picker.PickSaveFileAsync();
SOme times green line under this method "which shows that use picksavefile and continue" But when I use this method then error display. not able to understand this issue. how can I save my picture in media library
The SaveJpeg method is an extension method from the namespace System.Windows.Media.Imaging.Extensions. Add a using at the top of the source file:
using System.Windows.Media.Imaging.Extensions;
And, possibly you meant to use System.Windows.Media.Imaging.WriteableBitmap instead of Windows.UI.Xaml.Media.Imaging.WriteableBitmap?
You maybe want use RenderTargetBitMap for save control image. Please check this example code.
FileSavePicker picker = new FileSavePicker();
picker.FileTypeChoices.Add("JPG File", new List<string>() { ".jpg" });
StorageFile file = await picker.PickSaveFileAsync(); if (file != null)
{
RenderTargetBitmap renderTargetBitMap = new RenderTargetBitmap();
//With this method we can make our XAML elements in an image. await
renderTargetBitMap.RenderAsync(grdRender, (int)grdRender.Width, (int)grdRender.Height);
var pixels = await renderTargetBitMap.GetPixelsAsync();
using (IRandomAccessStream randomAccessStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, randomAccessStream);
byte[] bytes = pixels.ToArray();
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)renderTargetBitMap.PixelWidth, (uint)renderTargetBitMap.PixelHeight, 96, 96, bytes); await encoder.FlushAsync();
}
}

WriteableBitmap SaveJpeg missing for universal apps

I am developing an universal app, in my shared code i am trying to download the image from net and save the image to LocalFolder.
I am using HttpClient to download the images from user given urls and reading the client response to save the image. I am using below code to save, but couldn't able to find Writeable SaveJpeg method.
HttpResponseMessage response = await httpClient.GetAsync(imageUri);
await Task.Run(async () =>
{
if (response.IsSuccessStatusCode)
{
// save image locally
StorageFolder folder = await ApplicationData.Current.LocalFolder.CreateFolderAsync("Images", CreationCollisionOption.OpenIfExists);
BitmapImage bmp = new BitmapImage();
var buffer = await response.Content.ReadAsBufferAsync();
InMemoryRandomAccessStream ras = new InMemoryRandomAccessStream();
DataWriter writer = new DataWriter(ras.GetOutputStreamAt(0));
writer.WriteBuffer(buffer);
bmp.SetSource(ras);
}
});
What is the best way to save the imageresponse to localfolder with image quality % (for both WP and Windows).
You should save the stream directly instead of saving the BitmapImage.
Something like this.
var ras = new InMemoryRandomAccessStream();
var writer = new DataWriter(ras);
writer.WriteBuffer(buffer);
await writer.StoreAsync();
var inputStream = ras.GetInputStreamAt(0);
// you can still use this to display it on the UI though
//bmp.SetSource(ras);
// write the picture into this folder
var storageFile = await folder.CreateFileAsync("image1.jpg", CreationCollisionOption.GenerateUniqueName);
using (var storageStream = await storageFile.OpenAsync(FileAccessMode.ReadWrite))
{
await RandomAccessStream.CopyAndCloseAsync(inputStream, storageStream.GetOutputStreamAt(0));
}
Update
You can use BitmapEncoder and when pass in property dpi values in SetPixelData.
using (var storageStream = await storageFile.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, storageStream);
var pixelStream = yourWriteableBitmap.PixelBuffer.AsStream();
var pixels = new byte[pixelStream.Length];
await pixelStream.ReadAsync(pixels, 0, pixels.Length);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)yourWriteableBitmap.PixelWidth, (uint)yourWriteableBitmap.PixelHeight, 48, 48, pixels);
await encoder.FlushAsync();
}

Render XAML tree to an image and save it using FileSavePicker

I'm working on WinRT app and for some reason, I want to save XAML tree as image using FileSavePicker. Currently I'm saving the image inside ApplicationData which is quite hectic to browse to afterwards. What I want is, user picks directory of their own choice and name and save the image. I'm using following code right now :
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(MainGrid);
var file = await ApplicationData.Current.LocalFolder.CreateFileAsync("Image.png", creationCollisionOption.ReplaceExisting);
var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)renderTargetBitmap.PixelWidth,
(uint)renderTargetBitmap.PixelHeight, 96d, 96d,
pixelBuffer.ToArray());
await encoder.FlushAsync();
}
Change your code like this
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(MainGrid);
var file = await DestinationFileFromUserAsync();
if (file != null)
{
var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)renderTargetBitmap.PixelWidth,
(uint)renderTargetBitmap.PixelHeight, 96d, 96d,
pixelBuffer.ToArray());
await encoder.FlushAsync();
}
}
private async Task<StorageFile> DestinationFileFromUserAsync()
{
if (EnsureUnsnapped())
{
StorageFile file = null;
FileSavePicker savePicker = new FileSavePicker();
savePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
savePicker.FileTypeChoices.Add("Images", new List<string>() { ".jpg", ".jpeg", ".png"});
savePicker.SuggestedFileName = "New Image";
file = await savePicker.PickSaveFileAsync();
return file;
}
else
{
return null;
}
}
internal bool EnsureUnsnapped()
{
// FilePicker APIs will not work if the application is in a snapped state.
// If an app wants to show a FilePicker while snapped, it must attempt to unsnap first
return ((ApplicationView.Value != ApplicationViewState.Snapped) || ApplicationView.TryUnsnap());
}
Don't forget to check out FileSavePicker class on MSDN

Rotating images in WinRT

I have a Windows 8 app in which I want to rotate an image file.
In shot, I want to open an image file, rotate it and save the content back to the file.
Is that possible in WinRT? If so, how? Thanks.
Update:
Base on Vasile's answer, I could do some work on this. However I'm not sure what to do next:
public static async Task RotateImage(StorageFile file)
{
if (file == null)
return;
var data = await FileIO.ReadBufferAsync(file);
// create a stream from the file
var ms = new InMemoryRandomAccessStream();
var dw = new DataWriter(ms);
dw.WriteBuffer(data);
await dw.StoreAsync();
ms.Seek(0);
// find out how big the image is, don't need this if you already know
var bm = new BitmapImage();
await bm.SetSourceAsync(ms);
// create a writable bitmap of the right size
var wb = new WriteableBitmap(bm.PixelWidth, bm.PixelHeight);
ms.Seek(0);
// load the writable bitpamp from the stream
await wb.SetSourceAsync(ms);
wb.Rotate(90);
//How should I save the image to the file now?
}
Ofcourse it is possible. You can do it yourself with a pixel manipulation and create a new WriteableBitmapObject or, you could reuse the already implemented functionality from the WriteableBitmapEx (WriteableBitmap Extensions). You can get it via NuGet.
Here you can find a description of the implemented functionality which it offers, and few short samples.
Use this to save WriteableBitmap to StorageFile
private async Task<StorageFile> WriteableBitmapToStorageFile(WriteableBitmap writeableBitmap)
{
var picker = new FileSavePicker();
picker.FileTypeChoices.Add("JPEG Image", new string[] { ".jpg" });
StorageFile file = await picker.PickSaveFileAsync();
if (file != null && writeableBitmap != null)
{
using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(
BitmapEncoder.JpegEncoderId, stream);
Stream pixelStream = writeableBitmap.PixelBuffer.AsStream();
byte[] pixels = new byte[pixelStream.Length];
await pixelStream.ReadAsync(pixels, 0, pixels.Length);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore,
(uint)writeableBitmap.PixelWidth, (uint)writeableBitmap.PixelHeight, 96.0, 96.0, pixels);
await encoder.FlushAsync();
}
return file;
}
else
{
return null;
}
}

Categories