Как сохранить изображение с камеры?

Вот мой код:

package com.commonsware.android.skeleton; import android.app.Activity; import android.content.Context; import android.hardware.Camera; import android.hardware.Camera.*; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.Display; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.Window; import android.view.WindowManager; import android.widget.FrameLayout; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.List; // ---------------------------------------------------------------------- public class SimpleBulbActivity extends Activity { private Preview mPreview; private static final String TAG = "CameraDemo"; FrameLayout preview; Camera mCamera; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Hide the window title. requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.main); } protected void onResume() { super.onResume(); //Setup the FrameLayout with the Camera Preview Screen mPreview = new Preview(this); preview = (FrameLayout)findViewById(R.id.preview); preview.addView(mPreview); } public void snap() { mCamera.takePicture(shutterCallback, rawCallback, jpegCallback); } ShutterCallback shutterCallback = new ShutterCallback() { public void onShutter() { Log.d(TAG, "onShutter'd"); } }; PictureCallback rawCallback = new PictureCallback() { public void onPictureTaken(byte[] _data, Camera _camera) { Log.d(TAG, "onPictureTaken - raw"); } }; PictureCallback jpegCallback = new PictureCallback() { public void onPictureTaken(byte[] data, Camera _camera) { FileOutputStream outStream = null; try { // write to local sandbox file system // outStream = // CameraDemo.this.openFileOutput(String.format("%d.jpg", // System.currentTimeMillis()), 0); // Or write to sdcard outStream = new FileOutputStream(String.format( "/sdcard/%d.jpg", System.currentTimeMillis())); outStream.write(data); outStream.close(); Log.d(TAG, "onPictureTaken - wrote bytes: " + data.length); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { } Log.d(TAG, "onPictureTaken - jpeg"); } }; // ---------------------------------------------------------------------- class Preview extends SurfaceView implements SurfaceHolder.Callback { SurfaceHolder mHolder; Preview(Context context) { super(context); // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. mHolder = getHolder(); mHolder.addCallback(this); mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } public void surfaceCreated(SurfaceHolder holder) { // The Surface has been created, acquire the camera and tell it where // to draw. mCamera = Camera.open(); try { mCamera.setPreviewDisplay(holder); mCamera.setPreviewCallback(new PreviewCallback() { public void onPreviewFrame(byte[] data, Camera arg1) { FileOutputStream outStream = null; try { outStream = new FileOutputStream(Environment.getExternalStorageDirectory().toString()); outStream.write(data); outStream.close(); Log.d(TAG, "onPreviewFrame - wrote bytes: " + data.length); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { } Preview.this.invalidate(); } }); } catch (IOException e) { mCamera.release(); mCamera = null; e.printStackTrace(); } } public void surfaceDestroyed(SurfaceHolder holder) { // Surface will be destroyed when we return, so stop the preview. // Because the CameraDevice object is not a shared resource, it's very // important to release it when the activity is paused. mCamera.stopPreview(); mCamera.release(); mCamera = null; } 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; } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // Now that the size is known, set up the camera parameters and begin // the preview. Camera.Parameters parameters = mCamera.getParameters(); List<Size> sizes = parameters.getSupportedPreviewSizes(); Size optimalSize = getOptimalPreviewSize(sizes, w, h); Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay(); if(display.getRotation() == Surface.ROTATION_0) { parameters.setPreviewSize(optimalSize.height, optimalSize.width); mCamera.setDisplayOrientation(90); } if(display.getRotation() == Surface.ROTATION_90) { parameters.setPreviewSize(optimalSize.width, optimalSize.height); } if(display.getRotation() == Surface.ROTATION_180) { parameters.setPreviewSize(optimalSize.width, optimalSize.height); } if(display.getRotation() == Surface.ROTATION_270) { parameters.setPreviewSize(optimalSize.width, optimalSize.height); mCamera.setDisplayOrientation(0); } mCamera.setParameters(parameters); mCamera.startPreview(); } } } 

Хорошо, я немного изменил свой код.

У меня это в моем основном макете:

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/layout"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Camera Demo" android:textSize="24sp" /> <FrameLayout android:layout_weight="1" android:layout_width="fill_parent" android:layout_height="fill_parent"> <FrameLayout android:id="@+id/preview" android:layout_weight="1" android:layout_width="fill_parent" android:layout_height="fill_parent"> </FrameLayout> <ImageView android:src="@drawable/litbulb" android:layout_width="match_parent" android:layout_height="112dip" /> </FrameLayout> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/buttonClick" android:text="Snap!" android:layout_gravity="center"></Button> </LinearLayout> 

Когда я нажимаю «Snap!» buttonClick кнопку buttonClick , предполагается захват и сохранение изображения, но это не так. Может ли кто-нибудь помочь мне изменить этот код, чтобы он это сделал?

