展会信息港展会大全

Android双SurfaceView实现底部拍照,顶部绘图
来源:互联网   发布日期:2015-10-03 15:18:03   浏览:2361次  

导读:当SurfaceHolder对象的类型设置为SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS时就只能拍照不能绘制了。为了既能通过SurfaceView拍照又能在...

当SurfaceHolder对象的类型设置为SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS时就只能拍照不能绘制了。

为了既能通过SurfaceView拍照又能在上面绘制图形,可以通过双SurfaceView层叠的变通方式如下:

用于绘制的SurfaceView,使其透明并位于顶部:

[java]

package com.test;

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.graphics.PixelFormat;

import android.graphics.Rect;

import android.graphics.Paint.Style;

import android.util.AttributeSet;

import android.view.SurfaceHolder;

import android.view.SurfaceView;

public class SVDraw extends SurfaceView implements SurfaceHolder.Callback {

private Bitmap bmp;

private String imgPath = "";

protected SurfaceHolder sh; // 专门用于控制surfaceView的

private int width;

private int height;

// XML文件解析需要调用View的构造函数View(Context , AttributeSet)

// 因此自定义SurfaceView中也需要该构造函数

public SVDraw(Context context, AttributeSet attrs) {

super(context, attrs);

// TODO Auto-generated constructor stub

sh = getHolder();

sh.addCallback(this);

sh.setFormat(PixelFormat.TRANSPARENT); // 设置为透明

setZOrderOnTop(true);// 设置为顶端

}

@Override

public void surfaceChanged(SurfaceHolder arg0, int arg1, int w, int h) {

// TODO Auto-generated method stub

width = w;

height = h;

}

@Override

public void surfaceCreated(SurfaceHolder arg0) {

// TODO Auto-generated method stub

}

@Override

public void surfaceDestroyed(SurfaceHolder arg0) {

// TODO Auto-generated method stub

}

void clearDraw() {

Canvas canvas = sh.lockCanvas();

canvas.drawColor(Color.BLUE);// 清除画布

sh.unlockCanvasAndPost(canvas);

}

/**

* 绘制

*/

public void doDraw() {

if (bmp != null) {

Canvas canvas = sh.lockCanvas();

canvas.drawColor(Color.TRANSPARENT);// 这里是绘制背景

Paint p = new Paint(); // 笔触

p.setAntiAlias(true); // 反锯齿

p.setColor(Color.RED);

p.setStyle(Style.STROKE);

canvas.drawBitmap(bmp, 0, 0, p);

canvas.drawLine(width / 2 - 100, 0, width / 2 - 100, height, p);

canvas.drawLine(width / 2 + 100, 0, width / 2 + 100, height, p);

// ------------------------ 画边框---------------------

Rect rec = canvas.getClipBounds();

rec.bottom--;

rec.right--;

p.setColor(Color.GRAY); // 颜色

p.setStrokeWidth(5);

canvas.drawRect(rec, p);

// 提交绘制

sh.unlockCanvasAndPost(canvas);

}

}

public void drawLine() {

Canvas canvas = sh.lockCanvas();

canvas.drawColor(Color.TRANSPARENT);// 这里是绘制背景

Paint p = new Paint(); // 笔触

p.setAntiAlias(true); // 反锯齿

p.setColor(Color.RED);

p.setStyle(Style.STROKE);

canvas.drawLine(width / 2 - 100, 0, width / 2 - 100, height, p);

canvas.drawLine(width / 2 + 100, 0, width / 2 + 100, height, p);

// 提交绘制

sh.unlockCanvasAndPost(canvas);

}

public String getImgPath() {

return imgPath;

}

public void setImgPath(String imgPath) {

this.imgPath = imgPath;

// 根据路径载入目标图像

bmp = BitmapFactory.decodeFile(imgPath);

}

}

用于在SurfaceView(使其位于绘制SurfaceView底部)上拍照及预览的Activity:

[java]

package com.test;

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.OutputStream;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.Iterator;

import java.util.List;

import android.app.Activity;

import android.content.ContentValues;

import android.content.pm.ActivityInfo;

import android.graphics.Bitmap;

import android.graphics.Bitmap.Config;

import android.graphics.BitmapFactory;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Typeface;

import android.graphics.PixelFormat;

import android.hardware.Camera;

import android.hardware.Camera.PictureCallback;

import android.hardware.Camera.ShutterCallback;

