Mvvmcross PictureChooser Plugin - Droid - Picture orientation is wrong - c#

I am using the following code to choose a photo on both iOS and Droid; however, on Droid, images taken in portrait are saved in landscape orientation. On iOS, the image saves with the correct orientation.
Mvx.Resolve<IMvxPictureChooserTask>().TakePicture(2000, 64, CaptureImageStream, () =>
{
/* don't do anything on cancel */
});
protected virtual void CaptureImageStream(Stream stream)
{
var fileStore = Mvx.Resolve<IMvxFileStore>();
const string folderName = "Observation_Photos";
fileStore.EnsureFolderExists(folderName);
//get file name
var fileName = RandomString(10);
while (fileStore.Exists(string.Format("{0}/{1}.jpg", folderName, fileName)))
{
fileName = RandomString(10);
}
//get file bytes
var fileContents = GetBytes(stream);
//write file
var fullPath = string.Format("{0}/{1}.jpg", folderName, fileName);
fileStore.WriteFile(fullPath, fileContents);
}
private static IEnumerable<byte> GetBytes(Stream stream)
{
using (var memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
Any ideas why the photo has the wrong orientation on droid or how to resolve the problem?

Update version of the MvxPictureChooserTask.cs from this pull request, https://github.com/MvvmCross/MvvmCross/pull/627, fixed the problem.

Related

ArgumentException: Parameter is not valid while copying from FileStream to MemoryStream

I am trying to resize image using bitmap from Memorystream and save to directory. It works on the first run but if i try to update the image second time i am getting ArgumentException.
public IActionResult UpdatePhoto(int id, IFormFile file)
{
var company = _context.Companies.FirstOrDefault(x => x.Id == id);
var image = company.Logo;
var path = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/companies", image);
if (System.IO.File.Exists(path))
{
System.IO.File.Delete(path);
}
ResizeImage(file, file.FileName);
company.Logo = file.FileName;
_context.Companies.Update(company);
_context.SaveChanges();
return RedirectToAction(nameof(Index));
}
I am getting error in Resize Method
public void ResizeImage(IFormFile file, string FileName)
{
using (var memoryStream = new MemoryStream())
{
file.CopyToAsync(memoryStream);
Bitmap original = (Bitmap)Image.FromStream(memoryStream);
Bitmap processed = new Bitmap(original,new Size(300,300));
var path = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/companies", FileName );
processed.Save(path);
}
you shouldn't be using any of the async methods inside the methods which are not awaitable. updating your code to following should fix the issue.
public void ResizeImage(IFormFile file, string FileName)
{
using (var memoryStream = new MemoryStream())
{
file.CopyTo(memoryStream);
Bitmap original = (Bitmap)Image.FromStream(memoryStream);
Bitmap processed = new Bitmap(original,new Size(300,300));
var path = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/companies", FileName );
processed.Save(path);
}
}

Save image from an image box to gallery in Xamarin Forms

Is there a way to save the picture in an image control to the Android gallery in Xamarin Forms? All help is appreciated.
var image = new Image();
image.Source = "test.png";
Screenshot
You could use Dependency Service to get the stream from Resource/drawable image.
Create the IDependency interface.
public interface IDependency
{
MemoryStream DrawableByNameToByteArray(string fileName);
}
Android implementation
public class DependencyImplementation : IDependency
{
public MemoryStream DrawableByNameToByteArray(string fileName)
{
var context = Application.Context;
using (var drawable = Xamarin.Forms.Platform.Android.ResourceManager.GetDrawable(context, fileName))
using (var bitmap = ((BitmapDrawable)drawable).Bitmap)
{
var stream = new MemoryStream();
bitmap.Compress(Bitmap.CompressFormat.Png, 100, stream);
bitmap.Recycle();
return stream;
}
}
}
For the IOS implementation, you could refer to the thread in SO.
Convert Image (from drawable folder) to ByteArray
And then register in Android Mainactivity.
DependencyService.Register<IDependency, DependencyImplementation>();
If your android version is highter than android 6.0, you need runtime permission for storage in this question. Please check the Plugin.Permissions with runtime permission.
https://github.com/jamesmontemagno/PermissionsPlugin
After that, you could save the image to picture internal storage.
var filename = "";
var source = image.Source as FileImageSource;
if (source != null)
{
filename = source.File;
}
var savingFile = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyPictures);
//var savingFile1 = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData), "save.png");
var S = DependencyService.Get<IDependency>().DrawableByNameToByteArray(filename);
if (!File.Exists(savingFile))
{
File.WriteAllBytes(savingFile, S.ToArray());
}
In Internal Storage, you couldn't see the files without root permission.
If you want to view it, you could use adb tool.
Please check the way in link.
How to write the username in a local txt file when login success and check on file for next login?
You can use Media Plugin and it can solve your issue. https://github.com/jamesmontemagno/MediaPlugin
You can visit the above link.
takePhoto.Clicked += async (sender, args) =>
{
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
DisplayAlert("No Camera", ":( No camera available.", "OK");
return;
}
var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
Directory = "Sample",
Name = "test.jpg"
});
if (file == null)
return;
await DisplayAlert("File Location", file.Path, "OK");
image.Source = ImageSource.FromStream(() =>
{
var stream = file.GetStream();
return stream;
});
};

