114

How can I get an image to a canvas in order to draw on that image?

Mahozad
  • 18,032
  • 13
  • 118
  • 133
Lana
  • 1,161
  • 3
  • 8
  • 5

7 Answers7

206

The good way to draw a Drawable on a canvas is not decoding it yourself but leaving it to the system to do so:

Drawable d = getResources().getDrawable(R.drawable.foobar, null);
d.setBounds(left, top, right, bottom);
d.draw(canvas);

This will work with all kinds of drawables, not only bitmaps. And it also means that you can re-use that same drawable again if only the size changes.

Gábor
  • 9,466
  • 3
  • 65
  • 79
  • How does one use an animation-list (multiple frames) for animation with the canvas approach? – RichieHH Jul 27 '14 at 14:53
  • 1
    Very useful! At least when you need just a background picture with no rocket science involved! – Asim Jan 06 '15 at 01:31
  • @RichieHH I have my background on a SurfaceView (propably a waste) and that surface view is embedded in a Framelayout and that framelayout contains ImageViews which I then animate - maybe that's an option for you? – AgentKnopf Apr 27 '15 at 08:08
  • 4
    getDrawable(id) is being deprecated, you should either use the ContextCompat call above, or the getDrawable(id, theme) call. https://developer.android.com/reference/android/content/res/Resources.html#getDrawable(int) – wblaschko Dec 02 '16 at 21:37
  • @Saveen: Are you sure? As far as I can remember, this is supposed to work from the earliest versions of Android. – Gábor Aug 18 '17 at 07:50
  • `setBounds(0, 0, width, height)` – vrgrg Feb 09 '21 at 13:10
40

You need to load your image as bitmap:

 Resources res = getResources();
 Bitmap bitmap = BitmapFactory.decodeResource(res, R.drawable.your_image);

Then make the bitmap mutable and create a canvas over it:

Canvas canvas = new Canvas(bitmap.copy(Bitmap.Config.ARGB_8888, true));

You then can draw on the canvas.

Konstantin Burov
  • 68,980
  • 16
  • 115
  • 93
  • What if my .png is big and it gets cut after being loaded? i.e. I don;t want to have it cropped. It can be bigger than the screen, then I will try to make it zoomable and movable. How may I do that? Thank you so so much! – Sibbs Gambling Jul 04 '13 at 08:52
  • 1
    @perfectionm1ng look at using BitmapRegionDecoder. It allows partial loading for big images. So you should be able to load only the part of image you're rendering at the moment. – Konstantin Burov Jul 05 '13 at 01:55
  • I have the same problem I am using the code Canvas cs = new Canvas(bitmap); Resources res = getResources(); Bitmap bitmapx = BitmapFactory.decodeResource(res, R.drawable.overlay_good_full); Bitmap bitmapxx = BitmapFactory.decodeResource(res, R.drawable.overlay_bad_full); if(text.equals("Good")) { cs.drawBitmap(bitmapx, 0, 0, tPaint); } else { cs.drawBitmap(bitmapxx, 0, 0, tPaint); } – Ahmad Arslan Feb 10 '14 at 06:06
  • How does creating new canvas object draw on the canvas of onDraw ? – Siddarth G Feb 12 '20 at 14:55
16

also you can use this way. it will change your big drawble fit to your canvas:

Resources res = getResources();
Bitmap bitmap = BitmapFactory.decodeResource(res, yourDrawable);
yourCanvas.drawBitmap(bitmap, 0, 0, yourPaint);
AzizAhmad
  • 637
  • 1
  • 9
  • 20
14
Drawable d = ContextCompat.getDrawable(context, R.drawable.***)
d.setBounds(left, top, right, bottom);
d.draw(canvas);
34m0
  • 5,755
  • 1
  • 30
  • 22
  • I create Drawable with gerResource().getDrawable(id); – Vikram Sep 23 '16 at 09:16
  • getDrawable(id) is being deprecated, you should either use the ContextCompat call above, or the getDrawable(id, theme) call. https://developer.android.com/reference/android/content/res/Resources.html#getDrawable(int) – wblaschko Dec 02 '16 at 21:36
  • 1
    For me, it was necessary to use `setBounds`. Without it, nothing got displayed. –  Feb 04 '17 at 18:30
8

try this

Bitmap mBitmap = Bitmap.createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter);

protected void onDraw(Canvas canvas) {
            canvas.drawColor(0xFFAAAAAA);
            canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);

        }
Rohit Mandiwal
  • 10,258
  • 5
  • 70
  • 83
  • But if i use canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); it works and it load the saved image on the canvas, but at the same time undo and redo stop working, Check my code http://pastebin.com/cP9w6stm – AndroidDev May 02 '13 at 09:52
3

To preserve the aspect ratio of my vector drawable I did this (in Kotlin):

val drawable = resources.getDrawable(R.drawable.my_vector, null)
val aspectRatio = drawable.intrinsicWidth.toFloat() / drawable.intrinsicHeight
val desiredWidthInPx = 100
val derivedHeightInPx = (desiredWidthInPx / aspectRatio).toInt()
drawable.setBounds(0, 0, desiredWidthInPx, derivedHeightInPx)
drawable.draw(canvas)
Mahozad
  • 18,032
  • 13
  • 118
  • 133
2
package com.android.jigsawtest;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class SurafaceClass extends SurfaceView implements
        SurfaceHolder.Callback {
    Bitmap mBitmap;
Paint paint =new Paint();
    public SurafaceClass(Context context) {
        super(context);
        mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        // TODO Auto-generated method stub

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // TODO Auto-generated method stub

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // TODO Auto-generated method stub

    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(Color.BLACK);
        canvas.drawBitmap(mBitmap, 0, 0, paint);

    }

}
user1140237
  • 5,015
  • 1
  • 28
  • 56