import android.hardware.Camera.Size;

import android.media.AudioManager;

import android.media.ToneGenerator;

import android.net.Uri;

import android.os.Bundle;

import android.os.Environment;

import android.provider.MediaStore;

import android.provider.SyncStateContract.Constants;

import android.util.Log;

import android.view.SurfaceHolder;

import android.view.SurfaceView;

import android.view.View;

import android.view.Window;

import android.view.WindowManager;

import android.widget.Button;

public class SurfaceViewDraw extends Activity implements

SurfaceHolder.Callback, Camera.PictureCallback {

/** Called when the activity is first created. */

private SVDraw svDraw = null;

private SurfaceView svCamera = null;

protected SurfaceHolder mSurfaceHolder;

private Button btnClear;

private Button btnOpen;

private Button btnClose;

private Button btnTakePic;

private Button btnDraw;

private Camera mCamera; // 这个是hardware的Camera对象

private boolean isOpen = false;// 相机是否打开

private ToneGenerator tone;

private String imgPath;

private int width;

private int height;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

hideStatusBar();

setContentView(R.layout.main);

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);// 强制为横屏

svDraw = (com.test.SVDraw) findViewById(R.id.svDraw);

svCamera = (SurfaceView) findViewById(R.id.svCamera);

btnClear = (Button) findViewById(R.id.btnClear);

btnOpen = (Button) findViewById(R.id.btnOpen);

btnClose = (Button) findViewById(R.id.btnClose);

btnTakePic = (Button) findViewById(R.id.btnTakePic);

btnDraw = (Button) findViewById(R.id.btnDraw);

btnClear.setOnClickListener(new ClickEvent());

btnOpen.setOnClickListener(new ClickEvent());

btnClose.setOnClickListener(new ClickEvent());

btnTakePic.setOnClickListener(new ClickEvent());

btnDraw.setOnClickListener(new ClickEvent());

mSurfaceHolder = svCamera.getHolder();

mSurfaceHolder.addCallback(this);

// 当设置为SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS后就不能绘图了

mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

}

class ClickEvent implements View.OnClickListener {

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

if (v == btnClear) {

stopPreview(); // 停止预览后清屏速度会快一点

svDraw.setVisibility(View.INVISIBLE);

startPreview();// 清屏后启动预览

} else if (v == btnOpen) {

initCamera();

} else if (v == btnClose) {

closeCamera();

} else if (v == btnTakePic) {

if (isOpen) {

startPreview();// 防止异常

mCamera.takePicture(mShutterCallback, null, null,

mjpegCallback);

svDraw.setVisibility(View.VISIBLE);

svDraw.drawLine();// 拍照后绘制测线

}

} else if (v == btnDraw) {

svDraw.setVisibility(View.VISIBLE);

svDraw.doDraw();

}

}

}

ShutterCallback mShutterCallback = new ShutterCallback() {

@Override

public void onShutter() {

// TODO Auto-generated method stub

if (tone == null)

// 发出提示用户的声音

tone = new ToneGenerator(AudioManager.STREAM_MUSIC,

ToneGenerator.MAX_VOLUME);

tone.startTone(ToneGenerator.TONE_PROP_BEEP);

}

};

/**

* Jpeg格式压缩

*/

PictureCallback mjpegCallback = new PictureCallback() {

@Override

// 取得拍照图片

public void onPictureTaken(byte[] data, Camera camera) {

// TODO Auto-generated method stub

// 拍照前关闭预览

mCamera.stopPreview();

// 取得图像路径

imgPath = saveFile2(data);

svDraw.setImgPath(imgPath);

}

};

/**

* draw information on the picture

*

* @param imgPath

*/

