Skip to content
September 29, 2010 / Daniel Freeman

Dr Android Answers: Saving Camera Pictures to SQL lite

A couple of students need to take pictures, and store their pictures in the database.  This allowed them to easily associate (tag) other data to the each picture, and manage their pictures, access and remove them easily.  We store binary data in a database record using a BLOB.

The database helper class looks like this:-

package com.danielfreeman.android.classes;

import android.content.Context;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase;

public class MyDBHelper extends SQLiteOpenHelper {

	final protected static String DATABASE_NAME="pictures";

	public MyDBHelper(Context context) {
		super(context, DATABASE_NAME, null, 4);
	}

	@Override
	public void onCreate(SQLiteDatabase db) {
		db.execSQL("DROP TABLE storedImages;");
		db.execSQL("CREATE TABLE storedImages (_id INTEGER PRIMARY KEY, image BLOB, tag TEXT);");
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		if (oldVersion >= newVersion)
			return;

	    onCreate(db);
	}
}

I put the application inside a TabActivity. Although the camera preview gets a bit squashed up this way.  So the UI needs a bit of thought.  Nevertheless, here is the main Activity code, based on Marakana’s camera tutorial:-

package com.danielfreeman.android;

import com.danielfreeman.android.classes.Preview;
import com.danielfreeman.android.classes.MyDBHelper;

import android.app.TabActivity;
import android.content.ContentValues;
import android.content.pm.ActivityInfo;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TabHost;
import android.widget.TextView;
import android.widget.TabHost.TabSpec;

public class HelloCamera extends TabActivity {

  protected Preview preview;
  protected Button buttonClick;
  protected MyDBHelper myDBHelper;
  protected TabHost tabHost;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

    tabHost = getTabHost();
    newTab("gallery", null, R.id.tab0);
    newTab("camera", null, R.id.tab1);

    preview = new Preview(this);
    ((FrameLayout) findViewById(R.id.preview)).addView(preview);

    buttonClick = (Button) findViewById(R.id.buttonClick);
    buttonClick.setOnClickListener(new OnClickListener() {
      public void onClick(View v) {
        preview.camera.takePicture(shutterCallback, rawCallback, jpegCallback);
      }
    });

    myDBHelper = new MyDBHelper(this);
    readDatabase();
  }

  protected void newTab(String label, Drawable icon, int page) {
  	TabSpec tabSpec = tabHost.newTabSpec(label);
  	tabSpec.setIndicator(label,icon);
  	tabSpec.setContent(page);
  	tabHost.addTab(tabSpec);
  }

  // Called when shutter is opened
  ShutterCallback shutterCallback = new ShutterCallback() {
    public void onShutter() {
    }
  };

  // Handles data for raw picture
  PictureCallback rawCallback = new PictureCallback() {
    public void onPictureTaken(byte[] data, Camera camera) {
    }
  };

  // Handles data for jpeg picture
  PictureCallback jpegCallback = new PictureCallback() {
    public void onPictureTaken(byte[] data, Camera camera) {

    SQLiteDatabase db = myDBHelper.getReadableDatabase();
    ContentValues values = new ContentValues();
    values.put("image", data);
    db.insert("storedImages", "tag", values);
    preview.camera.startPreview();
    }
  };

  protected void readDatabase() {
	  TextView info = (TextView) findViewById(R.id.info);
	  info.setText("Integer.toString(cursor.getCount())");
	  SQLiteDatabase db = myDBHelper.getReadableDatabase();
	  Cursor cursor = db.rawQuery("SELECT * FROM storedImages ;", null);

	  info.setText(Integer.toString(cursor.getCount()));

	  if (cursor.getCount()>0) {
		  cursor.moveToNext();
		  ImageView image = (ImageView) findViewById(R.id.image);
		  byte[] data = cursor.getBlob(cursor.getColumnIndex("image"));
		  image.setImageBitmap(BitmapFactory.decodeByteArray(data, 0, data.length));
	  }
  }

}

I use a db.insert() method to put the jpeg data into the database.  Note that the readDatabase() class is very simple.  Although it retrieves the entire database, it only displays one image.

Finally, here is the Preview class:-

package com.danielfreeman.android.classes;

