Search code examples
c#androidxamarin.androidsurfaceview

Draw a fixed size bitmap image on canvas


I am creating a card game, for this i have created a custom surface view, in which images are getting load. Since images are downloaded from internet, they are of different sizes and looks visually bad on screen. I want to achieve two things here.

  1. Load images of fixed size or resize the images dynamically.
  2. Draw images from bottom of screen in upward direction.

For 1st point i used CreateBitmap method but getting below exception.

java.lang.OutOfMemoryError: Failed to allocate a 1915060280 byte allocation with 4194304 free bytes and 123MB until OOM error

To fixed the issue i thought of using Glide/Picasso based on this question and this, but i found out that Glide/Picasso load images only on imageview, but i don't have any imageview, i only got a custom surfaceview inside a linearlayout.

For 2nd point i used rotation of image. Following is the code of that.

  public  void Render(Canvas paramCanvas)
    {

        try
        {
            // paramCanvas.DrawColor(Android.Graphics.Color.Blue);


            int i = 0;
            Down_Card_Gap = 0;
            foreach (Cards localcard in FaceDownDeck.ToList())
            {


                Bitmap localimage = BitmapFactory.DecodeResource(Resources, localcard.GetImageId(context));  
                Bitmap rotatedimage = RotateBitmap(localimage, 180);
                paramCanvas.DrawBitmap(rotatedimage, (Screen_Center_X - Card_Width / 2)+Down_Card_Gap, (Screen_Height - Card_Height), null);
               //   paramCanvas.DrawBitmap(localimage, (Screen_Center_X - Card_Width / 2), (Screen_Center_Y - Card_Height), null);


                if (i++ == 7)
                { break; }
                if (Down_Card_Gap > 0)
                {
                    Down_Card_Gap += Card_Width / 2; 
                }
                else
                {
                    Down_Card_Gap -= Card_Width / 2;
                }
                Down_Card_Gap *= -1;
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.ToString());
        }
    }

    private Bitmap RotateBitmap(Bitmap localimage, float angle)
    {
         Matrix matrix = new Matrix();
        matrix.PostRotate(angle);
        matrix.PostScale(Card_Width, Card_Height);
        Bitmap resized= Bitmap.CreateBitmap(localimage, 0, 0, localimage.Width, localimage.Height, matrix, true);
        localimage.Recycle();
        return resized;
    }

I want to know if it is a right approach, or is there any better method achieve the functionality.


Solution

  • Load images of fixed size or resize the images dynamically.

    About the fixed size and resize, you can refer to this, find decodeFile method:

       protected Bitmap decodeFile(File f) {
            try { 
                //decode image size 
                BitmapFactory.Options o = new BitmapFactory.Options();
                o.inJustDecodeBounds = true;
                BitmapFactory.decodeStream(new FileInputStream(f), null, o);
    
                //Find the correct scale value. It should be the power of 2. 
                final int REQUIRED_SIZE = 150;
                int width_tmp = o.outWidth, height_tmp = o.outHeight;
                int scale = 1;
                while (true) { 
                    if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)
                        break; 
                    width_tmp /= 2;
                    height_tmp /= 2;
                    scale *= 2;
                } 
    
                //decode with inSampleSize 
                BitmapFactory.Options o2 = new BitmapFactory.Options();
                o2.inSampleSize = scale;
                return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
            } catch (FileNotFoundException e) {
            } 
            return null; 
        } 
    

    You can see, it uses BitmapFactory.Options.inJustDecodeBounds= true to preload the bitmap, and scale the bitmap. Also you can refer to official document. Read this to compress bitmap's quality.

    Except from this, you also need consider the picture cache.This talks about how to build an efficient memory cache for bitmaps.