public void drawInfo(String imgPath) {

Bitmap bmp = BitmapFactory.decodeFile(imgPath);

if (bmp != null) {

Bitmap drawBmp = Bitmap.createBitmap(640, 480, Config.ARGB_8888);

Canvas c = new Canvas(drawBmp);

Paint p = new Paint();

c.drawBitmap(bmp, 0, 0, p);

String familyName = "Arial";

Typeface font = Typeface.create(familyName, Typeface.NORMAL);

p.setColor(Color.RED);

p.setTypeface(font);

p.setTextSize(20);

p.setStyle(Paint.Style.STROKE);

SimpleDateFormat dateFormat = new SimpleDateFormat(

"yyyy-MM-dd hh:mm:ss");

String strDate = dateFormat.format(new Date());

c.drawText(strDate, 10, 30, p);

try {

saveBmp(drawBmp, imgPath);

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

/**

* save bmp as jpg by path

*

* @param bmpPath

* @param bmp

* @throws IOException

*/

public void saveBmp(Bitmap bmp, String fileName) throws IOException {

File f = new File(fileName);

f.createNewFile();

FileOutputStream fOut = null;

try {

fOut = new FileOutputStream(f);

} catch (FileNotFoundException e) {

e.printStackTrace();

}

bmp.compress(Bitmap.CompressFormat.JPEG, 100, fOut);

try {

fOut.flush();

} catch (IOException e) {

e.printStackTrace();

}

try {

fOut.close();

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* return imgFilePath

*

* @param data

* @return

*/

private String saveFile2(byte[] data) {

File imgFileDir = getDir();

if (!imgFileDir.exists() && !imgFileDir.mkdirs()) {

Log.v("directory", "Can't create directory to save image.");

return null;

}

// 图像名称

SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddhhmmss");

String strDate = dateFormat.format(new Date());

String imgFileName = "img_" + strDate + ".jpg";

// 图像路径

String imgFilePath = imgFileDir.getPath() + File.separator

+ imgFileName;

File imgFile = new File(imgFilePath);

try {

FileOutputStream fos = new FileOutputStream(imgFile);

fos.write(data);

fos.close();

Log.v("directory", "New Image saved:" + imgFile);

} catch (Exception error) {

Log.d(Constants.ACCOUNT_NAME,

imgFileName + " not saved: " + error.getMessage());

}

//绘制拍照日期等

drawInfo(imgFilePath);

return imgFilePath;

}

/**

*

* @return

*/

private File getDir() {

File sdDir = Environment

.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);

// 创建图像需要保存的文件夹

return new File(sdDir, "Photo");

}

@Override

public void onPictureTaken(byte[] data, Camera camera) {

// TODO Auto-generated method stub

// data是一个原始的JPEG图像数据,

// 在这里我们可以存储图片,很显然可以采用MediaStore

// 注意保存图片后,再次调用stopPreview()停止预览,等待测量

Uri imageUri = this.getContentResolver().insert(

MediaStore.Images.Media.EXTERNAL_CONTENT_URI,

new ContentValues());

try {

OutputStream os = this.getContentResolver().openOutputStream(

imageUri);

os.write(data);

os.flush();

os.close();

} catch (Exception e) {

// TODO: handle exception

e.printStackTrace();

}

// 拍照后停止预览

mCamera.stopPreview();

}

@Override

public void surfaceCreated(SurfaceHolder holder) {

// TODO Auto-generated method stub

}

@Override

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {

// TODO Auto-generated method stub

width = w;

height = h;

}

@Override

public void surfaceDestroyed(SurfaceHolder holder) {

// TODO Auto-generated method stub

}

/**

* 关闭相机

*/

public void closeCamera() {

if (isOpen) {

mCamera.stopPreview();

mCamera.release();

mCamera = null;

isOpen = false;

}

}

/**

* 停止拍照预览

*/

public void stopPreview() {

if (isOpen) {

mCamera.stopPreview();

}

}

/**

* 启动拍照预览

*/

public void startPreview() {

if (isOpen) {

mCamera.startPreview();

}

}

/**

* 初始化相机

*/

public void initCamera() {

if (!isOpen) {

mCamera = Camera.open();

}

if (mCamera != null && !isOpen) {

try {

Camera.Parameters mParameters = mCamera.getParameters();

mParameters.setPictureFormat(PixelFormat.JPEG); // 设置照片格式

List<Size> sizes = mParameters.getSupportedPreviewSizes();

Size optimalSize = getOptimalPreviewSize(sizes, width, height);

mParameters.setPreviewSize(optimalSize.width,

optimalSize.height); // 大小

mParameters.setPictureSize(optimalSize.width,

optimalSize.height);

mParameters.set("jpeg-quality", 100);// 照片质量

// 首先获取系统设备支持的所有颜色特效,有复合我们的,则设置;否则不设置

List<String> colorEffects = mParameters

.getSupportedColorEffects();

Iterator<String> colorItor = colorEffects.iterator();

while (colorItor.hasNext()) {

String currColor = colorItor.next();

if (currColor.equals(Camera.Parameters.EFFECT_SOLARIZE)) {

mParameters

.setColorEffect(Camera.Parameters.EFFECT_SOLARIZE);

break;

}

}

mCamera.setParameters(mParameters);

mCamera.setPreviewDisplay(mSurfaceHolder);

mCamera.startPreview();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

isOpen = true;

}

}

private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {

final double ASPECT_TOLERANCE = 0.05;

double targetRatio = (double) w / h;

if (sizes == null)

return null;

Size optimalSize = null;

double minDiff = Double.MAX_VALUE;

int targetHeight = h;

// Try to find an size match aspect ratio and size

for (Size size : sizes) {

double ratio = (double) size.width / size.height;

if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)

continue;

if (Math.abs(size.height - targetHeight) < minDiff) {

optimalSize = size;

minDiff = Math.abs(size.height - targetHeight);

}

}

// Cannot find the one match the aspect ratio, ignore the requirement

if (optimalSize == null) {

minDiff = Double.MAX_VALUE;

for (Size size : sizes) {

if (Math.abs(size.height - targetHeight) < minDiff) {

optimalSize = size;

minDiff = Math.abs(size.height - targetHeight);

}

}

}

return optimalSize;

}

@Override

protected void onDestroy() {

// TODO Auto-generated method stub

super.onDestroy();

if (isOpen) {

closeCamera();

}

}

// 在 Activity.setCurrentView()之前调用

public void hideStatusBar() {

// 隐藏标题

requestWindowFeature(Window.FEATURE_NO_TITLE);

// 定义全屏参数

int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;

// 获得窗口对象

Window curWindow = this.getWindow();

// 设置Flag标示

curWindow.setFlags(flag, flag);

}

}

主界面main.xml:

[html]

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:orientation="horizontal" >

<!-- 对于自定义控件要指明的控件的包名与空间名,系统自带的控件不需要指定包名 -->

<FrameLayout

android:layout_width="640dip"

android:layout_height="480dip"

android:orientation="vertical" >

<SurfaceView

android:id="@+id/svCamera"

android:layout_width="fill_parent"

android:layout_height="fill_parent"/>

<com.test.SVDraw

android:id="@+id/svDraw"

android:layout_width="fill_parent"

android:layout_height="fill_parent"/>

</FrameLayout>

<LinearLayout

android:id="@+id/LinearLayout01"

android:layout_width="158dip"

android:layout_height="fill_parent"

android:layout_marginLeft="1dip"

android:layout_marginRight="1dip"

android:orientation="vertical"

android:background="@drawable/main_right_bg">

<Button

android:id="@+id/btnOpen"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:layout_marginTop="10dip"

android:text="打开相机"/>

<Button

android:id="@+id/btnClose"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="关闭相机"/>

<Button

android:id="@+id/btnTakePic"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="拍照" />

<Button

android:id="@+id/btnClear"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="预览"/>

<Button

android:id="@+id/btnDraw"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="绘制"/>

</LinearLayout>

</LinearLayout>

在res下新建文件夹drawable,并在其下面新建面板背景main_right_bg.xml:

[html]

<?xml version="1.0" encoding="utf-8"?>

<shape xmlns:android="http://schemas.android.com/apk/res/android"

android:shape="rectangle">

<gradient

android:startColor = "#666666"

android:centerColor="#000FFF"

android:endColor = "#666666"

android:angle = "270"/>

<corners

android:radius="4dip"/>

</shape>

AndroidManifest.xml:

[html] view plaincopy

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="com.test"

android:versionCode="1"

android:versionName="1.0" >

<uses-sdk android:minSdkVersion="8" />

<!-- 照相机权限 -->

<uses-permission android:name="android.permission.CAMERA" />

<uses-feature android:name="android.hardware.camera" />

<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />

<!-- 在SDCard中创建与删除文件权限 -->

<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

<!-- 往SDCard写入数据权限 -->

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<application

android:icon="@drawable/ic_launcher"

android:label="@string/app_name" >

<activity

android:name=".SurfaceViewDraw"

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>

作者:xinzheng_wang

赞助本站

人工智能实验室

相关热词: android开发 教程

AiLab云推荐
展开

热门栏目HotCates

Copyright © 2010-2024 AiLab Team. 人工智能实验室 版权所有    关于我们 | 联系我们 | 广告服务 | 公司动态 | 免责声明 | 隐私条款 | 工作机会 | 展会港