Local Image not displayed in Skia.WPF Uno Platform project - uno-platform

I save images relative to the workingdirectory and then want to display them in a uno Skia.WPF app.
However they never appear.
This is how I create the ImageSource:
public static async Task<ImageSource> GenerateSource()
{
var picker = new Windows.Storage.Pickers.FileOpenPicker();
picker.FileTypeFilter.Add(".png");
var pickerResult = await picker.PickSingleFileAsync("tileset");
if (pickerResult is null)
return null;
using var stream = await pickerResult.OpenReadAsync();
string imagePath = Path.GetFullPath(Path.Combine("cache", "image.png"));
Directory.CreateDirectory(Path.GetDirectoryName(imagePath));
using (var bitmapImageStream = File.Open(imagePath,
FileMode.Create,
FileAccess.Write,
FileShare.None))
{
await stream.AsStreamForRead().CopyToAsync(bitmapImageStream);
bitmapImageStream.Flush(true);
}
var imgSrc = new Windows.UI.Xaml.Media.Imaging.BitmapImage();
imgSrc.UriSource = new Uri($"file://{imagePath}");
var width = imgSrc.PixelHeight;
return imgSrc;
}
But when I use the path directly in the Xaml it also not working.
<Image Source="file://cache/image.png" Width="32" Height="32" />
Using an image from the Internet using an http url works.
Sample Repo

file: URIs are currently not supported in Uno, however, you can still show local images by copying to the appropriate folder using ms-appdata scheme. If you copy the file into ApplicationData.Current.TemporaryFolder, you will the be able to reference that path by ms-appdata:///temp/{imageName} URI.

Related

How do I convert a stream of images to a path? (xamarin-forms)

I used the Xamarin(Photo Picker) example and was able to output the image using this code
image.Source = ImageSource.FromStream(() => stream);
How do I convert a stream of images to a file.Path?
I want to save the path to the image to a local database.
Yes,it is recommended that you use Xamarin.Essentials: Media Picker to achieve this.
You can get the FullPath of your image except the stream.
Please refer the following code:
async void Button_Clicked(System.Object sender, System.EventArgs e)
{
var result = await MediaPicker.PickPhotoAsync(new MediaPickerOptions
{
Title = "Please pick a photo"
});
if (result != null)
{
var stream = await result.OpenReadAsync();
resultImage.Source = ImageSource.FromStream(() => stream);
// you can get the FullPath of current photo
string path = result.FullPath;
}
}
If you have an Image in your UI, it can have different types of Sources. It can be from a File, a URL or a Stream.
A stream is in memory only, so if you want a path to a file, you will have to convert it to a file first.
using (System.IO.FileStream fileStream = System.IO.File.Create(filePath))
{
stream.CopyTo(fileStream);
}
And then you can get the path to your file.
You can save the file wherever you want, I recommend using Xamarin.Essentials FileSystem Helper

Download multiple files (50mb) blazor server-side

