Taking picture from camera without preview

前端 未结 9 1267
北荒
北荒 2020-11-22 13:01

I am writing an Android 1.5 application which starts just after boot-up. This is a Service and should take a picture without preview. This app will log the ligh

9条回答
  •  情深已故
    2020-11-22 13:43

    Taking the Photo

    Get this working first before trying to hide the preview.

    • Correctly set up the preview
      • Use a SurfaceView (pre-Android-4.0 compatibility) or SurfaceTexture (Android 4+, can be made transparent)
      • Set and initialise it before taking the photo
      • Wait for the SurfaceView's SurfaceHolder (via getHolder()) to report surfaceCreated() or the TextureView to report onSurfaceTextureAvailable to its SurfaceTextureListener before setting and initialising the preview.
    • Ensure the preview is visible:
      • Add it to the WindowManager
      • Ensure its layout size is at least 1x1 pixels (you might want to start by making it MATCH_PARENT x MATCH_PARENT for testing)
      • Ensure its visibility is View.VISIBLE (which seems to be the default if you don't specify it)
      • Ensure you use the FLAG_HARDWARE_ACCELERATED in the LayoutParams if it's a TextureView.
    • Use takePicture's JPEG callback since the documentation says the other callbacks aren't supported on all devices

    Troubleshooting

    • If surfaceCreated/onSurfaceTextureAvailable doesn't get called, the SurfaceView/TextureView probably isn't being displayed.
    • If takePicture fails, first ensure the preview is working correctly. You can remove your takePicture call and let the preview run to see if it displays on the screen.
    • If the picture is darker than it should be, you might need to delay for about a second before calling takePicture so that the camera has time to adjust its exposure once the preview has started.

    Hiding the Preview

    • Make the preview View 1x1 size to minimise its visibility (or try 8x16 for possibly more reliability)

      new WindowManager.LayoutParams(1, 1, /*...*/)
      
    • Move the preview out of the centre to reduce its noticeability:

      new WindowManager.LayoutParams(width, height,
          Integer.MIN_VALUE, Integer.MIN_VALUE, /*...*/)
      
    • Make the preview transparent (only works for TextureView)

      WindowManager.LayoutParams params = new WindowManager.LayoutParams(
          width, height, /*...*/
          PixelFormat.TRANSPARENT);
      params.alpha = 0;
      

    Working Example (tested on Sony Xperia M, Android 4.3)

    /** Takes a single photo on service start. */
    public class PhotoTakingService extends Service {
    
        @Override
        public void onCreate() {
            super.onCreate();
            takePhoto(this);
        }
    
        @SuppressWarnings("deprecation")
        private static void takePhoto(final Context context) {
            final SurfaceView preview = new SurfaceView(context);
            SurfaceHolder holder = preview.getHolder();
            // deprecated setting, but required on Android versions prior to 3.0
            holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    
            holder.addCallback(new Callback() {
                @Override
                //The preview must happen at or after this point or takePicture fails
                public void surfaceCreated(SurfaceHolder holder) {
                    showMessage("Surface created");
    
                    Camera camera = null;
    
                    try {
                        camera = Camera.open();
                        showMessage("Opened camera");
    
                        try {
                            camera.setPreviewDisplay(holder);
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
    
                        camera.startPreview();
                        showMessage("Started preview");
    
                        camera.takePicture(null, null, new PictureCallback() {
    
                            @Override
                            public void onPictureTaken(byte[] data, Camera camera) {
                                showMessage("Took picture");
                                camera.release();
                            }
                        });
                    } catch (Exception e) {
                        if (camera != null)
                            camera.release();
                        throw new RuntimeException(e);
                    }
                }
    
                @Override public void surfaceDestroyed(SurfaceHolder holder) {}
                @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
            });
    
            WindowManager wm = (WindowManager)context
                .getSystemService(Context.WINDOW_SERVICE);
            WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                    1, 1, //Must be at least 1x1
                    WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                    0,
                    //Don't know if this is a safe default
                    PixelFormat.UNKNOWN);
    
            //Don't set the preview visibility to GONE or INVISIBLE
            wm.addView(preview, params);
        }
    
        private static void showMessage(String message) {
            Log.i("Camera", message);
        }
    
        @Override public IBinder onBind(Intent intent) { return null; }
    }
    

提交回复
热议问题