Android中截图(surfaceView)

原创 2012年07月13日 23:47:38

   前几天,在网上总结了一个方法,实现了在Android当前Activity的截图,本人测试确实通过了,不过有朋友说截出来的图是黑色的,不能看。我心想,这没有问题啊,相同的代码我就可以执行通过,并没有没有在意这个问题。可是,今天我再调用那个方法时,截出来的图部分是黑屏。我当时就郁闷了。网上的东西很全,但同时很乱。有一个大神用的是引用Linux下编译出来的库,又用到什么JNI我完全不懂,貌似可以实现截屏。当时这个方法太麻烦,我看了一下觉得没有信心,就又继续寻找其他的方法。

   我截图出现黑屏的原因是在Activity中用到了SurfaceView控件,在XML布局中的控件可以完整的显示出来但是有surfaceView的时候就出现黑屏了。具体原因我想的是因为在surfaceView中用线程不停的绘图,操作太频繁了,原来那种方法没有办法截出来。在surfaceView中绘图的原理:

   用另外一个Canvas对象不停的把要画到surfaceView中的对象画到这个额外的canvas中,再声明一个Bitmap bitmap对象,注意这个bitmap不是你画在surfaceView中的对象,而是你的目标对象,就是需要截的图。你只需要这样:Canvas canvas=new Canvas(bitmap),接着用canvas.drawBitmap(curBitmap, 0, 0, null),你就可以把当前的的要画的到SurfaceView保存到bitmap中,然后把bitmap保存出来就可以了。PS:这只是截出来SurfaceView中图像,如果想截取背景图片,可以把surfaceView设置为透明。网上有很多种方法,这里就不介绍了。

贴出网上可以运行的代码:

  menu.xml:

  <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/screenshot" android:title="@string/screenshot"></item>
</menu>


 Element.java

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;

public class Element {
    private float mX;
    private float mY;

    private Bitmap mBitmap;

    public Element(Resources res, int x, int y) {
        mBitmap = BitmapFactory.decodeStream(new BufferedInputStream(res.openRawResource(R.drawable.icon)));
        mX = x - mBitmap.getWidth() / 2;
        mY = y - mBitmap.getHeight() / 2;
    }

    public void doDraw(Canvas canvas) {
        canvas.drawBitmap(mBitmap, mX, mY, null);
    }
}

Panel.java

 

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Environment;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class Panel extends SurfaceView implements SurfaceHolder.Callback
{

 public static float mWidth;
 public static float mHeight;

 private ViewThread mThread;
 private ArrayList<Element> mElements = new ArrayList<Element>();
 private int mElementNumber = 0;

 private Paint mPaint = new Paint();
 private String mScreenshotPath = Environment.getExternalStorageDirectory()
   + "/droidnova";

 public Panel(Context context)
 {
  super(context);
  getHolder().addCallback(this);
  mThread = new ViewThread(this);
  mPaint.setColor(Color.WHITE);
 }

 

 @Override
 public void surfaceChanged(SurfaceHolder holder, int format, int width,
   int height)
 {
  mWidth = width;
  mHeight = height;
 }

 @Override
 public void surfaceCreated(SurfaceHolder holder)
 {
  if (!mThread.isAlive())
  {
   mThread = new ViewThread(this);
   mThread.setRunning(true);
   mThread.start();
  }
 }

 @Override
 public void surfaceDestroyed(SurfaceHolder holder)
 {
  if (mThread.isAlive())
  {
   mThread.setRunning(false);
  }
 }

 @Override
 public boolean onTouchEvent(MotionEvent event)
 {
  synchronized (mElements)
  {
   mElements.add(new Element(getResources(), (int) event.getX(),
     (int) event.getY()));
   mElementNumber = mElements.size();
  }
  return super.onTouchEvent(event);
 }

 /**
  * If called, creates a screenshot and saves it as a JPG in the folder
  * "droidnova" on the sdcard.
  */
 //在surfaceView上不停的绘图
 public void doDraw(long elapsed, Canvas canvas)
 {
  canvas.drawColor(Color.BLACK);
  synchronized (mElements)
  {
   for (Element element : mElements)
   {
    element.doDraw(canvas);
   }
  }
  canvas.drawText("FPS: " + Math.round(1000f / elapsed) + " Elements: "
    + mElementNumber, 10, 10, mPaint);
 }
 public void saveScreenshot()
 {
  if (ensureSDCardAccess())
  {
   Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(),
     Bitmap.Config.ARGB_8888);
   Canvas canvas = new Canvas(bitmap);
   //在surfaceView上不停的绘图
   doDraw(1, canvas);
   File file = new File(mScreenshotPath + "/"
     + System.currentTimeMillis() + ".jpg");
   FileOutputStream fos;
   try
   {
    fos = new FileOutputStream(file);
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
    fos.close();
   }
   catch (FileNotFoundException e)
   {
    Log.e("Panel", "FileNotFoundException", e);
   }
   catch (IOException e)
   {
    Log.e("Panel", "IOEception", e);
   }
  }
 }

 /**
  * Helper method to ensure that the given path exists. TODO: check external
  * storage state
  */
 private boolean ensureSDCardAccess()
 {
  File file = new File(mScreenshotPath);
  if (file.exists())
  {
   return true;
  }
  else if (file.mkdirs())
  {
   return true;
  }
  return false;
 }
}

 