i can't really find a way to download a 100mb zip file from the server to the client and also show the progress while downloading. So how will this look for a normal api controller i can add to my server-side project? if lets say i have 3 files i want to download at 50mb each.
i have tried using JSInterop like this, but this is not showing the progress of the file download, and how will i do if i want to download 3 seperate files at the same time?
try
{
//converting file into bytes array
var dataBytes = System.IO.File.ReadAllBytes(file);
await JSRuntime.InvokeVoidAsync(
"downloadFromByteArray",
new
{
ByteArray = dataBytes,
FileName = "download.zip",
ContentType = "application/force-download"
});
}
catch (Exception)
{
//throw;
}
JS:
function downloadFromByteArray(options: {
byteArray: string,
fileName: string,
contentType: string
}): void {
// Convert base64 string to numbers array.
const numArray = atob(options.byteArray).split('').map(c => c.charCodeAt(0));
// Convert numbers array to Uint8Array object.
const uint8Array = new Uint8Array(numArray);
// Wrap it by Blob object.
const blob = new Blob([uint8Array], { type: options.contentType });
// Create "object URL" that is linked to the Blob object.
const url = URL.createObjectURL(blob);
// Invoke download helper function that implemented in
// the earlier section of this article.
downloadFromUrl({ url: url, fileName: options.fileName });
// At last, release unused resources.
URL.revokeObjectURL(url);
}
UPDATE:
if im using this code, it will show me the progress of the file. But how can i trigger it from my code? This way does not do it. But typing the url does.
await Http.GetAsync($"Download/Model/{JobId}");
Controller
[HttpGet("download/model/{JobId}")]
public IActionResult DownloadFile([FromRoute] string JobId)
{
if (JobId == null)
{
return BadRequest();
}
var FolderPath = $"xxxx";
var FileName = $"Model_{JobId}.zip";
var filePath = Path.Combine(environment.WebRootPath, FolderPath, FileName);
byte[] fileBytes = System.IO.File.ReadAllBytes(filePath);
return File(fileBytes, "application/force-download", FileName);
}
UPDATE 2!
i have got it download with progress and click with using JSInterop.
public async void DownloadFiles()
{
//download all selectedFiles
foreach (var file in selectedFiles)
{
//download these files
await JSRuntime.InvokeAsync<object>("open", $"Download/Model/{JobId}/{file.Name}", "_blank");
}
}
Now the only problem left is.. it only downloads the first file out of 3.

xamarin.forms Sharing Image AND text (body, not title)

I am using this sharing function:
public static async void ShareImageAndText(string text, string image)
{
var fn = "pic.png";
var file = Path.Combine(FileSystem.CacheDirectory, fn);
File.WriteAllBytes(file, Convert.FromBase64String(image));
await Share.RequestAsync(new ShareFileRequest()
{
Title = text,
File = new ShareFile(file)
});
}
This shares an image to whereever I please, but the text "title" only appears if I share to email. If I share to whatsapp for instance, it will only give the image. But since I also want to share a text with an uri in it, this option doesnt work.
Who knows how to share a file AND a text in the same request?
Thanks
Having the same problem, I was unable of resolving it using the Xamaring.Essentials.Share. So, I created in my Xamarin Forms App a Page with the Image and Text that I need to send, and take a screenshot of it using Screenshot https://learn.microsoft.com/en-us/xamarin/essentials/screenshot and saving it to File. Then just send it.
//Take a screenshot from this page to a file
string path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
var File_Path = System.IO.Path.Combine(path, "Screenshot.png");
var screenshot = await Screenshot.CaptureAsync();
var stream = await screenshot.OpenReadAsync(ScreenshotFormat.Png);
using (var fileStream = System.IO.File.Create(File_Path))
{
stream.Seek(0, System.IO.SeekOrigin.Begin);
stream.CopyTo(fileStream);
}
await Share.RequestAsync(new ShareFileRequest
{
Title = "Some Title",
File = new ShareFile(File_Path)
});

Xamarin Forms: Get the path of an image file stored on the shared project?

