Creating an Empty Bitmap and Drawing Though Canvas in Android

Creating an empty bitmap and drawing though canvas in Android

This is probably simpler than you're thinking:

int w = WIDTH_PX, h = HEIGHT_PX;

Bitmap.Config conf = Bitmap.Config.ARGB_8888; // see other conf types
Bitmap bmp = Bitmap.createBitmap(w, h, conf); // this creates a MUTABLE bitmap
Canvas canvas = new Canvas(bmp);

// ready to draw on that bitmap through that canvas

Here's the official documentation on the topic: Custom Drawing

Creating a bitmap of a View that never gets drawn

Thanks to both @Rafael Toledo and @Roman_Donchenko, I figured out the issue. The problem was that my custom view was doing the drawing in the onDraw method which doesn't get called. In my case, I simply needed to perform the drawing done in the onDraw directly to the canvas and then used the bitmap passed to the canvas. My code ended up being:

public Bitmap getBitmapFromCircleView(CircleView v)
{
Bitmap bitmap = Bitmap.createBitmap(v.getLayoutParams().width, v.getLayoutParams().height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
v.drawToCanvas(canvas); //Method in the custom CircleView class, posted below
return bitmap;
}

public class CircleView extends View
{
... //Constructors

public Canvas drawToCanvas(Canvas canvas)
{
canvas.drawColor(0x00000000);

if(m_lineWidthPx == 0) //Previously set
return null;

int width = getLayoutParams().width;
int height = getLayoutParams().height;

float centerX = height / 2.f;
float centerY = height / 2.f;
float radius = width / 2.f - (m_lineWidthPx) / 2.f;
m_paint.setStrokeWidth(m_lineWidthPx);
m_paint.setStyle(Paint.Style.STROKE);
m_paint.setAntiAlias(true);
canvas.drawCircle(centerX, centerY, radius, m_paint);
return canvas;
}

@Override protected void onDraw(Canvas c)
{
... //Code here remained unchanged
}
}

Android: drawing on the Canvas and View (without Bitmap)

I've found non-trivial solution. I've inited the view by the constructor with 1 parameter. And then I inserted the custom view in the layout and called invalidate() when I needed it.

how do I create a huge, white bitmap with Canvas?

Naturally, you are limited by memory when you want to create huge bitmaps, but you have enough memory to create quite big bitmaps. For example, a 1024*1024 ARGB_8888 bitmap will need roughly 4 MB of memory, which is not a problem if your app is frugal with memory in general. The normal heap size for an Android app is usually between 16-32 MB depending on Android version, just to give you a feeling for what you have to play with.

You say you make a copy of large bitmap, and that might be your main problem. There's no need to make a copy of a large bitmap, you need only one. Here's a sample project that creates a large (1024*1024) white bitmap and draws a View in your app in the middle of it, and then writes the result to a PNG:

package com.example.android;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

public class WhitePngActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.draw_to_bitmap).setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Bitmap largeWhiteBitmap = Bitmap.createBitmap(1024, 1024, Bitmap.Config.ARGB_8888);

// Make a canvas with which we can draw to the bitmap
Canvas canvas = new Canvas(largeWhiteBitmap);

// Fill with white
canvas.drawColor(0xffffffff);

// Draw the view to the middle of the big white bitmap. In this
// case, it will be the button, but you can draw any View in
// your view hierarchy to the bitmap like this. And of course
// you can position the View anywhere you want
canvas.save();
canvas.translate(
largeWhiteBitmap.getWidth() / 2 - view.getWidth() / 2,
largeWhiteBitmap.getHeight() / 2 - view.getHeight() / 2);
view.draw(canvas);
canvas.restore();

// Write the file (don't forget android.permission.WRITE_EXTERNAL_STORAGE)
File pictureDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File pngFile = new File(pictureDir, "big-white-image-with-view.png");
try {
largeWhiteBitmap.compress(Bitmap.CompressFormat.PNG, 0, new FileOutputStream(pngFile));
} catch (FileNotFoundException e) {
Log.e("WhitePngActivity", "Could not write " + pngFile, e);
}

// Immediately release the bitmap memory to avoid OutOfMemory exception
largeWhiteBitmap.recycle();
}
});
}
}

Together with this main layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<Button
android:id="@+id/draw_to_bitmap"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Click to draw to bitmap" />

</LinearLayout>

You'll get a bitmap somewhere like /mnt/sdcard/Pictures/big-white-image-with-view.png that looks something like this:

Sample Image

Android creating a circle bitmap without drawing it on canvas

You can easily get a bitmap object using Bitmap static method (Bitmap.create) and then use that object to draw anything on it by instantiating a canvas object with bitmapObject.

your code should look something like this:

Bitmap bitmap = Bitmap.create(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
//draw on your canvas.


Related Topics



Leave a reply



Submit