trying to capture screenshot on uwp But some issue is arising,saying
1) writable map doesn't contain a definition for Render.
2) writable map doesn't contain a definition for Save.jpeg
3)Type or namespace media library doesn't found.
any type of help would be appreciated.
Code
private void Download(object sender, TappedRoutedEventArgs e)
{
// Create a WriteableBitmap with height and width same as that of Layoutroot
WriteableBitmap bmp = new WriteableBitmap(480, 696);
//Render the layoutroot element on it
bmp.Render(Scrshot, null);
bmp.Invalidate();
//Save the image to Medialibrary
//create a stream of image
var ms = new MemoryStream();
bmp.SaveJpeg(ms, 480, 696, 0, 100);
ms.Seek(0, SeekOrigin.Begin);
//every path must be unique
var filePath = "myfile" + DateTime.Now.ToString();
//Remember to include Medialib capabilty from WMAppManifest.xml for acessing the Medialibrary
var lib = new MediaLibrary();
lib.SavePicture(filePath, ms);
MessageBox.Show("Saved in your media library!", "Done", MessageBoxButton.OK);
}
Instead of WriteableBitmap use RenderTargetBitmap to create a bitmap representation of a visible UIElement. To save this bitmap as a file you can use this extension method I've created (here's a great example for extension methods):
public static class RenderTargetBitmapExtensions {
public static async Task<StorageFile> ToFile(this RenderTargetBitmap renderTargetBitmap, string filename, StorageFolder folder = null, bool overrideExisting = true) {
if (folder == null) folder = ApplicationData.Current.TemporaryFolder;
try {
byte[] pixels = (await renderTargetBitmap.GetPixelsAsync()).ToArray();
StorageFile outputFile = await folder.CreateFileAsync(filename, overrideExisting ? CreationCollisionOption.ReplaceExisting : CreationCollisionOption.GenerateUnique);
var bitmapEncodingMode = BitmapEncoder.PngEncoderId;
using (var writeStream = await outputFile.OpenAsync(FileAccessMode.ReadWrite)) {
var encoder = await BitmapEncoder.CreateAsync(bitmapEncodingMode, writeStream);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, (uint)renderTargetBitmap.PixelWidth, (uint)renderTargetBitmap.PixelHeight, 96, 96, pixels);
await encoder.FlushAsync();
}
return outputFile;
} catch {
return null;
}
}
}
And finally to get the public Images folder (as MediaLibrary is a Silverlight class and does not exist in UWP anymore) you can do the following according to this thread:
StorageFolder picturesLibrary = KnownFolders.PicturesLibrary;
StorageFolder savedPicturesFolder = await picturesLibrary.CreateFolderAsync("Saved Pictures", CreationCollisionOption.OpenIfExists);
Note: By default, apps do not have access to the Pictures Library. You must add the capability in Package.appxmanifest. Open Package.appxmanifest and click on the Capabilities tab. There is a checkbox for the Pictures Library.
So a whole code to do this should be:
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(LayoutRoot, Convert.ToInt32(LayoutRoot.ActualWidth), Convert.ToInt32(LayoutRoot.ActualHeight));
StorageFolder savedPicturesFolder = await KnownFolders.PicturesLibrary.CreateFolderAsync("Saved Pictures", CreationCollisionOption.OpenIfExists);
await renderTargetBitmap.ToFile("filename.jpg", savedPicturesFolder);
Or if you don't want to override existing files, the last line would be:
await renderTargetBitmap.ToFile("filename.jpg", savedPicturesFolder, false);
For that you can alternatively create a time-based filename:
string filename = String.Format("downloaded_{0}.jpg", DateTime.Now.ToString("yyyyMMdd_HHmmss"));
await renderTargetBitmap.ToFile(filename, savedPicturesFolder, false);
Related
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);
}
}
I'm trying to store a BitmapImage to the filesystem using C# on UWP. The image is downloaded from Facebook using the graph api and returned as a BitmapImage. That part works, and to retrieve the image (once I can store it, tested with pictures just dropped in the local folder) I'm using the following code:
public static async Task<BitmapImage> GetProfilePicture(string userId){
BitmapImage profilePicture = new BitmapImage();
StorageFolder pictureFolder = await
ApplicationData.Current.LocalFolder.GetFolderAsync("ProfilePictures");
StorageFile pictureFile = await pictureFolder.GetFileAsync(userId + ".jpg");
IRandomAccessStream stream = await pictureFile.OpenAsync(FileAccessMode.Read);
profilePicture.SetSource(stream);
return profilePicture;
This works as well, so what I would want is to simply do the opposite. The preferred result would look like this:
public static async void SaveBitmapToFile(BitmapImage image, userId){
StorageFolder pictureFolder = await
ApplicationData.Current.LocalFolder.CreateFolderAsync(
"ProfilePictures",CreationCollisionOption.OpenIfExists);
//save bitmap to pictureFolder with name userId.jpg
}
I've searched far and wide trying to find a solution, but I can't seem to find any for the UWP platform. How would a go about saving the Bitmap to file? The extension doesn't have to be .jpg if it would be easier to use another extension.
It would be easier if you used a WriteableBitmap. For example, the first method would then be:
public static async Task<WriteableBitmap> GetProfilePictureAsync(string userId)
{
StorageFolder pictureFolder = await ApplicationData.Current.LocalFolder.GetFolderAsync("ProfilePictures");
StorageFile pictureFile = await pictureFolder.GetFileAsync(userId + ".jpg");
using (IRandomAccessStream stream = await pictureFile .OpenAsync(FileAccessMode.Read))
{
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
WriteableBitmap bmp = new WriteableBitmap((int)decoder.PixelWidth, (int)decoder.PixelHeight);
await bmp.SetSourceAsync(stream);
return bmp;
}
}
Then you could do:
public static async Task SaveBitmapToFileAsync(WriteableBitmap image, userId)
{
StorageFolder pictureFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync("ProfilePictures",CreationCollisionOption.OpenIfExists);
var file = await pictureFolder.CreateFileAsync(userId + ".jpg", CreationCollisionOption.ReplaceExisting);
using (var stream = await file.OpenStreamForWriteAsync())
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream.AsRandomAccessStream());
var pixelStream = image.PixelBuffer.AsStream();
byte[] pixels = new byte[image.PixelBuffer.Length];
await pixelStream.ReadAsync(pixels, 0, pixels.Length);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)image.PixelWidth, (uint)image.PixelHeight, 96, 96, pixels);
await encoder.FlushAsync();
}
}
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();
}
}
I want to share the screenshot of my app. The screenshot is saved into the phone's picture library then it's shared as StorageFile
The problem is, the image is not attached to the sharing apps. I've verified that the screenshot was saved successfully in the phone's picture library.
Here's my code. What am I missing?
private async void askFacebook()
{
// Render some UI to a RenderTargetBitmap
var renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(this.gridRoot, (int)this.gridRoot.ActualWidth, (int)this.gridRoot.ActualHeight);
// Get the pixel buffer and copy it into a WriteableBitmap
var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
var width = renderTargetBitmap.PixelWidth;
var height = renderTargetBitmap.PixelHeight;
var wbmp = await new WriteableBitmap(1, 1).FromPixelBuffer(pixelBuffer, width, height);
imageToShare = await saveWriteableBitmapAsJpeg(wbmp, string.Format("{0}.jpg", getAppTitle()));
DataTransferManager.ShowShareUI();
}
private string getAppTitle()
{
// Get the assembly with Reflection:
Assembly assembly = typeof(App).GetTypeInfo().Assembly;
// Get the custom attribute informations:
var titleAttribute = assembly.CustomAttributes.Where(ca => ca.AttributeType == typeof(AssemblyTitleAttribute)).FirstOrDefault();
// Now get the string value contained in the constructor:
return titleAttribute.ConstructorArguments[0].Value.ToString();
}
private async Task<StorageFile> saveWriteableBitmapAsJpeg(WriteableBitmap bmp, string fileName)
{
// Create file in Pictures library and write jpeg to it
var outputFile = await KnownFolders.PicturesLibrary.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
using (var writeStream = await outputFile.OpenAsync(FileAccessMode.ReadWrite))
{
await encodeWriteableBitmap(bmp, writeStream, BitmapEncoder.JpegEncoderId);
}
return outputFile;
}
private async Task encodeWriteableBitmap(WriteableBitmap bmp, IRandomAccessStream writeStream, Guid encoderId)
{
// Copy buffer to pixels
byte[] pixels;
using (var stream = bmp.PixelBuffer.AsStream())
{
pixels = new byte[(uint)stream.Length];
await stream.ReadAsync(pixels, 0, pixels.Length);
}
// Encode pixels into stream
var encoder = await BitmapEncoder.CreateAsync(encoderId, writeStream);
var logicalDpi = DisplayInformation.GetForCurrentView().LogicalDpi;
encoder.SetPixelData(BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied,
(uint)bmp.PixelWidth,
(uint)bmp.PixelHeight,
logicalDpi,
logicalDpi,
pixels);
await encoder.FlushAsync();
}
private void ShareImageHandler(DataTransferManager sender, DataRequestedEventArgs e)
{
DataRequest request = e.Request;
request.Data.Properties.Title = "Ask Social Media";
request.Data.Properties.Description = "Do you know the answer to this question?";
// Because we are making async calls in the DataRequested event handler,
// we need to get the deferral first.
DataRequestDeferral deferral = request.GetDeferral();
// Make sure we always call Complete on the deferral.
try
{
request.Data.SetBitmap(RandomAccessStreamReference.CreateFromFile(imageToShare));
}
finally
{
deferral.Complete();
}
}
Apparently for Windows Phone, the image needs to be a StorageItem as the SetBitmap methods only works with Windows 8.x
So for Windows phone, instead of
request.Data.SetBitmap(RandomAccessStreamReference.CreateFromFile(imageToShare));
I created a storage item and use SetStorageItems to share it. It works with native Windows Phone apps such as emails, OneNote but I haven't tested it for sharing on Facebook, Twitter etc.
var imageItems = new List<IStorageItem>();
imageItems.Add(imageToShare);
request.Data.SetStorageItems(imageItems);
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;
}
}