I'm trying to add an image cropper to my app and have found Xamarin.Plugin.ImageEdit, that seems to be a good way to start on it, but the problem is that I couldn't find any example of how to show the image and the square over it to cut the image, in other words, integrate it with UI. Does anyone here have used ImageEdit and can tell me how to do it?
What I have so far:
async void Init()
{
MediaFile a = await CrossMedia.Current.PickPhotoAsync(new PickMediaOptions
{
CompressionQuality = 80,
RotateImage = true
});
byte[] imageArray = await Task.Run(()=>ImagePath2ByteArray(a));
using (var image = await CrossImageEdit.Current.CreateImageAsync(imageArray))
{
var croped = await Task.Run(() =>
image.Crop(10, 20, 250, 100)
.Rotate(180)
.Resize(100, 0)
.ToPng()
);
}
}
async Task<byte[]> ImagePath2ByteArray(MediaFile a)
{
byte[] imageArray = null;
if (a != null)
{
using (MemoryStream ms = new MemoryStream())
{
var stream = a.GetStream();
stream.CopyTo(ms);
imageArray = ms.ToArray();
}
}
return imageArray;
}
It seems to work fine but doesn't have UI.
Related
if (!CrossMedia.Current.IsPickPhotoSupported)
{
await Application.Current.MainPage.DisplayAlert("Photos Not Supported", ":( Permission not granted to photos.", "OK");
return;
}
var file = await Plugin.Media.CrossMedia.Current.PickPhotoAsync(new Plugin.Media.Abstractions.PickMediaOptions
{
PhotoSize = Plugin.Media.Abstractions.PhotoSize.Medium,
});
if (file == null)
return;
var tmpSrc = ImageSource.FromStream(() =>
{
var stream = file.GetStream();
file.Dispose();
return stream;
});
ImageSource toBeConverted = tmpSrc;
I want the variable toBeConverted to be converted into Byte[] so
that I can send it to my webapi ...
ImageSource is a way to provide a source image for Xamarin.Forms.Image to show some content. If you're already showing something on the screen your Image view was populated with data that came from elsewhere, such as a file or resource or stored in an array in memory... or however else you got that in the first place. Instead of trying to get that data back from ImageSource you can keep a reference to it and upload it as needed.
So you could get the byte array from the file after you pick the photo.
var file = await Plugin.Media.CrossMedia.Current.PickPhotoAsync(new Plugin.Media.Abstractions.PickMediaOptions
{
PhotoSize = Plugin.Media.Abstractions.PhotoSize.Medium,
});
if (file == null)
return;
var bytes = File.ReadAllBytes(file.Path); // you could get the byte[] here from the file path.
This code also worked for me ...
private async void Capture()
{
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await Application.Current.MainPage.DisplayAlert("No Camera", ":( No camera available.", "OK");
return;
}
var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
Directory = "Test",
SaveToAlbum = true,
CompressionQuality = 75,
CustomPhotoSize = 50,
PhotoSize = PhotoSize.Medium,
DefaultCamera = CameraDevice.Front
});
if (file == null)
return;
var stream = file.GetStream();
if (stream != null)
{
var StreamByte = ReadAllBytes(stream);
var NewStream = new MemoryStream(StreamByte);
// stream = mystream;
Device.BeginInvokeOnMainThread(() => {
ImageSource = ImageSource.FromStream(() => NewStream);
});
student.ProfilePicture = StreamByte;
}
}
public byte[] ReadAllBytes(Stream instream)
{
if (instream is MemoryStream)
return ((MemoryStream)instream).ToArray();
using (var memoryStream = new MemoryStream())
{
instream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
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 have a problem with views, when I open the camera and take the photo it sends me directly to the home screen, the same happens with an image of the gallery, this only happens with ios, since Android works without any problem. I would like to know what is happening because I have not found the error.
public async Task TakePicture()
{
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await Application.Current.MainPage.DisplayAlert("Error", "No se encontro una cámara disponible.", "OK");
return;
}
var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
SaveToAlbum = false,
CompressionQuality = 30,
PhotoSize = PhotoSize.Small
});
if (file == null)
{
return;
}
byte[] array;
using (var memoryStream = new MemoryStream())
{
int count = 0;
file.GetStream().CopyTo(memoryStream);
array = memoryStream.ToArray();
while (count < 10)
{
if (array.Count() == 0)
{
file.GetStream().CopyTo(memoryStream);
array = memoryStream.ToArray();
await Task.Delay(1000);
}
count++;
}
}
Stream stream = new MemoryStream(array);
var image = ImageSource.FromStream(() => stream);
FotoPerfil = image;
User.Foto = array;
}
This part is to take the photo directly from the cell phone, I have no problem opening the camera, the error comes when I choose that photo sends me to another screen, I do not know if it is closing and reopening the application but I do not know what happens.
public async Task PickPicture()
{
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsPickPhotoSupported)
{
await Application.Current.MainPage.DisplayAlert("Error",
"No se otorgaron permisos para accesar a las fotos.", "OK");
return;
}
var file = await CrossMedia.Current.PickPhotoAsync(new PickMediaOptions
{
PhotoSize = PhotoSize.Medium,
CompressionQuality = 30,
});
if (file == null)
{
return;
}
byte[] array;
using (var memoryStream = new MemoryStream())
{
int count = 0;
file.GetStream().CopyTo(memoryStream);
array = memoryStream.ToArray();
while (count < 10)
{
if (array.Count() == 0)
{
file.GetStream().CopyTo(memoryStream);
array = memoryStream.ToArray();
await Task.Delay(1000);
}
count++;
}
}
await Application.Current.MainPage.DisplayAlert("Error", array.ToString(), "OK");
User.Foto = array;
Stream stream = new MemoryStream(array);
var image = ImageSource.FromStream(() => stream);
FotoPerfil = image;
}
The latter is to select any image from the gallery, and exactly the same happens.
I have a function On my wcf service it returns Image as Bytes
I didnt Find any idea on how to display it in my Image Control
How can i Convert Those Bytes to an Image And thanks !
Here is my WCF Function:
public List<Data.Product> Show_P()
{
DataTable Table = new DataTable();
List<Data.Product> MyProductsLIST = new List<Data.Product>();
Table = Sp.SelectData("Show_Products", null);
if (Table.Rows.Count > 0)
for (int i = 0; i < Table.Rows.Count; i++)
{
Data.Product Log = new Data.Product();
Log._ID = Convert.ToInt32(Table.Rows[i]["ID"]);
Log._Name = Table.Rows[i]["Name"].ToString();
Log._Price = Table.Rows[i]["Price"].ToString();
Log._Qte = Table.Rows[i]["Qte"].ToString();
Log._CAT = Convert.ToInt32(Table.Rows[i]["Cat"]);
Log._Vote = Convert.ToInt32(Table.Rows[i]["Vote"]);
Log._Image = (byte[])Table.Rows[i]["Image"];
MyProductsLIST.Add(Log);
}
return MyProductsLIST;
}
And in my uwp :
public static List<Products> Get_Products()
{
MspService.Service1Client Serv = new MspService.Service1Client();
MspService.Product[] Product = Serv.Show_PAsync().Result.Show_PResult;
List<Products> Produc = new List<Design_TesTiNg.MenuBox.Products>();
for (int i = 0; i < Product.Length; i++)
{
Products Prod = new Products();
Prod._ID = Product[i]._ID;
Prod._Name = Product[i]._Name;
Prod._Price = Product[i]._Price;
Prod._Qte = Product[i]._Qte;
Prod._CAT = Product[i]._CAT;
Prod._Vote = Product[i]._Vote;
Prod._Image = Product[i]._Image;
Prod.ms = new MemoryStream(Prod._Image);
Convert(Prod.ms,Prod._Img);
Produc.Add(Prod);
}
return Produc;
}
So I tried to convert it that way :
public static async void Convert(MemoryStream mem, BitmapImage Img)
{
IRandomAccessStream a1 = await ConvertToRandomAccessStream(mem);
Img = new BitmapImage();
await Img.SetSourceAsync(a1);
}
public static async Task<IRandomAccessStream> ConvertToRandomAccessStream(MemoryStream memoryStream)
{
var randomAccessStream = new InMemoryRandomAccessStream();
var outputStream = randomAccessStream.GetOutputStreamAt(0);
var dw = new DataWriter(outputStream);
var task = Task.Factory.StartNew(() => dw.WriteBytes(memoryStream.ToArray()));
await task;
await dw.StoreAsync();
await outputStream.FlushAsync();
return randomAccessStream;
}
it returns Image as Bytes I didnt Find any idea on how to display it in my Image Control
From your code Log._Image = (byte[])Table.Rows[i]["Image"];, I think your Bytes means byte array here. I think problem is you need to know how your images are converted from image to byte arrays. I assumed that your wcf is for saving data (include byte arrays of images) to table and retrieve them, your converting images to byte arrays work is still done in the UWP app, then I've tested your code, if I convert image to byte array in UWP app in this way:
var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/1.jpeg"));
var b64 = await ConvertStorageFileToBase64String(file);
private async Task<byte[]> ConvertStorageFileToBase64String(StorageFile File)
{
var stream = await File.OpenReadAsync();
using (var dataReader = new DataReader(stream))
{
var bytes = new byte[stream.Size];
await dataReader.LoadAsync((uint)stream.Size);
dataReader.ReadBytes(bytes);
return bytes;
}
}
And convert back using your method like this:
MemoryStream mem = new MemoryStream(b64);
IRandomAccessStream a1 = await ConvertToRandomAccessStream(mem);
var Img = new BitmapImage();
await Img.SetSourceAsync(a1);
myimg.Source = Img; //myimg is the name of the image control.
The image can be correctly showed in image control. So if your code can't work by your side, please update your code for converting image to byte array, or maybe you can upload your sample so can we have a test.
I create livetiles with the following code:
// wide 310x150
var tileXml = TileUpdateManager.GetTemplateContent(TileTemplateType.TileWide310x150PeekImage03);
tileXml.GetElementsByTagName(textElementName).LastOrDefault().InnerText = string.Format(artist + " - " + trackname);
var image = tileXml.GetElementsByTagName(imageElementName).FirstOrDefault();
if (image != null)
{
var src = tileXml.CreateAttribute("src");
if (albumart == String.Empty)
src.Value = "Assets/onemusic_logo_wide.scale-240.png";
else
src.Value = albumart;
image.Attributes.SetNamedItem(src);
}
// square 150x150
var squaredTileXml = TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquare150x150PeekImageAndText01);
squaredTileXml.GetElementsByTagName(textElementName).FirstOrDefault().InnerText = string.Format(artist + " - " + trackname);
image = squaredTileXml.GetElementsByTagName(imageElementName).LastOrDefault();
if (image != null)
{
var src = squaredTileXml.CreateAttribute("src");
if (albumart == String.Empty)
src.Value = "Assets/onemusic_logo_square.scale-240.png";
else
src.Value = albumart;
image.Attributes.SetNamedItem(src);
}
updater.Update(new TileNotification(tileXml));
updater.Update(new TileNotification(squaredTileXml));
The problem I face is that the images shown on the livetile aren't sharp (in the app they are). I think this is because of the 310x150 pixels size of the template. I looked at the templates, there aren't any higher resolution ones. Is there a way to make the images sharper?
I noticed that providing an image with a resolution of exactly 744x360 pixels solves the problem. So I wrote this function to resize my albumarts (maybe it will come in handy for someone);
private async static Task<string> CropAndSaveImage(string filePath)
{
const string croppedimage = "cropped_albumart.jpg";
// read file
StorageFile file = await StorageFile.GetFileFromPathAsync(filePath);
if (file == null)
return String.Empty;
// create a stream from the file and decode the image
var fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream);
// create a new stream and encoder for the new image
using (InMemoryRandomAccessStream writeStream = new InMemoryRandomAccessStream())
{
// create encoder
BitmapEncoder enc = await BitmapEncoder.CreateForTranscodingAsync(writeStream, decoder);
enc.BitmapTransform.InterpolationMode = BitmapInterpolationMode.Linear;
// convert the entire bitmap to a 744px by 744px bitmap
enc.BitmapTransform.ScaledHeight = 744;
enc.BitmapTransform.ScaledWidth = 744;
enc.BitmapTransform.Bounds = new BitmapBounds()
{
Height = 360,
Width = 744,
X = 0,
Y = 192
};
await enc.FlushAsync();
StorageFile albumartfile = await ApplicationData.Current.LocalFolder.CreateFileAsync(croppedimage, CreationCollisionOption.ReplaceExisting);
using (var stream = await albumartfile.OpenAsync(FileAccessMode.ReadWrite))
{
await RandomAccessStream.CopyAndCloseAsync(writeStream.GetInputStreamAt(0), stream.GetOutputStreamAt(0));
}
// return image path
return albumartfile.Path;
}
}