I am trying to upload an image file as ByteArrayContent through my web service. I have added all the images to the shared project and set the build action as Embedded resource.
Following is my code:
var fileBytes = File.ReadAllBytes("Avatars." + selectedAvatar);
var byteContent = new ByteArrayContent(fileBytes);
content.Add(byteContent, "file", selectedAvatar);
When I try like above I am getting System.IO.FileNotFoundException: Could not find file "/Projectname.Avatars.ic_avatar01_xx.png"
Added the images directly inside a folder in the shared project like the below screenshot.
:
I tried changing the . with a / in the file path, like below:
var fileBytes = File.ReadAllBytes("Avatars/" + selectedAvatar);
var byteContent = new ByteArrayContent(fileBytes);
content.Add(byteContent, "file", selectedAvatar);
But in that case, I am getting the System.IO.DirectoryNotFoundException: Could not find a part of the path "/Avatars/ic_avatar01_xx.png"
What is the correct way to get the path of an image file stored on a shared project?
Also tried another approach:
string avatarFileName = "Avatars/" + selectedAvatar;
var assembly = typeof(ProfilePage).GetTypeInfo().Assembly;
var stream = assembly.GetManifestResourceStream($"{assembly.GetName().Name}.{avatarFileName}");
content.Add(stream, "file", avatarFileName);
But in the above case I am getting the below error:
If you want to upload the image with Stream , you could check the following code
private async Task<string> UploadImage(Stream FileStream)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://your.url.com/");
MultipartFormDataContent form = new MultipartFormDataContent();
HttpContent content = new StringContent("fileToUpload");
form.Add(content, "fileToUpload");
content = new StreamContent(FileStream);
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "fileToUpload",
FileName = "xxx.png"
};
form.Add(content);
var response = await client.PostAsync("http://your.url.com/", form);
return response.Content.ReadAsStringAsync().Result;
}
Option 2:
You could also use the plugin FileUploaderPlugin . It support uploading multiple files at once
Uploading from a file path
CrossFileUploader.Current.UploadFileAsync("<URL HERE>", new FilePathItem("<REQUEST FIELD NAME HERE>","<FILE PATH HERE>"), new Dictionary<string, string>()
{
{"<HEADER KEY HERE>" , "<HEADER VALUE HERE>"}
}
);
Option 3:
The first parameter of MultipartFormDataContent is HttpContent. To handle the stream, try using the StreamContent type which inherits from the HttpContent. Get the streamContent from the stream and add id to the MultipartFormDataContent.
string avatarFileName = "Avatars." + selectedAvatar;
var assembly = typeof(ProfilePage).GetTypeInfo().Assembly;
var stream = assembly.GetManifestResourceStream($"{assembly.GetName().Name}.{avatarFileName}");
var streamContent = new StreamContent(stream);
content.Add(streamContent, "file", avatarFileName);

Issue with Returning Epplus spreadsheets with an Image in .zip file using DotNetZip

This scenario works fine without any images on the spreadsheet, but after attempting to add an image to the spreadsheets that get put in the zip file, the spreadsheets open with the excel error of "We found a problem with some content ....".
I have other methods using Epplus without DotNetZip that use the exact same code to insert the image into a spreadsheet and they work fine with no errors or issues.
Code that works to return a single spreadsheet with an image
public async Task<ActionResult> GenerateSpreadsheet(ReportViewModel reportViewModel)
{
using (var excelPackage = new ExcelPackage())
{
Bitmap logoFile = getLogoFile();
var companyLogo = worksheet.Drawings.AddPicture("File Name", logoFile);
companyLogo.From.Column = columnIndex - 4;
companyLogo.From.Row = rowIndex;
companyLogo.SetSize(logoFile.Width, logoFile.Height);
//Write all the stuff to the spreadsheet
Response.ClearContent();
Response.BinaryWrite(excelPackage.GetAsByteArray());
string fileName = "attachment;filename=Project_Report_Export.xlsx";
Response.AddHeader("content-disposition", fileName);
Response.ContentType = "application/excel";
Response.Flush();
Response.End();
}
}
Code that will build a spreadsheet, add it to a zip file, but where the spreadsheet will open with the "We found a problem with some content ...." if an image was added to the spreadsheet as shown below. If there is no image added to it, it will open without the error.
public async Task<ActionResult> GenerateSpreadsheet(ReportViewModel reportViewModel)
{
using (var stream = new MemoryStream())
{
using (ZipFile zip = new ZipFile())
{
foreach(var spreadSheet in listOfStuffToBuildFrom)
{
using (var excelPackage = new ExcelPackage())
{
Bitmap logoFile = getLogoFile();
var companyLogo = worksheet.Drawings.AddPicture("File Name", logoFile);
companyLogo.From.Column = columnIndex - 4;
companyLogo.From.Row = rowIndex;
companyLogo.SetSize(logoFile.Width, logoFile.Height);
//Write all the stuff to the spreadsheet
//Add the workbook to the zip file
zip.AddEntry(excelPackage.Workbook.Properties.Title, excelPackage.GetAsByteArray());
}
}
zip.Save(stream);
return File(stream.ToArray(), System.Net.Mime.MediaTypeNames.Application.Zip, "Project Reports.zip");
}
}
}
Why does the second method return spreadsheets that open with the error "We found a problem with some content ...."??

Resources