coding xamarin form project and also using pcl storage. have problem with saving image or file on device all examples i found show how to save stream of byte array into file but non of them show how to turn convert image into usable format for saving.
var webImage = new Image();
webImage.Source = new UriImageSource
{
CachingEnabled = false,
Uri = new Uri("http://server.com/image.jpg"),
};
byte[] image = ????(what i need)????(webImage.Source);
// get hold of the file system
IFolder folder = rootFolder ?? FileSystem.Current.LocalStorage;
// create a file, overwriting any existing file
IFile file = await folder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
// populate the file with image data
using (System.IO.Stream stream = await file.OpenAsync(FileAccess.ReadAndWrite))
{
stream.Write(image, 0, image.Length);
}
In other words looking for code to save image/file on device from url.
Tried ffimageloading since it contain converter to byte[], but always get error:"Object reference not set to an instance of an object." for GetImageAsJpgAsync and GetImageAsPngAsync method. problem might be that image isn't fully loaded. but finish event and finish command never get called even trough image is fully loaded on screen and bound to cachedImage.
var cachedImage = new CachedImage()
{
Source = "https://something.jpg",
FinishCommand = new Command(async () => await TEST()),
};
cachedImage.Finish += CachedImage_Finish;
var image = await cachedImage.GetImageAsJpgAsync();
With FFImageLoading (I noticed you use it):
await ImageService.Instance.LoadUrl("https://something.jpg").AsJpegStream();
If you want to get original file location, use this:
await ImageService.Instance.LoadUrl("https://something.jpg").Success((imageInfo) => { //TODO imageInfo.FilePath } ).DownloadOnly();
Related
As the title says. It seems that Avalonia Bitmap requires file path, so the only solution that comes to my mind is saving image, and then displaying it. But it's not exactly what I want to do, I would want to directly display the image from memory.
public void ReadAndDisplayImage()
{
ReadWrite rw = new ReadWrite();
var image = rw.ReadImage(ImagePath); //ImageSharp Image
SelectedImage = new Avalonia.Media.Imaging.Bitmap(ImagePath); //constructor accepts only string, unable to display ImageSharp Image directly
}
In this case here displaying from path is fully acceptable, but later I will need to display it without saving.
You can save the Image's data into a memory stream and pass it in to Avalonia's Bitmap.
public void ReadAndDisplayImage()
{
ReadWrite rw = new ReadWrite();
var image = rw.ReadImage(ImagePath);
using (MemoryStream ms = new MemoryStream())
{
image.Save(ms,PngFormat.Instance);
SelectedImage = new Avalonia.Media.Imaging.Bitmap(ms);
}
}
Now I am working on edit operation in my app. So in edit operation there is an ability to change image and in the same time name of the file that keep image of the contact can not be renamed(during one session of operation image files will be changing but all this file will take same name).
And I used overload of CopyAsync method (docs to this method here) that as I have understand must to replace file to the existing file with the same name.
I get imageFile variable by FileOpenPicker. Code below runs every time I have choosed image by FileOpenPicker. And when I re-choose image at the result Image UI control show me previous chosen image. I expect that Image will view last image that I have choosed but this does not occurred.
public BitmapImage Image { set; get; }
//Copy of the file that saved in temporary storage
StorageFile fileForView = await imageFile.CopyAsync
(ApplicationData.Current.TemporaryFolder,
fileName,
NameCollisionOption.ReplaceExisting);
Image = new BitmapImage(new Uri(fileForView.Path));
Maybe I understand logic of CopyAsync method not correctly if I am in this case please show me how make my plan working with this method if it is possible. Otherwise offer your solution cause I have no idea now how to do this.
Also I tried to do this with CopyAndReplaceAsync method. But still no result. I do it in this way:
if (null != await ApplicationData.Current.TemporaryFolder.TryGetItemAsync(fileName))
{
StorageFile storageFile = await ApplicationData.Current.TemporaryFolder.GetFileAsync(fileName);
await storageFile.CopyAndReplaceAsync(imageFile);
}
I expect that Image will view last image that I have choosed but this does not occurred.
The above CopyAsync method is correct, and I have tested with the following code, it works well.
private async void ListOption_ItemClick(object sender, ItemClickEventArgs e)
{
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
openPicker.FileTypeFilter.Add(".jpg");
openPicker.FileTypeFilter.Add(".jpeg");
openPicker.FileTypeFilter.Add(".png");
StorageFile file = await openPicker.PickSingleFileAsync();
if (file != null)
{
StorageFile fileForView = await file.CopyAsync(ApplicationData.Current.TemporaryFolder, file.Name, NameCollisionOption.ReplaceExisting);
Image = new BitmapImage(new Uri(fileForView.Path));
TestImg.Source = Image;
}
else
{
}
}
I am developing a media player like vlc. One of it's features is saving snapshot during playback. I am able to successfully save the snapshot of any element using rendertargetbitmap class, using the following c# code.
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(RenderedGrid, width, height);
RenderedImage.Source = renderTargetBitmap;
But it does not allow to capture media element. Please help me with a workaround. I guess, I am not sure, may it be possible by extracting a thumbnail from a specific position using position of StorageItemThumbnail Class. If even so, it will be a thumbnail not an image of current frame. Someone help please. It is essential feature of my app!
in a digital signage uwp app that I developed I had also a similar requirement. Searching the web on how I can do I found that in UWP you can't directly take a screenshot of a media element due to a protection policy (for example you could create a small app that captures all the frames of a video file without DRM management).
I came up with a workaround: I have the video file locally so I can extract a single frame at a certain point and save it to disk with the same dimensions of the video rendered on screen (in this way I had a full image of the frame to use later). To doing this I wrote this function:
private async Task<string> Capture(StorageFile file, TimeSpan timeOfFrame, Size imageDimension)
{
if (file == null)
{
return null;
}
//Get FrameWidth & FrameHeight
List<string> encodingPropertiesToRetrieve = new List<string>();
encodingPropertiesToRetrieve.Add("System.Video.FrameHeight");
encodingPropertiesToRetrieve.Add("System.Video.FrameWidth");
IDictionary<string, object> encodingProperties = await file.Properties.RetrievePropertiesAsync(encodingPropertiesToRetrieve);
uint frameHeight = (uint)encodingProperties["System.Video.FrameHeight"];
uint frameWidth = (uint)encodingProperties["System.Video.FrameWidth"];
//Get image stream
var clip = await MediaClip.CreateFromFileAsync(file);
var composition = new MediaComposition();
composition.Clips.Add(clip);
var imageStream = await composition.GetThumbnailAsync(timeOfFrame, (int)frameWidth, (int)frameHeight, VideoFramePrecision.NearestFrame);
//Create BMP
var writableBitmap = new WriteableBitmap((int)frameWidth, (int)frameHeight);
writableBitmap.SetSource(imageStream);
//Get stream from BMP
string mediaCaptureFileName = "IMG" + Guid.NewGuid().ToString().Substring(0, 4) + ".jpg";
var saveAsTarget = await CreateMediaFile(mediaCaptureFileName);
Stream stream = writableBitmap.PixelBuffer.AsStream();
byte[] pixels = new byte[(uint)stream.Length];
await stream.ReadAsync(pixels, 0, pixels.Length);
using (var writeStream = await saveAsTarget.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, writeStream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied,
(uint)writableBitmap.PixelWidth,
(uint)writableBitmap.PixelHeight,
96,
96,
pixels);
await encoder.FlushAsync();
using (var outputStream = writeStream.GetOutputStreamAt(0))
{
await outputStream.FlushAsync();
}
}
return saveAsTarget.Name;
}
This function save the frame to disk as image and return his filename.
In my application I had more "widget" (some of those with images, some with video) so I used this function to get the video frames and put a new image on top of the media element with the same dimensions and a higher Canvas Z-Index in order to use RenderTargetBitmap for take the final screenshot.
It's not a clean solution but it was a workaround for RenderTargetBitmap not considering MediaElement.
Edit:
I forgot a reference to an internal function in my application so I canghed the previous code and the line var file = await _mediaEngine.CreateMediaFile($"{Guid.NewGuid().ToString()}.jpg"); is now var file = await CreateMediaFile($"{Guid.NewGuid().ToString()}.jpg");
The async function CreateMediaFile(string fileName) simply create a new file on the disk:
public async Task<StorageFile> CreateMediaFile(string filename)
{
StorageFolder _mediaFolder = KnownFolders.PicturesLibrary;
return await _mediaFolder.CreateFileAsync(filename);
}
I'm trying to load some 20 images in my WPF application. Only the first image loads completely. Other images are loading partially. When i used breakpoint to debug i tried to load each image after 2 seconds and that worked well.
Code
Images will be loaded like,
foreach (string path in ImagesCollection)
{
DisplayImage = LoadImage(path);
}
Load image method,
MemoryStream mem;
if (!string.IsNullOrEmpty(path) && (File.Exists(path)))
{
FileInfo ImageFile = new FileInfo(path);
ImageFile.Refresh();
if (mem != null)
{
mem.Dispose();
}
using (var stream = ImageFile.OpenRead())
{
mem = new MemoryStream();
stream.CopyTo(mem);
}
mem.Position = 0;
ImageFrame = BitmapFrame.Create(mem);
}
Screenshot:
I believe Dispose or a new instance makes the image doesn't load. Kindly help.
The documentation for BitmapFrame.Create state "The bitmapStream can be closed after the frame is created only when the OnLoad cache option is used. The default OnDemand cache option retains the stream until the frame is needed"
This means you cannot re-use the MemoryStream once you've passed it to the BitmapFrame. This is the source of the error.
For efficiency just pass the FileStream.
Load image method
if (!string.IsNullOrEmpty(path) && (File.Exists(path)))
{
var stream = ImageFile.OpenRead())
ImageFrame = BitmapFrame.Create(stream);
}
I am ABLE to take a picture, but I am having trouble saving it to one of the KnownFolders.
Yes, I have declared the Picture Library Access Capability in Package.appxmanifest.
var ui = new CameraCaptureUI();
ui.PhotoSettings.CroppedAspectRatio = new Size(4, 3);
StorageFile file = await ui.CaptureFileAsync(CameraCaptureUIMode.Photo);
if (file != null)
{
var stream = await file.OpenAsync(FileAccessMode.Read);
var bitmap = new BitmapImage();
bitmap.SetSource(stream);
Photo.Source = bitmap;
StorageFolder storageFolder = KnownFolders.PicturesLibrary;
var result = await file.CopyAsync(storageFolder, "tps.jpg");
}
The code stops on the last line. What am I doing wrong?
I think you also need declare the file types!
In the Declarations tab, choose File Type Associations from Available
Declarations and click Add.
Under Properties, set the Name property to image.
In the Supported File Types box, add .jpg as a supported file type by
entering .jpg in the FileType field.