How to resize an image in Xamarin.Forms (iOS, Android and WP)?

FredyWengerFredyWenger CHInsider ✭✭✭✭✭

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 :sunglasses:

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
    }
}

Posts

  • FredyWengerFredyWenger CHInsider ✭✭✭✭✭

    Additional note:
    The code is for a shared-project.
    So... if you work with a PCL, I think, the "#if's" won't work and you have to separate the code to the platforms.
    But I think, this should not be a big problem...
    Thanks @MitchMilam for the hint :blush:

  • PD.6026PD.6026 USMember ✭✭

    @FredyWenger , Do you have any example for achieving this in PCL ?

  • FredyWengerFredyWenger CHInsider ✭✭✭✭✭

    @PD.6026:
    Unfortunately no...
    But, as I wrote, you will have to separate the code in the #if's to the (your) platform-code.

  • aarthidlaarthidl USMember ✭✭

    @FredyWenger How to use this code with in Xamarin.forms?

  • FredyWengerFredyWenger CHInsider ✭✭✭✭✭

    @aarthidl:

    I don't really understand the question :wink:
    This code is for Xamarin.Forms.
    Please just read the description in the first message of this thread in detail :smile: .

  • aarthidlaarthidl USMember ✭✭

    @FredyWenger i can't use UIImage in my code ,
    which reference can i use?

  • FredyWengerFredyWenger CHInsider ✭✭✭✭✭

    @aarthidl:
    If I interpret your message correct, you have an error-message, that UIImage is not found in your code?

    I'm not a iOS-specialist, but - I think - therefore the following iOS-usings are needed:

    #if __IOS__
    using System.Drawing;
    using UIKit;
    using CoreGraphics;
    #endif
    

    The "#"-statements only works in a Shared-project (not in a PCL).
    If you use a shared-project, and have implemented it exactly like described in the example, it should work.
    If you work with a PCL, you have do implement it on another way (you have to overtake the code between the #-statements in your platform-code).
    As I don't work with PCL, I can't give you an exact example, how to do this.
    But I'm sure, that other users already have implemented it in a PCL.

    Maybe somebody can post an example, how to implement it in a PCL-project...?

  • RogerSchmidlinRogerSchmidlin CHUniversity ✭✭✭

    @FredyWenger I am just wondering why you don't use the Image class to handle it all? I have a ListView with my images that are much larger. All I do is this code in my xaml:

    The aspect ratio is set true by default and it resizes my images automatically.
    The only problem that I got is wanting to save my thumbnails locally. At the moment I reference to some internet source. So I need to load them resize them and save them locally. Then I can use them in the ListView without it to do all the work.

  • FredyWengerFredyWenger CHInsider ✭✭✭✭✭

    @RogerSchmidlin:
    Unfortunately I don't see any code / xaml in your message :smirk:
    The target is, do really downscale/downsize them (e.g. size 8 MB -> 2 KB) to use the smaller image (in my case to submit it for storing it a SQL-Server) and - this for all platforms.
    Is this possible with your (hidden :wink: ) line..?
    If yes, please post again with visible line ( :smiley:

  • RogerSchmidlinRogerSchmidlin CHUniversity ✭✭✭

    @FredyWenger No hidden xaml code :blush: The image gets resized for display purpose by default. But of course only in the listview. My source points to the internet. The images can be more than 1 MB big, but they downscale in my listview. But if I understand correctly, you are storing your images in your DB. In that case you do want to "really downscale" them :wink:
    where ThumbNailVideo is a http:// path to my image on the internet.

  • FredyWengerFredyWenger CHInsider ✭✭✭✭✭

    @RogerSchmidlin:

    No hidden xaml code

    In your message, after the line:

    All I do is this code in my xaml:

    I don't see any content (at least not with IE and FF).
    I think, there should be a statement here...?

    And.. the problem is not to be able to show a "big" image on a "small" page (here you're right, that is handled in the image-class :smile: ), the problem/target of the code is, to really downscale the image (make it smaller).

  • ChiragVashishtChiragVashisht INMember

    Can anyone implemented image resizer code on windows phone 8.1? Anyone has idea, please share.......

  • BrianRepettiBrianRepetti USUniversity ✭✭✭

    @ChiragVashisht , you want to get the WriteableBitmap extension from Nuget.

    WriteableBitmap wb = new WriteableBitmap(yourBitmap);
    wb.Resize(desiredWidth, desiredHeight, WriteableBitmapExtensions.Interpolation.Bilinear);

  • @breps I have installed the WriteableBitmap extension from Nuget, but not found suitable constructor of WriteableBitmap which takes argument Bitmap. It is taking two arguments of pixelWidth and pixelHeight. One more thing, Currently I am passing byte array of image which I want to use for resize.
    Also, I have tried the following code to resize:

    public async Task<byte[]> ResizeImage(byte[] imageData, float width, float height)
    {
    try
    {

                WriteableBitmap wb;
                using (var ms = new MemoryStream(imageData))
                {
                    using (var randomStream = ms.AsRandomAccessStream())
                    {
                        var decoder = await BitmapDecoder.CreateAsync(randomStream);
    
                        wb = new WriteableBitmap((int)decoder.PixelWidth, (int)decoder.PixelHeight);
                    }
                    wb.FromByteArray(imageData);
                    var cd = wb.Resize(Convert.ToInt32(width), Convert.ToInt32(height),
                        WriteableBitmapExtensions.Interpolation.Bilinear).ToByteArray();
    
                    //var ab = cd.ToByteArray();
                    return cd;
                }
            }
            catch (Exception ex)
            {
            }
    

    }
    Here, I am getting out of memory exception. I have stucked in this issue....

  • BrianRepettiBrianRepetti USUniversity ✭✭✭
  • MadhumithaMMadhumithaM INMember
    edited October 2015

    I have created an image inside button, in want to increase my image size alone.

    My code:

  • MadhumithaMMadhumithaM INMember
    edited October 2015

    I have created an image inside button, in want to increase my image size alone.

    My code:
    <Button x:Name="ActivityButton" Image="Aktivieter.png" VerticalOptions="Center" WidthRequest="{StaticResource ActivityButtonWidth}" Style="{StaticResource ActvityButtonStyle}" Clicked="ActivityButton_OnClicked" />

  • DanielLDanielL PLInsider ✭✭✭✭

    If you want an image replacements which can automatically resize/downsample images, you could try: https://github.com/molinch/FFImageLoading. Then, just set DownsampleWidth or DownsampleHeight property.

  • MadhumithaMMadhumithaM INMember
    edited October 2015

    Thanks Daniel..
    I have used **Scale property **to increase the image size inside button.

    <Button x:Name="ActivityButton" Scale="1.5" Image="Aktivieter.png" VerticalOptions="Center" WidthRequest="{StaticResource ActivityButtonWidth}" Style="{StaticResource ActvityButtonStyle}" Clicked="ActivityButton_OnClicked" />

  • MiguelCervantesMiguelCervantes MXMember ✭✭✭

    @DanielL hi mate! does your plugin resizes the image for uploading or just at loading it for displaying it?

  • DanielLDanielL PLInsider ✭✭✭✭
    edited January 2016

    @MiguelCervantes Hi! Currently FFImageLoading supports only downscaling of images which will be displayed, you can also export displayed image with GetImageAsJpgAsync method (or Png).

  • PriscilaCostaPriscilaCosta ARMember

    Hi Guys,

    I'm developing a very simple app for WP RTM in which you could pick an image from the sd card.
    After selected the image I want to resize the image and save it on the camera roll directory. The resize function is commented for now.

    This is my code:

    mediaPicker = await CrossMedia.Current.PickPhotoAsync();
    
    byte[] image;
    using (MemoryStream ms = new MemoryStream())
    {
        mediaPicker.GetStream().CopyTo(ms);
        image = ms.ToArray();
    }
    
    StorageFolder picsFolder = KnownFolders.CameraRoll;
    StorageFile file = await picsFolder.CreateFileAsync("myImage_" + DateTime.Now.Ticks.ToString() + ".jpg", CreationCollisionOption.ReplaceExisting);
    
    /*for testing purpose*/
    int width = 1456;
    int height = 2592;
    /*********************/
    
    WriteableBitmap b = new WriteableBitmap(width, height);
    b.FromByteArray(image);
    //b = b.Resize((int)resWidth, (int)resHeight, WriteableBitmapExtensions.Interpolation.Bilinear);
    
    using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
    {
        BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
        Stream pixelStream = b.PixelBuffer.AsStream();
        byte[] pixels = new byte[pixelStream.Length];
        await pixelStream.ReadAsync(pixels, 0, pixels.Length);
        encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)b.PixelWidth, (uint)b.PixelHeight,
            96.0,
            96.0,
            pixels);
        await encoder.FlushAsync();
    }
    

    The image variable is a byte[] array, I'm using the media plugin to pick the file.
    The thing is that the image is saved ok but its is blank like the one attached.
    Can you give me a hint please?
    Thanks!

  • HaithemHasniHaithemHasni CAMember ✭✭

    Take a look at this http://stackoverflow.com/questions/36009021/uwp-how-to-resize-an-image
    I think it would help you

  • PriscilaCostaPriscilaCosta ARMember

    Hi Haithem

    Thanks a lot. Now it is working with the link you submitted.

  • FredyWengerFredyWenger CHInsider ✭✭✭✭✭

    @PriscilaCosta
    You should "Like" postings that have helped you (like - I think - the posting from Haithem) :smirk:

  • CostasAletrariCostasAletrari USMember ✭✭

    Hi all i now have this working using a PCL and Dependancy service

    here is what i have done

    first i created an interface called IImageService in the PCL project

    public interface IImageService { byte[] ResizeTheImage(byte[] imageData, float width, float height); }

    then i created a class in the android projected called ResizeImage which inherits IImageService

    `
    [assembly: Dependency(typeof(CarraraDirectoryApp.Droid.ResizeImage))]

    namespace CarraraDirectoryApp.Droid
    {
    public class ResizeImage : IImageService
    {
    public byte[] ResizeTheImage(byte[] imageData, float width, float height)
    {
    Bitmap originalImage = BitmapFactory.DecodeByteArray(imageData, 0, imageData.Length);
    Bitmap resizedImage = Bitmap.CreateScaledBitmap(originalImage, (int)width, (int)height, false);

            using (MemoryStream ms = new MemoryStream())
            {
                resizedImage.Compress(Bitmap.CompressFormat.Jpeg, 100, ms);
                return ms.ToArray();
            }
        }
    
    }
    

    }`

    I then done the same in IOS created a called and inherited from IImageService

    `[assembly: Dependency(typeof(CarraraDirectoryApp.IOS.ResizeImage))]

    namespace CarraraDirectoryApp.IOS
    {
    public class ResizeImage : IImageService
    {

        public byte[] ResizeTheImage(byte[] imageData, float width, float height)
        {
            UIImage originalImage = ImageFromByteArray(imageData);
            UIImageOrientation orientation = originalImage.Orientation;
    
            //create a 24bit RGB image
            using (CGBitmapContext context = new CGBitmapContext(IntPtr.Zero,
                                                 (int)width, (int)height, 8,
                                                 (int)(4 * width), CGColorSpace.CreateDeviceRGB(),
                                                 CGImageAlphaInfo.PremultipliedFirst))
            {
    
                RectangleF imageRect = new RectangleF(0, 0, width, height);
    
                // draw the image
                context.DrawImage(imageRect, originalImage.CGImage);
    
                UIKit.UIImage resizedImage = UIKit.UIImage.FromImage(context.ToImage(), 0, orientation);
    
                // save the image as a jpeg
                return resizedImage.AsJPEG().ToArray();
            }
        }
    
        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;
        }
    
    
    
    }
    

    }`

    so now i call the interface

    ` var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
    {
    Directory = "Sample",
    Name = "test.jpg"
    });

            if (file == null)
                return;
    
            using (var memoryStream = new MemoryStream())
            {
                file.GetStream().CopyTo(memoryStream);
                var myfile = memoryStream.ToArray();
                mysfile = myfile;
                file.Dispose();
    
             //   ProductImage = file;
    
            }
    
           byte[] resizedImage = DependencyService.Get<IImageService>().ResizeTheImage(mysfile, 100, 100);
    
           mysfile = resizedImage;
    
    
           this.SpecialImagetxt.Source = ImageSource.FromStream(() => new MemoryStream(resizedImage));`
    

    i can now post the image to my webapi which saved the image to the filesystem on the server and creates a url for me to use in my list/details pages:smile:smile:
    hope this helps someone

  • ChaoticKingdomsChaoticKingdoms ESMember

    @CostasAletrari Your code has a flaw as float rounding can cause problems with some images. Instead of:

    using (CGBitmapContext context = new CGBitmapContext (IntPtr.Zero,
            (int)width, (int)height, 8,
            (int)(4 * width), CGColorSpace.CreateDeviceRGB (),
            CGImageAlphaInfo.PremultipliedFirst)) {
    ...
    }
    

    the following should be done to avoid some crashes:

    int intWidth = (int)width;
    int intHeihgt = (int)height;
    using (CGBitmapContext context = new CGBitmapContext (IntPtr.Zero, 
        intWidth, intHeihgt, 8, 
        4 * intWidth, CGColorSpace.CreateDeviceRGB (), 
        CGImageAlphaInfo.PremultipliedFirst)) {
    ...
    }
    

    I hope it helps some people to avoid crashes with this code.

  • ViniciusSchneiderViniciusSchneider USMember ✭✭

    I was wondered due not saw any simple solution to resize, flip, etc, to imagens with XF PCL!

    I'm a newbie but with 2 months of experience, I was at 1 step to develop a new library to Xamarin, but I did not believe not exists that!!!

    Well, I would to create a DependencyService because I saw many projets to IOS and ANDROID and seems easy to it. But...

    Finally I reached this code ready! I implemented in 5 minutes, correcting the not declared "MYSFILE" variable, and are working now!

    I will get off the redundant declarations and develop new methods to scale resize, or resize mantaining aspect ratio. If the code seems good and anyone wants, I publish here.

    Thank you for the help! I'm using in a complex system, with rest services over web and sockets (sockets was forget by developers to Rest services - no documentation!?)

    Sorry for my poor english, I'm a brazilian.

  • ViniciusSchneiderViniciusSchneider USMember ✭✭

    My Droid class to preserve aspect ratio without change Interface (to it just put the size "0" in the width or height and a new correct aspect ratio value will be used).

    This is a ugly code with new variable to easy understanding:

    (insert a code is not working here!!!)

    public class ResizeImage : IImageService
    {
    public byte[] ResizeTheImage(byte[] imageData, float width, float height)
    {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.InJustDecodeBounds = false; //default should be false, but... (true returns null to "originalImage" just setting options)

            Bitmap originalImage = BitmapFactory.DecodeByteArray(imageData, 0, imageData.Length, options);
    
            int newWidth=0;
            int newHeight=0;
    
            if (width == 0 && height == 0)
                return null;
    
            if (width == 0) //resizes to a width in the correct aspect ratio            
            {
                newHeight = (int)height;
                newWidth = (int)(height * options.OutWidth / options.OutHeight);
            }
            else
            {
                if (height == 0) //resizes to a height in the correct aspect ratio            
                {
                    newWidth = (int)width;
                    newHeight = (int)(width * options.OutHeight / options.OutWidth);
                }
                else
                {
                    newHeight = (int)height;
                    newWidth = (int)width;
                }
            }
    
    
    
    
            Bitmap resizedImage = Bitmap.CreateScaledBitmap(originalImage, newWidth, newHeight, false);
    
            using (MemoryStream ms = new MemoryStream())
            {
                resizedImage.Compress(Bitmap.CompressFormat.Jpeg, 100, ms);
                return ms.ToArray();
            }
        }
    
    }
    
  • ViniciusSchneiderViniciusSchneider USMember ✭✭

    Code without "easylification". Now, need to do same for iOS:

    ` public byte[] ResizeTheImage(byte[] imageData, float width, float height)
    {
    BitmapFactory.Options options = new BitmapFactory.Options();
    Bitmap originalImage = BitmapFactory.DecodeByteArray(imageData, 0, imageData.Length, options);

            if (width == 0 && height == 0)
                return null;
    
            if (width == 0) //resizes to a width in the correct aspect ratio            
                width = height * options.OutWidth / options.OutHeight;
            else
                if (height == 0) //resizes to a height in the correct aspect ratio            
                    height = width * options.OutHeight / options.OutWidth;                    
    
            Bitmap resizedImage = Bitmap.CreateScaledBitmap(originalImage, (int)width, (int)height, false);
    
            using (MemoryStream ms = new MemoryStream())
            {
                resizedImage.Compress(Bitmap.CompressFormat.Jpeg, 100, ms);
                return ms.ToArray();
            }
        }
    

    `

  • ViniciusSchneiderViniciusSchneider USMember ✭✭

    New iOS class, I not tested due not have a iMac working here now, but should works fine ( I not undertand why cast int before CGBitmap, but I implemented as recommended):

    `

    public byte[] ResizeTheImage(byte[] imageData, float width, float height)
    {
    if (width == 0 && height == 0)
    return null;

            UIImage originalImage = ImageFromByteArray(imageData);
            UIImageOrientation orientation = originalImage.Orientation;
    
            if (width == 0) //resizes to a width in the correct aspect ratio            
                width = (float)(height * originalImage.Size.Width / originalImage.Size.Height);
            else
                if (height == 0) //resizes to a height in the correct aspect ratio            
                height = (float)(width * originalImage.Size.Height / originalImage.Size.Width);
    
    
            //create a 24bit RGB image
    
    
            int intWidth = (int)width;
            int intHeihgt = (int)height;
            using (CGBitmapContext context = new CGBitmapContext(IntPtr.Zero,
                                intWidth, intHeihgt, 8,
                                4 * intWidth, CGColorSpace.CreateDeviceRGB(),
                                CGImageAlphaInfo.PremultipliedFirst))
            {
    
                RectangleF imageRect = new RectangleF(0, 0, width, height);
    
                // draw the image
                context.DrawImage(imageRect, originalImage.CGImage);
    
                UIKit.UIImage resizedImage = UIKit.UIImage.FromImage(context.ToImage(), 0, orientation);
    
                // save the image as a jpeg
                return resizedImage.AsJPEG().ToArray();
            }
        }
    

    `

  • Malcolm.JackMalcolm.Jack ZAMember ✭✭

    @FredyWenger - hope you don't mind, I've taken the liberty of adding the code to github, and creating a nuget package
    https://github.com/InquisitorJax/Wibci.Xamarin.Images
    https://www.nuget.org/packages/Wibci.Xamarin.Images/
    Support for Android / iOS / UWP

    ... as an additional note to those landing on this thread, if you're looking to resize images that come from the device or from the camera, @JamesMontemagno Media Plugin does that now
    https://github.com/jamesmontemagno/MediaPlugin

  • ZuhaibShahZuhaibShah USMember

    i am unable to find this using Android.Graphics.
    please help

  • ThomasKlockerThomasKlocker USMember ✭✭

    @Malcolm.Jack thanks for the Link to the MediaPlugin Lib. Works great, but i have one Problem: I´m using the PickPhoto function like this:

    var photo = await CrossMedia.Current.PickPhotoAsync(new Plugin.Media.Abstractions.PickMediaOptions()
    {
    PhotoSize = Plugin.Media.Abstractions.PhotoSize.Medium
    });

    After that, i save the photo to Disk. But the saved photo is the same size as the photo which was picked from the user. I wanted to get the choosen picture smaller in Size.
    Do you have any idea why the Picture still is the same size as the choosen picture (about 2500 x 1900 pixels).

    Thanks for your help
    Greetings

    Thomas

  • Malcolm.JackMalcolm.Jack ZAMember ✭✭

    @ThomasKlocker have you played around with other sizes?
    According to the source code, specifying medium will half the size of the original photo.
    try specify small - or if you're looking for a specific resolution, use CustomPhotoSize parameter on the options.
    what's the size if you don't specify null options?

  • ThomasKlockerThomasKlocker USMember ✭✭
    edited February 2017

    @Malcolm.Jack thanks for your help. The size doesn´t change, also if i supply a custom size.
    I think i´m using the lib wrong. That is my code:

    `
    var options = new Plugin.Media.Abstractions.PickMediaOptions()
    {
    PhotoSize = Plugin.Media.Abstractions.PhotoSize.Medium
    };

                var photo = await CrossMedia.Current.PickPhotoAsync(options);
    
                if(null == photo)
                    return;
    
                //save file to disk
                IFile photoFile = await CreateUniqueFileForImage();
                using(Stream src = photo.GetStream())
                {
                    using(System.IO.Stream dest = await photoFile.OpenAsync(FileAccess.ReadAndWrite))
                    {
                        int readCount = 0;
                        var buffer = new byte[8192];
                        while((readCount = src.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            dest.Write(buffer, 0, readCount);
                        }
                    }
                }`
    

    The CreateUniqueFileForImage() just calls CreateFileAsync to create a new file with a unique file name.
    All the IFile stuff i use is from the PCLStorage package.

    Maybe you see what i´m doing wrong. Again: thank you very much for your help

    Greetings
    Thomas

  • Malcolm.JackMalcolm.Jack ZAMember ✭✭

    @ThomasKlocker can't see anything explicitly wrong with the code - I use the same GetStream() to assign a memory stream in my code.

  • ThomasKlockerThomasKlocker USMember ✭✭

    I´ve tested it now on a iPhone, and it seems to work pretty well there. But on UWP it doesn´t. So i think it´s a bug / missing feature for the UWP Platform...

    Thanks for your help Malcolm.Jack

  • SametErapSametErap USMember

    @CostasAletrari

    I tried your PCL code, but there is one thing that is not working.

    `
    using (var memoryStream = new MemoryStream()){
    _mediaFile.GetStream().CopyTo(memoryStream);

                _mediaFile.Dispose();
                var myfile = memoryStream.ToArray();
    
                byte[] resizedImage = await DependencyService.Get<IImageService>()
                .ResizeImageAsync(myfile, 100, 100, ImageFormat.JPG);
    
                FileImage.Source = ImageSource.FromStream(
                () => new MemoryStream(resizedImage));
    
            } `
    

    When you say memoryStream.ToArray(), width and height are always 1, so there is nothing to show in ImageController.

    Even if you do this,

    FileImage.Source = ImageSource.FromStream(() => new MemoryStream(myfile));

    This doesn't show the image. Do you have any solution for this ?

Sign In or Register to comment.