Hi all
In my app, there is a registration-page, where the user can register to have access to more functions.
Among other he can load an image, that then is showed as his avatar.
To select an image, I user the media-picker.
The problem was, that the stored images are a lot larger as the avatar (only 71 x 61).
So I had to search a solution, how to downscale an image with correct aspect-ratio to the needed resolution.
I have found an base-example here: https://developer.xamarin.com/samples/xamarin-forms/XamFormsImageResize/
First, thanks to the authors for that example!
As I then had some problems with the iOS-Code and had further needs, I have replaced the code to iOS (with the help of another user) and added some more functionality for my needs (target resolution and calculation of the resize to hold aspect-ratio.)
Now, it works as I need it
So... as I think (hope), that this may help some other users, I post the code here...
The implementation is very easy:
Just add the .cs-File t your project ad change the name-space in the .cs-file to your namespace.
You don't need to more, as the .cs-file contains #statements for the platform-stuff.
On the registration-page in my app:
- I show first a default-avatar-image (male / female) -> this is loaded from resources.
- The user that can click a button "load another image" and the select one over the media-picker
- The selected image then is scaled over the resizer and showed in an standard-image-object
- If the user tap on register-button and all data are valid, the resized image is submitted to our json-web-service and stored on a SQL-Server
Code-example on my registration-page:
byte[] resizedImage = ImageResizer.ResizeImage(imageData, iZielBreite, iZielHoehe); // in this byte-array the resized image is given back
Avatar.Source = ImageSource.FromStream(() => new MemoryStream(resizedImage)); / Show resized Image on an Image
where imageData contains the image that has to be resized (byte[]), iZielBreite is the target-width and iZielHoehe is the target-height.
Code-File (ImageResizer.cs):
Just copy it to a class-file in your shared-code and change namespace MatrixGuide to namespace 'your Namespace':
using System;
using System.Collections.Generic;
using System.Text;
using System;
using System.IO;
// Usings je Platform
#if __IOS__
using System.Drawing;
using UIKit;
using CoreGraphics;
#endif
#if __ANDROID__
using Android.Graphics;
#endif
#if WINDOWS_PHONE
using Microsoft.Phone;
using System.Windows.Media.Imaging;
#endif
namespace MatrixGuide
{
public static class ImageResizer
{
static ImageResizer()
{
}
public static byte[] ResizeImage(byte[] imageData, float width, float height)
{
#if __IOS__
return ResizeImageIOS(imageData, width, height);
#endif
#if __ANDROID__
return ResizeImageAndroid(imageData, width, height);
#endif
#if WINDOWS_PHONE
return ResizeImageWinPhone(imageData, width, height);
#endif
}
//
#if __IOS__
public static byte[] ResizeImageIOS(byte[] imageData, float width, float height)
{
// Load the bitmap
UIImage originalImage = ImageFromByteArray(imageData);
//
var Hoehe = originalImage.Size.Height;
var Breite = originalImage.Size.Width;
//
nfloat ZielHoehe = 0;
nfloat ZielBreite = 0;
//
if (Hoehe > Breite) // Höhe (71 für Avatar) ist Master
{
ZielHoehe = height;
nfloat teiler = Hoehe / height;
ZielBreite = Breite / teiler;
}
else // Breite (61 for Avatar) ist Master
{
ZielBreite = width;
nfloat teiler = Breite / width;
ZielHoehe = Hoehe / teiler;
}
//
width = (float)ZielBreite;
height = (float)ZielHoehe;
//
UIGraphics.BeginImageContext(new SizeF(width, height));
originalImage.Draw(new RectangleF(0, 0, width, height));
var resizedImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
//
var bytesImagen = resizedImage.AsJPEG().ToArray();
resizedImage.Dispose();
return bytesImagen;
}
//
public static UIKit.UIImage ImageFromByteArray(byte[] data)
{
if (data == null)
{
return null;
}
//
UIKit.UIImage image;
try
{
image = new UIKit.UIImage(Foundation.NSData.FromArray(data));
}
catch (Exception e)
{
Console.WriteLine("Image load failed: " + e.Message);
return null;
}
return image;
}
#endif
//
#if __ANDROID__
public static byte[] ResizeImageAndroid(byte[] imageData, float width, float height)
{
// Load the bitmap
Bitmap originalImage = BitmapFactory.DecodeByteArray(imageData, 0, imageData.Length);
//
float ZielHoehe = 0;
float ZielBreite = 0;
//
var Hoehe = originalImage.Height;
var Breite = originalImage.Width;
//
if (Hoehe > Breite) // Höhe (71 für Avatar) ist Master
{
ZielHoehe = height;
float teiler = Hoehe / height;
ZielBreite = Breite / teiler;
}
else // Breite (61 für Avatar) ist Master
{
ZielBreite = width;
float teiler = Breite / width;
ZielHoehe = Hoehe / teiler;
}
//
Bitmap resizedImage = Bitmap.CreateScaledBitmap(originalImage, (int)ZielBreite, (int)ZielHoehe, false);
//
using (MemoryStream ms = new MemoryStream())
{
resizedImage.Compress(Bitmap.CompressFormat.Jpeg, 100, ms);
return ms.ToArray();
}
}
#endif
//
#if WINDOWS_PHONE
public static byte[] ResizeImageWinPhone(byte[] imageData, float width, float height)
{
byte[] resizedData;
using (MemoryStream streamIn = new MemoryStream(imageData))
{
WriteableBitmap bitmap = PictureDecoder.DecodeJpeg(streamIn, (int)width, (int)height);
//
float ZielHoehe = 0;
float ZielBreite = 0;
//
float Hoehe = bitmap.PixelHeight;
float Breite = bitmap.PixelWidth;
//
if (Hoehe > Breite) // Höhe (71 für Avatar) ist Master
{
ZielHoehe = height;
float teiler = Hoehe / height;
ZielBreite = Breite / teiler;
}
else // Breite (61 für Avatar) ist Master
{
ZielBreite = width;
float teiler = Breite / width;
ZielHoehe = Hoehe / teiler;
}
//
using (MemoryStream streamOut = new MemoryStream())
{
bitmap.SaveJpeg(streamOut, (int)ZielBreite, (int)ZielHoehe, 0, 100);
resizedData = streamOut.ToArray();
}
}
return resizedData;
}
#endif
}
}