【发布时间】:2015-02-22 15:54:30
【问题描述】:
我正在制作一个像 Snapchat 这样的应用程序,您可以在其中拍照、预览并在预览期间对其进行绘图。为了实现这一点,我使用了表面视图。
这是我的拍照和绘图代码
CameraActivity.java:
public class CameraActivity extends Activity {
public static final String TAG = CameraActivity.class.getSimpleName();
private android.hardware.Camera mCamera;
private CameraPreview mCameraPreview;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
mCamera = getCameraInstance();
mCameraPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mCameraPreview);
Button captureButton = (Button) findViewById(R.id.button_capture);
captureButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCamera.takePicture(null, null, mPicture);
}
});
}
/**
* Helper method to access the camera returns null if it cannot get the
* camera or does not exist
*
* @return
*/
private Camera getCameraInstance() {
Camera camera = null;
try {
camera = Camera.open();
} catch (Exception e) {
// cannot get camera or does not exist
}
return camera;
}
PictureCallback mPicture = new PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile();
if (pictureFile == null) {
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
} catch (IOException e) {
}
}
};
private static File getOutputMediaFile() {
File mediaStorageDir = new File(
Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"MyCameraApp");
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d("MyCameraApp", "failed to create directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
.format(new Date());
File mediaFile;
mediaFile = new File(mediaStorageDir.getPath() + File.separator
+ "IMG_" + timeStamp + ".jpg");
return mediaFile;
}
}
CameraPreview.java:
public class CameraPreview extends SurfaceView implements
SurfaceHolder.Callback {
public static final String TAG = CameraPreview.class.getSimpleName();
private SurfaceHolder mSurfaceHolder;
private android.hardware.Camera mCamera;
// Constructor that obtains context and camera
@SuppressWarnings("deprecation")
public CameraPreview(Context context, Camera camera) {
super(context);
this.mCamera = camera;
this.mSurfaceHolder = this.getHolder();
this.mSurfaceHolder.addCallback(this);
this.mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.startPreview();
tryDrawing(surfaceHolder);
} catch (IOException e) {
// left blank for now
}
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
mCamera.stopPreview();
mCamera.release();
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format,
int width, int height) {
// start preview with new settings
try {
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.startPreview();
tryDrawing(surfaceHolder);
} catch (Exception e) {
// intentionally left blank for a test
}
}
private void tryDrawing(SurfaceHolder surfaceHolder) {
Log.i(TAG, "Trying to draw...");
Canvas canvas = surfaceHolder.lockCanvas();
if (canvas == null) {
Log.e(TAG, "Cannot draw onto the canvas as it's null");
} else {
drawMyStuff(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
private void drawMyStuff(final Canvas canvas) {
Random random = new Random();
Log.i(TAG, "Drawing...");
canvas.drawRGB(255, 128, 128);
}
}
这非常适合拍照和预览,但是,当我尝试在画布上实际绘制时(也就是运行 CameraPreview.trydrawing() 方法),我收到此错误:
02-22 15:36:59.861 4261-4261/com.johncorser.selfiesnap I/CameraPreview﹕ Trying to draw...
02-22 15:36:59.861 4261-4261/com.johncorser.selfiesnap E/SurfaceHolder﹕ Exception locking surface
java.lang.IllegalArgumentException
at android.view.Surface.nativeLockCanvas(Native Method)
at android.view.Surface.lockCanvas(Surface.java:243)
at android.view.SurfaceView$4.internalLockCanvas(SurfaceView.java:814)
at android.view.SurfaceView$4.lockCanvas(SurfaceView.java:782)
at com.johncorser.selfiesnap.CameraPreview.tryDrawing(CameraPreview.java:63)
at com.johncorser.selfiesnap.CameraPreview.surfaceChanged(CameraPreview.java:54)
at android.view.SurfaceView.updateWindow(SurfaceView.java:583)
at android.view.SurfaceView.access$000(SurfaceView.java:86)
at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:175)
at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:847)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1867)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:996)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5600)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
at android.view.Choreographer.doCallbacks(Choreographer.java:574)
at android.view.Choreographer.doFrame(Choreographer.java:544)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
02-22 15:36:59.961 4261-4261/com.johncorser.selfiesnap E/CameraPreview﹕ Cannot draw onto the canvas as it's null
我在这里查看了堆栈溢出,基本上发现问题与相机锁定表面视图的事实有关,因此我无法锁定画布(因此它为空)。所以我想知道的是,有什么方法可以克服这个问题并能够在图像上绘图吗?
理想情况下,在图像上绘制的任何内容也将保存在文件中,但我也可以添加一个“保存”按钮来处理最有可能的逻辑?
【问题讨论】:
标签: android android-camera android-canvas surfaceview