Java Android App - 如何将画布上的位图绘图保存为图像?检查代码?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18676311/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android App - How to save a bitmap drawing on canvas as image? Check code?
提问by prateek
I tried to use the following codes to
我尝试使用以下代码
- Draw on canvas
- Save the canvas on Image
- 在画布上绘制
- 将画布保存在图像上
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:
第二个代码主活动:
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;
}
}
采纳答案by JRowan
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
活动_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>
回答by Mohit Rakhra
There is a little add on in the above code. The above code is saving the pic in the storage. 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 callthis function just after this line
并在此行之后调用此函数
save.compress(Bitmap.CompressFormat.PNG, 100, ostream);
Now the saved bitmap is also visible in the Gallery
现在保存的位图也可以在 Gallery