I have an image SurfaceImageSource and I would convert it to PNG.
I tried to use this project:
link
I tried to use SharpDX library, but I did not succeed.
private void initialize()
{
StorageFolder folder = await ApplicationData.Current.LocalFolder.CreateFolderAsync("folder", CreationCollisionOption.OpenIfExists);
StorageFile imagePng = await folder.CreateFileAsync("file.png", CreationCollisionOption.ReplaceExisting);
if (imagePng != null)
{
//surfaceImageSource to PNG method
surfaceToPng(surfaceImage,imagePng);
}
}
private void surfaceToPng(SurfaceImageSource surface,StorageFile imagePng){
IRandomAccessStream stream = await imagePng.OpenAsync(FileAccessMode.ReadWrite);
//.....//
}
The sample you linked is about "How to save SurfaceImageSource target as an image in Universal app" which is just what you want. It create a C++ Windows Runtime Component named "MyImageSourceComponent" and provide a sealed class named "MyImageSource" which contains the method public void SaveSurfaceImageToFile(IRandomAccessStream randomAccessStream); You can call this method to save the SurfaceImageSource to png.
uint imageWidth;
uint imageHeight;
MyImageSource myImageSource;
public MainPage()
{
this.InitializeComponent();
imageWidth = (uint)this.MyImage.Width;
imageHeight = (uint)this.MyImage.Height;
myImageSource = new MyImageSource(imageWidth, imageHeight, true);
this.MyImage.Source = myImageSource;
}
private async void btnSave_Click(object sender, RoutedEventArgs e)
{
FileSavePicker savePicker = new FileSavePicker();
savePicker.FileTypeChoices.Add("Png file", new List<string>() { ".png" });
savePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
StorageFile file = await savePicker.PickSaveFileAsync();
if (file != null)
{
IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite);
myImageSource.SaveSurfaceImageToFile(stream);
}
}
Although this sample is for Windows 8.1, it also should be able work with uwp app. I helped convert the sample into uwp app here you can reference. I created a new uwp app with a windows runtime component and reference the code of the "MyImageSouceComponent" in the sample. Then add the runtime component as reference to the uwp project. At last use the above code call the SaveSurfaceImageToFile method.
Related
I want to pick an image from my pictures album in windows phone 8.1 . For this I used this code but its gives error
private async void gallery_Tapped(object sender, TappedRoutedEventArgs e)
{
FileOpenPicker opener = new FileOpenPicker();
opener.ViewMode = PickerViewMode.Thumbnail;
opener.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
opener.FileTypeFilter.Add(".jpg");
opener.FileTypeFilter.Add(".jpeg");
opener.FileTypeFilter.Add(".png");
StorageFile file = await opener.PickSingleFileAsync();
if (file != null)
{
// We've now got the file. Do something with it.
var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
var bitmapImage = new Windows.UI.Xaml.Media.Imaging.BitmapImage();
await bitmapImage.SetSourceAsync(stream);
var decoder = await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(stream);
MyImage.Source=bitmapImage;
}
else
{
//OutputTextBlock.Text = "The operation may have been cancelled.";
}
}
Error
I think you can handle the OnActivated event even in the page where you required. Something like this
CoreApplicationView view = CoreApplication.GetCurrentView();
ImagePath=string.Empty;
FileOpenPicker filePicker = new FileOpenPicker();
filePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
filePicker.ViewMode = PickerViewMode.Thumbnail;
// Filter to include a sample subset of file types
filePicker.FileTypeFilter.Clear();
filePicker.FileTypeFilter.Add(".bmp");
filePicker.FileTypeFilter.Add(".png");
filePicker.FileTypeFilter.Add(".jpeg");
filePicker.FileTypeFilter.Add(".jpg");
filePicker.PickSingleFileAndContinue();
view.Activated += viewActivated;
private void viewActivated(CoreApplicationView sender, IActivatedEventArgs args1)
{
FileOpenPickerContinuationEventArgs args = args1 as FileOpenPickerContinuationEventArgs;
if (args != null)
{
if (args.Files.Count == 0) return;
view.Activated -= viewActivated;
storageFileWP = args.Files[0];
}
}
When you select the files from the picker the above method will be called. I believe it helps you.
Using FileOpenPicker in Windows Phone 8.1 to choose picture from Picture Gallery.
Step 1: Add Picture Library Capability in your Windows Phone 8.1 app.
Step 2: Add File Open Picker as a declaration.
Step 3: Add a button and image to MainPage.xaml.
<Grid>
<Image Name="img"/>
<Button Content="click me" Click="Button_Click"/>
</Grid>
Step 4: Add global variable view.
CoreApplicationView view;
Step 4.1 Initialize in page constructor.
view = CoreApplication.GetCurrentView();
Step 5: Add the code to call the File Open Picker on Button Click event.
private void Button_Click(object sender, RoutedEventArgs e)
{
FileOpenPicker filePicker = new FileOpenPicker();
filePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
filePicker.ViewMode = PickerViewMode.Thumbnail;
// Filter to include a sample subset of file types
filePicker.FileTypeFilter.Clear();
filePicker.FileTypeFilter.Add(".bmp");
filePicker.FileTypeFilter.Add(".png");
filePicker.FileTypeFilter.Add(".jpeg");
filePicker.FileTypeFilter.Add(".jpg");
filePicker.PickSingleFileAndContinue();
view.Activated += viewActivated;
}
Step 6: On View activated event set the image to the MainPage.
private async void viewActivated(CoreApplicationView sender, IActivatedEventArgs args1)
{
FileOpenPickerContinuationEventArgs args = args1 as FileOpenPickerContinuationEventArgs;
if (args != null)
{
if (args.Files.Count == 0) return;
view.Activated -= viewActivated;
StorageFile storageFile = args.Files[0];
var stream = await storageFile.OpenAsync(Windows.Storage.FileAccessMode.Read);
var bitmapImage = new Windows.UI.Xaml.Media.Imaging.BitmapImage();
await bitmapImage.SetSourceAsync(stream);
var decoder = await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(stream);
img.Source=bitmapImage;
}
}
It also allows you to take a photo and use it.
Reference:
Using FileOpenPicker in Windows Phone 8.1 to choose picture from Picture Gallery
Use RoutedEventArgs instead of TappedRoutedEventArgs for button click in wp 8.1 xaml
Don't use async key word
private void OpenImageFile(object sender, RoutedEventArgs e)
{
FileOpenPicker filePicker = new FileOpenPicker();
filePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
filePicker.ViewMode = PickerViewMode.Thumbnail;
// Filter to include a sample subset of file types
filePicker.FileTypeFilter.Clear();
filePicker.FileTypeFilter.Add(".bmp");
filePicker.FileTypeFilter.Add(".png");
filePicker.FileTypeFilter.Add(".jpeg");
filePicker.FileTypeFilter.Add(".jpg");
filePicker.PickSingleFileAndContinue();
view.Activated += viewActivated;
}
private void viewActivated(CoreApplicationView sender, IActivatedEventArgs args1)
{
FileOpenPickerContinuationEventArgs args = args1 as FileOpenPickerContinuationEventArgs;
if (args != null)
{
if (args.Files.Count == 0) return;
view.Activated -= viewActivated;
StorageFile SelectedImageFile = args.Files[0];
}
}
And use CoreApplicationView view; Any where in the class out side of every method as global
Don't forget to use view = CoreApplication.GetCurrentView(); inside the constructor of the relevant page class after InitializeComponent(); method
I think this will help :) Thanks
var fill = await StorageFile.GetFileFromPathAsync(selectItem.FolderPath);
BitmapImage bit = new BitmapImage();
if (fill != null)
{
// We've now got the file. Do something with it.
var stream = await fill.OpenAsync(Windows.Storage.FileAccessMode.Read);
//var bitmapImage = new Windows.UI.Xaml.Media.Imaging.BitmapImage();
//await bitmapImage.SetSourceAsync(stream);
bit.SetSource(stream);
imgTeste.Source = bit;
pvMestre.SelectedIndex = 1;
}
else
{
//OutputTextBlock.Text = "The operation may have been cancelled.";
}
I want to open an image, edit it, and then save it. I am able to open a file, but I have problems saving it. The way I have written the code, I can only save a file with .jpg but there is nothing in it.
Please explain to me how to save the image I have opened and edited(not made yet).
public sealed partial class MainPage : Page
{
BitmapImage originalImage = new BitmapImage();
public MainPage()
{
this.InitializeComponent();
}
private async void OpenButton_Click(object sender, RoutedEventArgs e)
{
var filePicker = new FileOpenPicker();
filePicker.FileTypeFilter.Add(".jpg");
filePicker.FileTypeFilter.Add(".jpeg");
filePicker.FileTypeFilter.Add(".gif");
filePicker.ViewMode = PickerViewMode.Thumbnail;
filePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
filePicker.SettingsIdentifier = "PicturePicker";
filePicker.CommitButtonText = "Select File";
StorageFile selectedFile = await filePicker.PickSingleFileAsync();
var stream = await selectedFile.OpenAsync(FileAccessMode.Read);
if (selectedFile != null)
{
originalImage.SetSource(stream);
pictureBox.Source = originalImage;
}
}
private async void SaveButton_Click(object sender, RoutedEventArgs e)
{
FileSavePicker savePicker = new FileSavePicker();
savePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
savePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
savePicker.FileTypeChoices.Add("jpeg image", new List<string>() { ".jpg" });
savePicker.SuggestedFileName = "EditedImage";
StorageFile file = await savePicker.PickSaveFileAsync();
}
}
After creating an Images file you need to Update it see FileSavePicker class.
Add the following code in your SaveButton_Click method and try modify it.
This will let you update your created file into real image file.
if (file != null)
{
// Prevent updates to the remote version of the file until we finish making changes and call CompleteUpdatesAsync.
CachedFileManager.DeferUpdates(file);
// write to file
await FileIO.WriteTextAsync(file, file.Name);
// Let Windows know that we're finished changing the file so the other app can update the remote version of the file.
// Completing updates may require Windows to ask for user input.
FileUpdateStatus status = await CachedFileManager.CompleteUpdatesAsync(file);
if (status == FileUpdateStatus.Complete)
{
OutputTextBlock.Text = "File " + file.Name + " was saved.";
}
else
{
OutputTextBlock.Text = "File " + file.Name + " couldn't be saved.";
}
}
else
{
OutputTextBlock.Text = "Operation cancelled.";
}
I have a WinRT project, and am getting an error when trying to preview an image. I have set capabilities to allow access to the Pictures library, and am using the following code:
var file = await Windows.Storage.KnownFolders.PicturesLibrary.GetFileAsync(path);
var fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
var img = new BitmapImage();
img.SetSource(fileStream);
This error occurs on the first line:
A first chance exception of type 'System.Runtime.InteropServices.COMException' occurred in mscorlib.dll
Additional information: Error HRESULT E_FAIL has been returned from a call to a COM component.
I've tried other operations, such as folder.GetFilesAsync() with the same error. Is there another or capability that I need to allow this functionality to work correctly?
EDIT:
Based on #L.T.s answer, I tried some other capabilities. The following gives me the same error:
var folder = KnownFolders.PicturesLibrary;
var files = await folder.GetFilesAsync();
However (obviously, providing I provide the Music capability) this does not:
var testfolder = KnownFolders.MusicLibrary;
var files = await testfolder.GetFilesAsync();
I don't doubt that this it something specific to my Pictures library, but I have no idea what that could be.
If your cost is just to preview an image. You can use this
Uri uri = new Uri("ms-appx:///Assets/test.png");
BitmapImage bitmap = new BitmapImage(uri);
Image image = new Image();
image.Source = bitmap;
and add the image to a canvas. But you need to add your test.png to your projects assets first or you can change the Uri to the location of your test image.
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Image Name="img"></Image>
<Button Name="btn" Click="Btn_OnClick"></Button>
</Grid>
private async void Btn_OnClick(object sender, RoutedEventArgs e)
{
var file = await Windows.Storage.KnownFolders.PicturesLibrary.GetFileAsync("images.jpg");
var fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
var image = new BitmapImage();
image.SetSource(fileStream);
img.Source = image;
}
I have windows8.1 and with vs.2013. Don't see any error. Could be something else?
//////to load an image file just do this
//put this in your app.xaml
protected override void OnActivated(IActivatedEventArgs args)
{
var root = Window.Current.Content as Frame;
var mainPage = root.Content as MainPage;
if (mainPage != null && args is FileOpenPickerContinuationEventArgs)
{
mainPage.ContinueFileOpenPicker(args as FileOpenPickerContinuationEventArgs);
}
}
//and this in your btn event
private void Button_Click(object sender, RoutedEventArgs e)
{
var openPicker = new FileOpenPicker
{
ViewMode = PickerViewMode.Thumbnail,
SuggestedStartLocation = PickerLocationId.PicturesLibrary
};
openPicker.FileTypeFilter.Add(".jpg");
openPicker.PickSingleFileAndContinue();
}
//and this in you page
public void ContinueFileOpenPicker(FileOpenPickerContinuationEventArgs fileOpenPickerContinuationEventArgs)
{
if (fileOpenPickerContinuationEventArgs.Files != null)
{
// Do something with selected file/s
}
}
I'm trying to implement some logical to share the image of my webView and some extras informations. If I do that without capture screen, it works perfectly:
private async void OnDataRequested(DataTransferManager sender, DataRequestedEventArgs e)
{
if (await GetShareContent(e.Request))
{
if (String.IsNullOrEmpty(e.Request.Data.Properties.Title))
{
e.Request.FailWithDisplayText("Nenhum título adicionado");
}
}
}
private async Task<bool> GetShareContent(DataRequest request, StorageFile file)
{
bool succeeded = false;
string text = "Dados do Arquivo:" + Environment.NewLine + webViewModel.Name;
string dataPackageText = text;
if (!String.IsNullOrEmpty(dataPackageText))
{
DataPackage requestData = request.Data;
requestData.Properties.Title = "Target";
requestData.Properties.Description = webViewModel.Name;
requestData.SetText(dataPackageText);
succeeded = true;
}
else
{
request.FailWithDisplayText("Não há nada para compartilhar");
}
return succeeded;
}
But, if I try the same thing justing adding the captured image, it doesn't work, doesn't show any Excepetion, just the message: "Não há nada para compartilhar agora" (There's nothing to share right now)
I don't know what is going on. The code that doesn't work:
private async void OnDataRequested(DataTransferManager sender, DataRequestedEventArgs e)
{
StorageFile file = await captureScreen();
if (await GetShareContent(e.Request, file))
{
if (String.IsNullOrEmpty(e.Request.Data.Properties.Title))
{
e.Request.FailWithDisplayText("Nenhum título adicionado");
}
}
}
private async Task<StorageFile> captureScreen()
{
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(webView, (int)webView.Width, (int)webView.Height);
Image myImage = new Image();
myImage.Source = renderTargetBitmap;
var file = await App.rootDir.CreateFileAsync("screenCapture.jpg", CreationCollisionOption.ReplaceExisting);
var pixels = await renderTargetBitmap.GetPixelsAsync();
using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
byte[] bytes = pixels.ToArray();
encoder.SetPixelData(BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)webView.Width, (uint)webView.Height,
96, 96, bytes);
await encoder.FlushAsync();
}
return file;
}
I though it could be happening because the image was not read when the share is called, but I'm using await as it should be. And my jpeg is created perfectly.
The OnDataRequested callback needs to take a deferral, using DataRequest.GetDeferral, when calling asynchronous APIs.
private async void OnDataRequested(DataTransferManager sender, DataRequestedEventArgs e)
{
DataRequestDeferral deferral = e.Request.GetDeferral();
// Code to do screen capture...
deferral.Complete();
}
But, per MSDN, "[the share operation] function must return a DataPackage object within 200ms to prevent the operation from timing out". It is definitely possible for the screen capture to take longer than 200 ms. Use the DataPackage.SetDataProvider for operations that may take longer such as screen capture.
private void OnDataRequested(DataTransferManager sender, DataRequestedEventArgs e)
{
DataPackage requestData = e.request.Data;
requestData.Properties.Title = "Target";
requestData.Properties.Description = webViewModel.Name;
// Set up the data provider for a long running share operation...
requestData.SetDataProvider(StandardDataFormats.Bitmap, OnDeferredRequestedHandler);
}
private async void OnDeferredRequestedHandler(DataProviderRequest providerRequest)
{
// Again, get a deferral as an asynchronous method is called
DataProviderDeferral deferral = providerRequest.GetDeferral();
// Code to do screen capture...
deferral.Complete();
}
The Share content source sample on MSDN shows how this can be performed in full detail.
In WinRT app I have one FlipView myFlipView with some pictures and one Image myImage. On myFlipView's event SelectionChanged there is the following method:
async private void myFlipView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (myFlipView == null) return;
Uri newUri = new Uri("ms-appx://" + (((BitmapImage)(((Image)(((ContentControl)(myFlipView.SelectedItem)).Content)).Source)).UriSource.AbsolutePath));
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(newUri);
WriteableBitmap wb = new WriteableBitmap(1, 1);
if (file != null)
{
using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
await wb.SetSourceAsync(fileStream);
}
}
wb = ModifyPicture(wb);
myImage.Source = wb;
}
To sum up it finds uri of current image in myFlipView and set that image in myImage but with some modifications defined in ModifyPicture. It works perfectly on tablets but on computers with mouses there is one error. When I click arrows attached to FlipView very fast then myImage shows wrong picture. For example if in myFlipView I have 10 pictures (p1, p2, ..., p10) and currently p1 is chosen, when I change to p2 on myImage also p2 appears. But when I click very fast sometimes in FlipView I have for example p9 and in myImage p8. I suppose it is connected with fact that method is called many times but I don't know how to fix it. Thank you in advance for help :)
You should probably save the Task/IAsyncOperation that's already running and cancel it if the event handler is called again before it completes.
See this article on how to cancel running tasks.
Pseudo-code (as I don't know C#):
Task loadAndSetImage(uri) {
return new Task...
}
flipView_SelectionChanged {
if (myFlipView == null) return;
if (this.runningTask && !this.runningTask.IsCanceled) {
this.runningTask.Cancel();
}
Uri newUri = new Uri("ms-appx://" + (((BitmapImage)(((Image)(((ContentControl)(myFlipView.SelectedItem)).Content)).Source)).UriSource.AbsolutePath));
this.runningTask = loadAndSetImage(newUri);
this.runningTask.ContinueWith( (t) => this.runningTask = null; );
}
In addition to or instead of cancelling internal tasks as ma_il mentions - you could break/cancel your async method execution if you detect that it should be canceled. E.g.
private int myFlipView_SelectionChangedCallId;
async private void myFlipView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (myFlipView == null) return;
var callId = ++myFlipView_SelectionChangedCallId;
Uri newUri = new Uri("ms-appx://" + (((BitmapImage)(((Image)(((ContentControl)(myFlipView.SelectedItem)).Content)).Source)).UriSource.AbsolutePath));
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(newUri);
if (callId != myFlipView_SelectionChangedCallId) return;
WriteableBitmap wb = new WriteableBitmap(1, 1);
if (file != null)
{
using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
await wb.SetSourceAsync(fileStream);
if (callId != myFlipView_SelectionChangedCallId) return;
}
}
wb = ModifyPicture(wb);
myImage.Source = wb;
}
Also if your ModifyPicture method does any heavy pixel processing - you would want to run it on a background thread and await it.