Xamarin Saving an image and displaying in navigation bar

I am trying to save an image to the internal storage of an Android device. Then I want to access it in the shared project for the icons in my navigation bar. The image is coming back from an API. Its giving Android.Content.Res.Resources+NotFoundException Resource ID #0x0.
Saving the image:
public async Task<bool> SaveImage(string filename, ImageSource img)
{
System.IO.Stream outputStream = null;
bool success = false;
var renderer = GetHandler(img);
Bitmap photo = Task.Run(async () => await renderer.LoadImageAsync(img, Forms.Context)).Result;
string savedImageFilename = System.IO.Path.Combine(documentsPath, filename);
using (outputStream = new System.IO.FileStream(savedImageFilename, FileMode.Create))
{
if (System.IO.Path.GetExtension(filename).ToLower() == ".png")
success = await photo.CompressAsync(Bitmap.CompressFormat.Png, 100, outputStream);
else
success = await photo.CompressAsync(Bitmap.CompressFormat.Jpeg, 100, outputStream);
}
return success;
}
Loading the Image:
public FileImageSource LoadImage(string filename)
{
var filePath = Path.Combine(documentsPath, MyBlueAssets);
filePath = Path.Combine(filePath, filename);
FileImageSource image = (FileImageSource)ImageSource.FromFile(filePath);
return image;
}
Accessing and displaying in shared project:
DependencyService.Get<IImageCacheDependency>().SaveImage(imageName, Image, count);
FileImageSource loadedImage = DependencyService.Get<IImageCacheDependency ().LoadImage(imageName);
navigation.Icon = loadedImage;

OneDrive Downloaded *.jpeg Image File Corrupt in Windows Phone 8