ScreenshotActivity.java

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.Window;

public class ScreenshotActivity extends Activity {
    private Panel mPanel;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        mPanel = new Panel(this);
        setContentView(mPanel);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.screenshot:
                mPanel.saveScreenshot();
                break;
        }
        return true;
    }
}

ViewThread.java

import android.graphics.Canvas;
import android.view.SurfaceHolder;

public class ViewThread extends Thread {
    private Panel mPanel;
    private SurfaceHolder mHolder;
    private boolean mRun = false;
    private long mStartTime;
    private long mElapsed;
   
    public ViewThread(Panel panel) {
        mPanel = panel;
        mHolder = mPanel.getHolder();
    }
   
    public void setRunning(boolean run) {
        mRun = run;
    }
   
    @Override
    public void run() {
        Canvas canvas = null;
        mStartTime = System.currentTimeMillis();
        while (mRun) {
            canvas = mHolder.lockCanvas();
            if (canvas != null) {
                mPanel.doDraw(mElapsed, canvas);
                mElapsed = System.currentTimeMillis() - mStartTime;
                mHolder.unlockCanvasAndPost(canvas);
            }
            mStartTime = System.currentTimeMillis();
        }
    }
}

 

  其实这很好理解。由于我的代码写在整个项目中,跌出来比较麻烦,就贴了一个以可以完整通过的工程。

下载地址:http://download.csdn.net/detail/yilip/4428045

关于截屏,暂时我的需求已经满足了,不知道这符合其他情况么?欢迎有兴趣的人一起交流。

安卓SurfaceView截屏

关于安卓SurfaceView截屏 2015.12.9号是一个值得记得日子,开始拖着背包从学校出来,挤上火车,做着接近30小时的硬座,来到了美丽的成都,那时候赵雷的还没火,‘走到玉林路的尽头 坐在小...
  • lzw136296634
  • lzw136296634
  • 2017年02月17日 17:27
  • 1273

Android完美实现截屏

很多app都有截屏的需求,当你遇到产品经理给你提出这个需求时,你搜索了一下: 1.取View的cacheDrawable 来实现截屏,这种方案,没有兼容性问题,但是缺点有两个: 不能截状态...
  • weizongwei5
  • weizongwei5
  • 2017年01月10日 11:40
  • 16108

Android中截图(surfaceView)

前几天,在网上总结了一个方法,实现了在Android当前Activity的截图,本人测试确实通过了,不过有朋友说截出来的图是黑色的,不能看。我心想,这没有问题啊,相同的代码我就可以执行通过,并没有没有...
  • yilip
  • yilip
  • 2012年07月13日 23:47
  • 19276

Android--SurfaceView截屏问题

 转载▼ 标签: it 分类: Android 一般的View截屏实现代码如下: View view = activity.getWin...
  • yuanyuan_186
  • yuanyuan_186
  • 2014年11月29日 21:14
  • 2017

Android应用截图和SurfaceView截图问题总结

最近在做android截图应用的过程遇到很多问题,接触了好些截图方法,但是还是不能实现SufaceView截图功能。今天就把我尝试过的方法总结下,希望把我惨痛的经历写出来后能够帮助到要做此功能的朋友少...
  • bboyfeiyu
  • bboyfeiyu
  • 2013年10月14日 18:19
  • 12719

Android中SurfaceView截屏

  • 2012年07月13日 23:45
  • 16KB
  • 下载

Android 截屏在surfaceview上失败的问题

项目中surfaceview,为了要透明效果不得不设置zorder。这个时候截屏 只能截到surfaceview以外的东西。 于是多加了一步操作 1、截出原有部分 2、画出surfaceview...
  • u013183495
  • u013183495
  • 2016年01月28日 15:01
  • 1400

Aandroid截屏遇到SurfaceView

最近做项目遇到个问题,网上搜索了一下,很多人也遇到这个问题,觉得很有必要拿出来说一下,做个总结!嗯,内容精华,千万别错过! 项目具体的需求说起来又要大费周章说半天,我就直接简单地说下我们的目的是什...
  • u012600955
  • u012600955
  • 2017年03月08日 16:00
  • 426

Android MediaProjection截屏与录屏(surfaceview截图)(一)

MediaProjection 和 MediaProjectionManager 是 Android 5.0 开放的屏幕截图与录制视频的接口,它可以用来对 surfaceview 进行截图,解决以前 ...
  • u010057266
  • u010057266
  • 2016年12月05日 21:11
  • 4114

SurfaceView截屏问题

做PPT截屏的时候遇到一个问题:显示content的View是SurfaceView做的,截屏时无法截取到内容,截取到的是一块黑色区域。    其实,原因就是SurfaceView的实现原理。Sur...
  • asan855
  • asan855
  • 2012年08月31日 18:17
  • 9763
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android中截图(surfaceView)
举报原因:
原因补充:

(最多只允许输入30个字)