Кроме того, он падает каждый раз, когда я покидаю приложение. Вот соответствующие данные logcat:

 12-21 13:30:47.820: ERROR/AndroidRuntime(3906): FATAL EXCEPTION: main 12-21 13:30:47.820: ERROR/AndroidRuntime(3906): java.lang.RuntimeException: Method called after release() 12-21 13:30:47.820: ERROR/AndroidRuntime(3906): at android.hardware.Camera.setHasPreviewCallback(Native Method) 12-21 13:30:47.820: ERROR/AndroidRuntime(3906): at android.hardware.Camera.access$600(Camera.java:114) 12-21 13:30:47.820: ERROR/AndroidRuntime(3906): at android.hardware.Camera$EventHandler.handleMessage(Camera.java:519) 12-21 13:30:47.820: ERROR/AndroidRuntime(3906): at android.os.Handler.dispatchMessage(Handler.java:99) 12-21 13:30:47.820: ERROR/AndroidRuntime(3906): at android.os.Looper.loop(Looper.java:123) 12-21 13:30:47.820: ERROR/AndroidRuntime(3906): at android.app.ActivityThread.main(ActivityThread.java:4627) 12-21 13:30:47.820: ERROR/AndroidRuntime(3906): at java.lang.reflect.Method.invokeNative(Native Method) 12-21 13:30:47.820: ERROR/AndroidRuntime(3906): at java.lang.reflect.Method.invoke(Method.java:521) 12-21 13:30:47.820: ERROR/AndroidRuntime(3906): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858) 12-21 13:30:47.820: ERROR/AndroidRuntime(3906): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 12-21 13:30:47.820: ERROR/AndroidRuntime(3906): at dalvik.system.NativeStart.main(Native Method) 

 pre.camera.takePicture(shutterCallback, rawCallback, jpegCallback); PictureCallback rawCallback = new PictureCallback() { public void onPictureTaken(byte[] data, Camera camera) { System.out.println( "onPictureTaken - raw"); } }; /** Handles data for jpeg picture */ PictureCallback jpegCallback = new PictureCallback() { public void onPictureTaken(byte[] data, Camera camera) { BitmapFactory.Options options=new BitmapFactory.Options(); options.inSampleSize = 5; m=BitmapFactory.decodeByteArray(data,0,data.length,options); 

Просто взглянув на свой код, вам нужно передать свои обратные вызовы методу takePicture mPreview.getCamera (). TakePicture (shutterCallback, rawCallback, null, jpegCallback); Взгляните сюда для получения более подробной информации.

Ваша трассировка стека, кажется, предполагает, что она не знает, что делать, как только она сделала фотографию.

Также я подозреваю, что вы можете указывать на неправильный корневой каталог для записи … попробуйте это: Environment.getExternalStorageDirectory (). ToString ()

Вот:

 public class PictureSaver { private static final String TAG = "PictureSaver"; public static final int MEDIA_TYPE_IMAGE = 1; public static final int MEDIA_TYPE_VIDEO = 2; /** null if unable to save the file */ public static File savePicture(byte[] data, String folder_name) throws SaveFileException { File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE, folder_name); if (pictureFile == null){ Log.d(TAG, "Error creating media file, check storage permissions!"); throw new SaveFileException(TAG, "Error creating media file, check storage permissions!"); } try { FileOutputStream fos = new FileOutputStream(pictureFile); fos.write(data); fos.close(); } catch (FileNotFoundException e) { Log.d(TAG, "File not found: " + e.getMessage()); throw new SaveFileException(TAG, "File not found: " + e.getMessage()); } catch (IOException e) { Log.d(TAG, "Error accessing file: " + e.getMessage()); throw new SaveFileException(TAG, "Error accessing file: " + e.getMessage()); } return pictureFile; } /** Create a File for saving an image or video * null if unable to create the file */ private static File getOutputMediaFile(int type, String folder_name) throws SaveFileException { // To be safe, you should check that the SDCard is mounted // using Environment.getExternalStorageState() before doing this. File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES), folder_name); // This location works best if you want the created images to be shared // between applications and persist after your app has been uninstalled. // Create the storage directory if it does not exist if (! mediaStorageDir.exists()){ if (! mediaStorageDir.mkdirs()){ Log.d(TAG, "Unable to create directory!"); throw new SaveFileException(TAG, "Unable to create directory!"); } } // Create a media file name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); File mediaFile; if (type == MEDIA_TYPE_IMAGE){ mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_"+ timeStamp + ".jpg"); } else if(type == MEDIA_TYPE_VIDEO) { mediaFile = new File(mediaStorageDir.getPath() + File.separator + "VID_"+ timeStamp + ".mp4"); } else { throw new SaveFileException(TAG, "Unkknown media type!"); } Log.d(TAG,mediaStorageDir.getPath() + File.separator + "IMG_"+ timeStamp + ".jpg"); return mediaFile; }} 

Помните также, чтобы сделать что-то вроде:

 sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory()))); sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://"+ Environment.getExternalStorageDirectory()))); 

Если изображение было правильно сохранено. Таким образом, в следующий раз, когда пользователь откроет галерею или любое другое приложение для работы с мультимедиа, ваше вновь принятое изображение будет правильно указано.