I'm doing a backup of my app database to OneDrive. The database records refer to images that are stored in isolated storage. I backup those images too. The database files.
The destinations of the backup file is:
me/skydrive/my_documents/MyCompany/MyApp/MyBackup.bak
The destination of the jpg image files is
me/skydrive/my_documents/MyCompany/MyApp/MyBackup Images/*.jpg
The database restores fine, but the images don't. I've verified that the image is backed up properly on SkyDrive - I can see it and open it fine from SkyDrive. However, when I restore, the file is corrupt. Here's the code I use to restore:
dynamic cmpFolder = await oneDrive.FindFolder("MyCompany", "me/skydrive/my_documents");
dynamic appFolder = await oneDrive.FindFolder(AppName, cmpFolder.id);
string imagesFileName = Path.GetFileNameWithoutExtension(selectedFile.FileName) + " Images";
dynamic imgFolder = await oneDrive.FindFolder(imagesFileName, appFolder.id);
dynamic fileList = await oneDrive.FindFiles(imgFolder.id);
foreach (var fileData in fileList.data)
{
string fileName = fileData.name;
var file =
await wilFolder.CreateFileAsync(
Path.GetFileName(fileName), CreationCollisionOption.ReplaceExisting);
var result = await client.BackgroundDownloadAsync(selectedFile.FileID +
"/content/", new Uri(#"\shared\transfers\" + fileName, UriKind.Relative));
}
Using ISETool and viewing \shared\transfers, I can see that the file is no longer readable. It's size is about 128k, whereas the original image was much larger.
I've also tried this, which was my original code until I began seeing the problem:
var downloadResult = await client.DownloadAsync(selectedFile.FileID + "/content/");
using (Stream oneDriveStream = downloadResult.Stream)
{
oneDriveStream.Position = 0;
byte[] imageBytes = new byte[oneDriveStream.Length];
int count = oneDriveStream.Read(imageBytes, 0, imageBytes.Length);
using (var s = await file.OpenStreamForWriteAsync())
{
oneDriveStream.CopyTo(s);
// and tried this
//s.Write(imageBytes, 0, imageBytes.Length);
}
}
For reference, here's the FindFolder and FindFiles implementations:
public async Task<dynamic> FindFiles(string folderName)
{
LiveOperationResult filesResult = await client.GetAsync(folderName + "/files");
dynamic files = filesResult.Result;
return files;
}
public async Task<dynamic> FindFolder(string folderName, string parentFolder)
{
LiveOperationResult folderResult = await client.GetAsync(parentFolder + "/files?filter=folders");
dynamic folders = folderResult.Result;
foreach (var folder in folders.data)
if (folder.name == folderName)
return folder;
return null;
}
How do I successfully download *.jpg images from my OneDrive folder?
Try this for your download path instead:
var downloadResult = await client.DownloadAsync(selectedFile.FileID + "/picture?type=full");

converting a base 64 string to an image and saving it

Here is my code:
protected void SaveMyImage_Click(object sender, EventArgs e)
{
string imageUrl = Hidden1.Value;
string saveLocation = Server.MapPath("~/PictureUploads/whatever2.png") ;
HttpWebRequest imageRequest = (HttpWebRequest)WebRequest.Create(imageUrl);
WebResponse imageResponse = imageRequest.GetResponse();
Stream responseStream = imageResponse.GetResponseStream();
using (BinaryReader br = new BinaryReader(responseStream))
{
imageBytes = br.ReadBytes(500000);
br.Close();
}
responseStream.Close();
imageResponse.Close();
FileStream fs = new FileStream(saveLocation, FileMode.Create);
BinaryWriter bw = new BinaryWriter(fs);
try
{
bw.Write(imageBytes);
}
finally
{
fs.Close();
bw.Close();
}
}
}
The top imageUrl declartion is taking in a Base64 image string, and I want to convert it into an image. I think my set of code only works for images like "www.mysite.com/test.jpg" not for a Base64 string. Anybody have some suggestions? Thanks!
Here is an example, you can modify the method to accept a string parameter. Then just save the image object with image.Save(...).
public Image LoadImage()
{
//data:image/gif;base64,
//this image is a single pixel (black)
byte[] bytes = Convert.FromBase64String("R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==");
Image image;
using (MemoryStream ms = new MemoryStream(bytes))
{
image = Image.FromStream(ms);
}
return image;
}
It is possible to get an exception A generic error occurred in GDI+. when the bytes represent a bitmap. If this is happening save the image before disposing the memory stream (while still inside the using statement).
You can save Base64 directly into file:
string filePath = "MyImage.jpg";
File.WriteAllBytes(filePath, Convert.FromBase64String(base64imageString));
Here is what I ended up going with.
private void SaveByteArrayAsImage(string fullOutputPath, string base64String)
{
byte[] bytes = Convert.FromBase64String(base64String);
Image image;
using (MemoryStream ms = new MemoryStream(bytes))
{
image = Image.FromStream(ms);
}
image.Save(fullOutputPath, System.Drawing.Imaging.ImageFormat.Png);
}
I would suggest via Bitmap:
public void SaveImage(string base64)
{
using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(base64)))
{
using (Bitmap bm2 = new Bitmap(ms))
{
bm2.Save("SavingPath" + "ImageName.jpg");
}
}
}
Here is working code for converting an image from a base64 string to an Image object and storing it in a folder with unique file name:
public void SaveImage()
{
string strm = "R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
//this is a simple white background image
var myfilename= string.Format(#"{0}", Guid.NewGuid());
//Generate unique filename
string filepath= "~/UserImages/" + myfilename+ ".jpeg";
var bytess = Convert.FromBase64String(strm);
using (var imageFile = new FileStream(filepath, FileMode.Create))
{
imageFile.Write(bytess, 0, bytess.Length);
imageFile.Flush();
}
}
In my case it works only with two line of code. Test the below C# code:
String dirPath = "C:\myfolder\";
String imgName = "my_mage_name.bmp";
byte[] imgByteArray = Convert.FromBase64String("your_base64_string");
File.WriteAllBytes(dirPath + imgName, imgByteArray);
That's it. Kindly up vote if you really find this solution works for you. Thanks in advance.
In a similar scenario what worked for me was the following:
byte[] bytes = Convert.FromBase64String(Base64String);
ImageTagId.ImageUrl = "data:image/jpeg;base64," + Convert.ToBase64String(bytes);
ImageTagId is the ID of the ASP image tag.
If you have a string of binary data which is Base64 encoded, you should be able to do the following:
byte[] encodedDataAsBytes = System.Convert.FromBase64String(encodedData);
You should be able to write the resulting array to a file.
public bool SaveBase64(string Dir, string FileName, string FileType, string Base64ImageString)
{
try
{
string folder = System.Web.HttpContext.Current.Server.MapPath("~/") + Dir;
if (!Directory.Exists(folder))
{
Directory.CreateDirectory(folder);
}
string filePath = folder + "/" + FileName + "." + FileType;
File.WriteAllBytes(filePath, Convert.FromBase64String(Base64ImageString));
return true;
}
catch
{
return false;
}
}
Using MemoryStream is not a good idea and violates a specification in MSDN for Image.FromStream(), where it says
You must keep the stream open for the lifetime of the Image.
A better solution is using ImageConverter, e.g:
public Image ConvertBase64ToImage(string base64)
=> (Bitmap)new ImageConverter().ConvertFrom(Convert.FromBase64String(base64));
In NetCore 6.0, you can use HttpClient and the async methods in the new File class.
The implementation is very simple:
static async Task DownloadFile(string imageUrl, string pathToSave)
{
var content = await GetUrlContent(url);
if (content != null)
{
await File.WriteAllBytesAsync(pathToSave, content);
}
}
static async Task<byte[]?> GetUrlContent(string url)
{
using (var client = new HttpClient())
using (var result = await client.GetAsync(url))
return result.IsSuccessStatusCode ? await result.Content.ReadAsByteArrayAsync():null;
}
Usage:
await DownloadFile("https://example.com/image.jpg", #"c:\temp\image.jpg");

Categories