[英]Android App - How to save a bitmap drawing on canvas as image? Check code?
I tried to use the following codes to 我尝试使用以下代码
Problem - When I try to save the image, it shows a null pointer error and nothing is saved. 问题 - 当我尝试保存图像时,它显示空指针错误,并且没有保存任何内容。
Please help me to find the problem with the code or suggest me an alternative, which does excatly the same. 请帮助我找到代码的问题或建议我一个替代方案,这是非常相似的。 Thanks in advance.
提前致谢。
Code to draw on canvas: 在画布上绘制的代码:
package com.example.draw2;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class MyDrawView extends View {
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
private Paint mPaint;
public MyDrawView(Context c, AttributeSet attrs) {
super(c, attrs);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFF000000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(9);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
public Bitmap getBitmap()
{
return mBitmap;
}
public void clear(){
mBitmap.eraseColor(Color.GREEN);
invalidate();
System.gc();
}
}
Second code to save the canvas as image is in main activity. 将画布保存为图像的第二个代码是主要活动。
I tried a few things and some part of the code is commented. 我尝试了一些东西,并对代码的某些部分进行了评论。
Since I am a beginner, I appreciate any advice 由于我是初学者,我感谢任何建议
Second code MainActivity: 第二代码MainActivity:
package com.example.draw2;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Environment;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends Activity
{
MyDrawView myDrawView;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
myDrawView = new MyDrawView(this, null);
setContentView(R.layout.activity_main);
Button button1 = (Button)findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
//View content = myDrawView;
//System.out.println(content);
//Bitmap bitmap = content.getDrawingCache();
File folder = new File(Environment.getExternalStorageDirectory().toString());
boolean success = false;
if (!folder.exists())
{
success = folder.mkdirs();
}
System.out.println(success+"folder");
File file = new File(Environment.getExternalStorageDirectory().toString() + "/sample.JPEG");
if ( !file.exists() )
{
try {
success = file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(success+"file");
FileOutputStream ostream = null;
try
{
ostream = new FileOutputStream(file);
System.out.println(ostream);
Bitmap save = myDrawView.getBitmap();
if(save == null) {
System.out.println("NULL bitmap save\n");
}
save.compress(Bitmap.CompressFormat.PNG, 100, ostream);
//bitmap.compress(Bitmap.CompressFormat.PNG, 100, ostream);
ostream.flush();
ostream.close();
}catch (NullPointerException e)
{
e.printStackTrace();
Toast.makeText(getApplicationContext(), "Null error", Toast.LENGTH_SHORT).show();
}
catch (FileNotFoundException e)
{
e.printStackTrace();
Toast.makeText(getApplicationContext(), "File error", Toast.LENGTH_SHORT).show();
}
catch (IOException e)
{
e.printStackTrace();
Toast.makeText(getApplicationContext(), "IO error", Toast.LENGTH_SHORT).show();
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
MyDrawView MyDrawView
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.LruCache;
import android.view.MotionEvent;
import android.view.View;
public class MyDrawView extends View {
public Bitmap mBitmap;
public Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
private Paint mPaint;
public MyDrawView(Context c, AttributeSet attrs) {
super(c, attrs);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFF000000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(9);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
public Bitmap getBitmap()
{
//this.measure(100, 100);
//this.layout(0, 0, 100, 100);
this.setDrawingCacheEnabled(true);
this.buildDrawingCache();
Bitmap bmp = Bitmap.createBitmap(this.getDrawingCache());
this.setDrawingCacheEnabled(false);
return bmp;
}
public void clear(){
mBitmap.eraseColor(Color.GREEN);
invalidate();
System.gc();
}
}
MainActivity 主要活动
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.os.Environment;
import android.view.Menu;
import android.view.View;
import android.view.View.MeasureSpec;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends Activity
{
MyDrawView myDrawView;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// myDrawView = new MyDrawView(this, null);
setContentView(R.layout.activity_main);
myDrawView = (MyDrawView)findViewById(R.id.draw);
Button button1 = (Button)findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
File folder = new File(Environment.getExternalStorageDirectory().toString());
boolean success = false;
if (!folder.exists())
{
success = folder.mkdirs();
}
System.out.println(success+"folder");
File file = new File(Environment.getExternalStorageDirectory().toString() + "/sample.png");
if ( !file.exists() )
{
try {
success = file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(success+"file");
FileOutputStream ostream = null;
try
{
ostream = new FileOutputStream(file);
System.out.println(ostream);
View targetView = myDrawView;
// myDrawView.setDrawingCacheEnabled(true);
// Bitmap save = Bitmap.createBitmap(myDrawView.getDrawingCache());
// myDrawView.setDrawingCacheEnabled(false);
// copy this bitmap otherwise distroying the cache will destroy
// the bitmap for the referencing drawable and you'll not
// get the captured view
// Bitmap save = b1.copy(Bitmap.Config.ARGB_8888, false);
//BitmapDrawable d = new BitmapDrawable(b);
//canvasView.setBackgroundDrawable(d);
// myDrawView.destroyDrawingCache();
// Bitmap save = myDrawView.getBitmapFromMemCache("0");
// myDrawView.setDrawingCacheEnabled(true);
//Bitmap save = myDrawView.getDrawingCache(false);
Bitmap well = myDrawView.getBitmap();
Bitmap save = Bitmap.createBitmap(320, 480, Config.ARGB_8888);
Paint paint = new Paint();
paint.setColor(Color.WHITE);
Canvas now = new Canvas(save);
now.drawRect(new Rect(0,0,320,480), paint);
now.drawBitmap(well, new Rect(0,0,well.getWidth(),well.getHeight()), new Rect(0,0,320,480), null);
// Canvas now = new Canvas(save);
//myDrawView.layout(0, 0, 100, 100);
//myDrawView.draw(now);
if(save == null) {
System.out.println("NULL bitmap save\n");
}
save.compress(Bitmap.CompressFormat.PNG, 100, ostream);
//bitmap.compress(Bitmap.CompressFormat.PNG, 100, ostream);
//ostream.flush();
//ostream.close();
}catch (NullPointerException e)
{
e.printStackTrace();
Toast.makeText(getApplicationContext(), "Null error", Toast.LENGTH_SHORT).show();
}
catch (FileNotFoundException e)
{
e.printStackTrace();
Toast.makeText(getApplicationContext(), "File error", Toast.LENGTH_SHORT).show();
}
catch (IOException e)
{
e.printStackTrace();
Toast.makeText(getApplicationContext(), "IO error", Toast.LENGTH_SHORT).show();
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
activity_main.xml activity_main.xml中
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<com.example.draw2.MyDrawView
android:id ="@+id/draw"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></com.example.draw2.MyDrawView>"
<Button
android:id ="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="save"
android:layout_alignParentBottom="true"
></Button>"
</RelativeLayout>
and in your AndroidManifest.xml make sure you have 并在你的AndroidManifest.xml中确保你有
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.draw2"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.draw2.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
There is a little add on in the above code. 上面的代码中有一点添加。 The above code is saving the pic in the storage.
上面的代码将pic保存在存储器中。 But the Image is not showing in the gallery.
但图像没有在画廊中显示。 To show the image in gallery just need to setup a
MediaScannerConnection
for the bitmap we are saving 要在图库中显示图像,只需为我们正在保存的位图设置
MediaScannerConnection
Sample Function 样本函数
public void scanPhoto(final String imageFileName) {
MediaScannerConnection msConn = new MediaScannerConnection(PaintPic.this,
new MediaScannerConnectionClient() {
public void onMediaScannerConnected() {
msConn.scanFile(imageFileName, null);
Log.i("msClient obj in Photo Utility",
"connection established");
}
public void onScanCompleted(String path, Uri uri) {
msConn.disconnect();
Log.i("msClient obj in Photo Utility", "scan completed");
}
});
msConn.connect();
}
and call this function just after this line 并在此行之后调用此函数
save.compress(Bitmap.CompressFormat.PNG, 100, ostream);
Now the saved bitmap is also visible in the Gallery
现在,在
Gallery
也可以看到保存的位图
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.