import java.io.IOException;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class Preview extends SurfaceView implements SurfaceHolder.Callback {

  SurfaceHolder mHolder;
  public Camera camera;

public 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);
  }

  // Called once the holder is ready
  public void surfaceCreated(SurfaceHolder holder) {
    // The Surface has been created, acquire the camera and tell it where
    // to draw.
    camera = Camera.open();
    try {
      camera.setPreviewDisplay(holder);

      camera.setPreviewCallback(new PreviewCallback() {
        // Called for each frame previewed
        public void onPreviewFrame(byte[] data, Camera camera) {
          Preview.this.invalidate();
        }
      });
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  // Called when the holder is destroyed
  public void surfaceDestroyed(SurfaceHolder holder) {
    camera.stopPreview();
    camera = null;
  }

  // Called when holder has changed
  public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    camera.startPreview();
  }

}

I haven’t included the layout file, as it probably needs rethinking, so you can probably come up with a better UI.  At the moment it’s wrapped up in a TabHost, a preview area (FrameLayout), and includes a Button called ‘buttonClick’.

Advertisements

10 Comments

Leave a Comment
  1. Jay / Oct 19 2011 2:10 am

    I have included Camera permissions in the manifest, but when I load this app on my HTC EVO the app crashes before its able to boot. What is a common problem that I attempt to investigate?

    • Daniel Freeman / Oct 20 2011 12:43 pm

      Does LogCat give you any clues? Worth checking that it’s not a known problem with your HTC device and the Camera. (HTC have been known to screw up with things like this). This is my usual checklist:-

      1. Make sure the manifest file points to your top class. Clean” (Eclipse drop down menu)
      4. Ensure that your references to drawables and strings exist.
      5. Check your layout XML syntax. Sometimes errors aren’t shown.

  2. rabia / Feb 24 2012 9:54 pm

    Hi Sir,

    I followed this tutorial but having errors as follow:

    02-24 21:50:10.646: E/ActivityThread(12681): start dispatch OnReceive message,mRegistered=false mCurOrdered=false intent=Intent { act=android.intent.action.PACKAGE_REMOVED dat=package:com.nya.camera flg=0x20000000 (has extras) } receiver = android.app.ApplicationContext$ApplicationPackageManager$PackageRemovedReceiver@2fb9c860

    Could you please guide me with this

    • Daniel Freeman / Feb 25 2012 2:49 am

      I’m not sure that’s the actual error diagnostic. That just seems to be telling me that a package removed intent was received. Does it say anything before that?

      In the manifest file, you have the permission to access the camera? Are you testing on a device?

  3. rabia / Feb 25 2012 10:02 am

    Sir thanks for you reply, yeah I am testing it on a device, I think the problem is with my Databases class, I am posting my DBAdapter and DBHelper class, I will be very thankful if you could please have a look at them:

    DBAapter class:

    package com.nya.camera;

    import android.content.Context;

    import android.database.SQLException;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteOpenHelper;

    public class DBAdapter{

    private static final String DATABASE_NAME = “pictures”;
    private static final int DATABASE_VERSION = 4;
    private final Context context;
    private DatabaseHelper1 DBHelper;

    private SQLiteDatabase db;

    public DBAdapter(Context ctx)
    {
    this.context = ctx;
    DBHelper = new DatabaseHelper1(context);
    }

    private static class DatabaseHelper1 extends SQLiteOpenHelper
    {
    DatabaseHelper1(Context context)
    {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
    // TODO Auto-generated method stub

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    // TODO Auto-generated method stub

    }
    }

    //—opens the database—
    public DBAdapter open() throws SQLException
    {
    db = DBHelper.getWritableDatabase();
    return this;
    }

    //—closes the database—
    public void close()
    {
    DBHelper.close();
    }
    }

    DBHelper class:

    package com.nya.camera;

    import android.content.Context;
    import android.database.sqlite.SQLiteOpenHelper;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteDatabase.CursorFactory;

    public class DBHelper extends SQLiteOpenHelper {

    // TODO Auto-generated constructor stub

    final protected static String DATABASE_NAME=”pictures”;

    public DBHelper(Context context) {

    super(context, DATABASE_NAME, null, 4);

    }

    @Override

    public void onCreate(SQLiteDatabase db) {

    db.execSQL(“DROP TABLE storedImages;”);

    db.execSQL(“CREATE TABLE storedImages (_id INTEGER PRIMARY KEY, image BLOB, tag TEXT);”);

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    if (oldVersion >= newVersion)

    return;

    onCreate(db);
    }
    }

    There might be a problem with my xml so i m posting that as well:

  4. rabia / Feb 25 2012 10:03 am

    Sir Please have look at this:

  5. rabia / Feb 25 2012 10:04 am
  6. rabia / Feb 25 2012 10:04 am

    Ohh Its not letting me post xml class.

  7. rabia / Feb 25 2012 10:10 am

Trackbacks

  1. Camera | Pearltrees

To discuss MadComponents/MC3D, join the Facebook group!

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: