Frage

I'm very new to Android and am trying to do something simple: using the camera API, I want to capture an image and save it to a directory.

I think my main problem is with the picturecallback() class. With this code I am able to save a jpeg image to a known directory on my SD card. I can see that it's in the correct location; however, the file size is 0 bytes and cannot be opened.

Here's my code:

    PictureCallback myPictureCallback_JPG = new PictureCallback(){

  @Override
  public void onPictureTaken(byte[] arg0, Camera arg1) {
   // TODO Auto-generated method stub

   if (arg0 == null){
       Toast.makeText(AndroidCamera.this,
                  "Image not saved.  ",
                  Toast.LENGTH_LONG).show();
       return;
       //Why is it returning NULL the first time and a 0-byte thing next...
   }


   File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
   if (pictureFile == null){
       System.out.println("Error creating media file, check storage permissions: ");
       return;
   }

//    
   Uri uriTarget = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, new ContentValues());

   try {

       FileOutputStream fos = new FileOutputStream(pictureFile);
       fos.write(arg0);
       fos.close();

    Toast.makeText(AndroidCamera.this,
      "Image saved: " + uriTarget.toString(),
      Toast.LENGTH_LONG).show();

   } catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }

   camera.startPreview();
  }};

When going through the debugger, the byte array arg0 seems to contain a lot of random numbers from -255 to 255. I'm not sure why any image values would apear negative other than that they were not actually captured correctly in the first place (capturing happens in oncreate).

Here is the main class:

package com.example.androidcamera;

import java.io.ByteArrayOutputStream;
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 com.example.androidcamera.R;

import android.app.Activity;
import android.content.ContentValues;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore.Images.Media;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;

public class AndroidCamera extends Activity implements SurfaceHolder.Callback{

 Camera camera;
 SurfaceView surfaceView;
 SurfaceHolder surfaceHolder;
 boolean previewing = false;
 LayoutInflater controlInflater = null;

 Button buttonTakePicture;

 final int RESULT_SAVEIMAGE = 0;
 public static final int MEDIA_TYPE_IMAGE = 1;
   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main);
       setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

       getWindow().setFormat(PixelFormat.UNKNOWN);
       surfaceView = (SurfaceView)findViewById(R.id.camerapreview);
       surfaceHolder = surfaceView.getHolder();
       surfaceHolder.addCallback(this);
       surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

       controlInflater = LayoutInflater.from(getBaseContext());
       View viewControl = controlInflater.inflate(R.layout.control, null);
       LayoutParams layoutParamsControl
        = new LayoutParams(LayoutParams.FILL_PARENT,
        LayoutParams.FILL_PARENT);
       this.addContentView(viewControl, layoutParamsControl);

       buttonTakePicture = (Button)findViewById(R.id.takepicture);
       buttonTakePicture.setOnClickListener(new Button.OnClickListener(){
           @Override
           public void onClick(View arg0) {
            // TODO Auto-generated method stub
            //camera.takePicture(myShutterCallback,
              //myPictureCallback_JPG, myPictureCallback_JPG);
               camera.takePicture(null, null, myPictureCallback_JPG);
           }
       });

       LinearLayout layoutBackground = (LinearLayout)findViewById(R.id.background);
       layoutBackground.setOnClickListener(new LinearLayout.OnClickListener(){

   @Override
   public void onClick(View arg0) {
    // TODO Auto-generated method stub

    buttonTakePicture.setEnabled(false);
    camera.autoFocus(myAutoFocusCallback);
    //camera.
   }});
   }

   AutoFocusCallback myAutoFocusCallback = new AutoFocusCallback(){

  @Override
  public void onAutoFocus(boolean arg0, Camera arg1) {
   // TODO Auto-generated method stub
   buttonTakePicture.setEnabled(true);
  }};

   ShutterCallback myShutterCallback = new ShutterCallback(){

  @Override
  public void onShutter() {
   // TODO Auto-generated method stub

  }};

 PictureCallback myPictureCallback_RAW = new PictureCallback(){

  @Override
  public void onPictureTaken(byte[] arg0, Camera arg1) {
   // TODO Auto-generated method stub

  }};

 PictureCallback myPictureCallback_JPG = new PictureCallback(){

  @Override
  public void onPictureTaken(byte[] arg0, Camera arg1) {
   // TODO Auto-generated method stub

   if (arg0 == null){
       Toast.makeText(AndroidCamera.this,
                  "Image not saved.  ",
                  Toast.LENGTH_LONG).show();
       return;
       //Why is it returning NULL the first time and a 0-byte thing next...
   }


   File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
   if (pictureFile == null){
       System.out.println("Error creating media file, check storage permissions: ");
       return;
   }

//    
   Uri uriTarget = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, new ContentValues());

   try {

       FileOutputStream fos = new FileOutputStream(pictureFile);
       fos.write(arg0);
       fos.close();

    Toast.makeText(AndroidCamera.this,
      "Image saved: " + uriTarget.toString(),
      Toast.LENGTH_LONG).show();

   } catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }

   camera.startPreview();
  }};

 @Override
 public void surfaceChanged(SurfaceHolder holder, int format, int width,
   int height) {
  // TODO Auto-generated method stub
  if(previewing){
   camera.stopPreview();
   previewing = false;
  }

  if (camera != null){
   try {
    camera.setPreviewDisplay(surfaceHolder);
    camera.startPreview();
    previewing = true;
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
 }

 @Override
 public void surfaceCreated(SurfaceHolder holder) {
  // TODO Auto-generated method stub
  camera = Camera.open();
 }

 @Override
 public void surfaceDestroyed(SurfaceHolder holder) {
  // TODO Auto-generated method stub
  camera.stopPreview();
  camera.release();
  camera = null;
  previewing = false;
 }

 /** Create a File for saving an image or video */
 private static File getOutputMediaFile(int type){
     // 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), "MyCameraApp");
     // 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("MyCameraApp", "failed to create directory");
             return null;
         }
     }

     // 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 {
         return null;
     }

     return mediaFile;
 }

 @Override
 protected void onPause() {
     super.onPause();
     releaseCamera();              // release the camera immediately on pause event
 }

 private void releaseCamera(){
     if (camera != null){
         camera.release();        // release the camera for other applications
         camera = null;
     }
 }

}

My AndroidManifest file:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.example.androidcamera"
     android:versionCode="1"
     android:versionName="1.0">
   <application android:icon="@drawable/ic_launcher" android:label="@string/app_name">
       <activity android:name="AndroidCamera"
                 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>
   <uses-sdk android:minSdkVersion="8" />
   <uses-permission android:name="android.permission.CAMERA"></uses-permission>
   <uses-feature android:name="android.hardware.camera" />
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
   <uses-feature android:name="android.hardware.camera.autofocus" />
</manifest>

And finally my main xml file:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:id="@+id/background"
   android:orientation="vertical"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   android:gravity="bottom"
   >
<Button
 android:id="@+id/takepicture" 
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text=" * Take Picture "
 android:layout_gravity="right"
 android:layout_margin="10dp"
 />
</LinearLayout>

Many thanks in advance.

War es hilfreich?

Lösung

Don't worry if the numbers in arg0[] look strange. This is because Java does not have an unsigned byte primitive data type.

In your file saving code, note that you display the Toast

"Image saved: " + uriTarget.toString()

while write() actually happens to

File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);

Probably you will find that the images are stored, but not where you expected them.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top