I want to change the area of camera scan. Now I take image to scan as big as screen of device. I'm trying to crop image to analyze. So just the center of preview will be source to scan. Is there any option to set captured preview to be smaller or creating Bitmap from byte[] data and crop it is the only way to get smaller area? I was trying to read something about it but documentation for Zbar Android is very poor (comparing to iOS).
Picture here:
https://postimg.cc/image/4wk4u0mln/
MainActivity
public class MainActivity extends Activity
{
private Camera mCamera;
private Context context;
private CameraPreview mPreview;
private Handler autoFocusHandler;
TextView scanText;
Button scanButton;
ImageScanner scanner;
private PowerManager.WakeLock wl;
private boolean barcodeScanned = false;
private boolean previewing = true;
static {
System.loadLibrary("iconv");
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
autoFocusHandler = new Handler();
mCamera = getCameraInstance();
context = getApplicationContext();
/* Instance barcode scanner */
scanner = new ImageScanner();
scanner.setConfig(0, Config.X_DENSITY, 3);
scanner.setConfig(0, Config.Y_DENSITY, 3);
mPreview = new CameraPreview(this, mCamera, previewCb, autoFocusCB);
FrameLayout preview = (FrameLayout)findViewById(R.id.cameraPreview);
preview.addView(mPreview);
scanText = (TextView)findViewById(R.id.scanText);
}
#Override
public void onPause() {
super.onPause();
releaseCamera();
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
onStart();
}
#Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
finish();
}
/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open();
} catch (Exception e){
}
return c;
}
private void releaseCamera() {
if (mCamera != null) {
previewing = false;
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
}
private Runnable doAutoFocus = new Runnable() {
#Override
public void run() {
if (previewing)
mCamera.autoFocus(autoFocusCB);
}
};
PreviewCallback previewCb = new PreviewCallback() {
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
Camera.Parameters parameters = camera.getParameters();
Size size = parameters.getPreviewSize();
//HERE we read taken picture from prieview
Image barcode = new Image(size.width, size.height, "Y800");
barcode.setData(data);
int result = scanner.scanImage(barcode);
if (result != 0) {
previewing = false;
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
SymbolSet syms = scanner.getResults();
for (Symbol sym : syms) {
if (sym.getType() == Symbol.CODE128) {
sym.getData());
MediaPlayer mp = MediaPlayer.create(context, R.raw.beep_ok);
mp.start();
} else {
MediaPlayer mp = MediaPlayer.create(context, R.raw.beep_wrong);
mp.start();
}
mCamera.setPreviewCallback(previewCb);
mCamera.startPreview();
previewing = true;
mCamera.autoFocus(autoFocusCB);
}
}
}
};
// Mimic continuous auto-focusing
AutoFocusCallback autoFocusCB = new AutoFocusCallback() {
#Override
public void onAutoFocus(boolean success, Camera camera) {
autoFocusHandler.postDelayed(doAutoFocus, 1000);
}
};
//Method to crop Bitmap in case of use
public Bitmap scaleCenterCrop(Bitmap source, int newHeight, int newWidth) {
int sourceWidth = source.getWidth();
int sourceHeight = source.getHeight();
float xScale = (float) newWidth / sourceWidth;
float yScale = (float) newHeight / sourceHeight;
float scale = Math.max(xScale, yScale);
float scaledWidth = scale * sourceWidth;
float scaledHeight = scale * sourceHeight;
float left = (newWidth - scaledWidth) / 2;
float top = (newHeight - scaledHeight) / 2;
RectF targetRect = new RectF(left, top, left + scaledWidth, top + scaledHeight);
Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, source.getConfig());
Canvas canvas = new Canvas(dest);
canvas.drawBitmap(source, null, targetRect, null);
return dest;
}
}
CameraPrieview.java
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
private PreviewCallback previewCallback;
private AutoFocusCallback autoFocusCallback;
public CameraPreview(Context context, Camera camera,
PreviewCallback previewCb,
AutoFocusCallback autoFocusCb) {
super(context);
mCamera = camera;
previewCallback = previewCb;
autoFocusCallback = autoFocusCb;
/*
* Set camera to continuous focus if supported, otherwise use
* software auto-focus. Only works for API level >=9.
*/
/*
Camera.Parameters parameters = camera.getParameters();
for (String f : parameters.getSupportedFocusModes()) {
if (f == Parameters.FOCUS_MODE_CONTINUOUS_PICTURE) {
mCamera.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
autoFocusCallback = null;
break;
}
}
*/
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
Log.d("DBG", "Error setting camera preview: " + e.getMessage());
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// Camera preview released in activity
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
/*
* If your preview can change or rotate, take care of those events here.
* Make sure to stop the preview before resizing or reformatting it.
*/
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
try {
// Hard code camera surface rotation 90 degs to match Activity view in portrait
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.setPreviewCallback(previewCallback);
mCamera.startPreview();
mCamera.autoFocus(autoFocusCallback);
} catch (Exception e){
Log.d("DBG", "Error starting camera preview: " + e.getMessage());
}
}
}
In the PreviewCallback you can actually crop the scanning area. In the onPreviewFrame method, after calling barcode.setData() you can call barcode.setCrop(left,top,width,height). All measurements in pixels.
Also make sure to set the crop size with respect to the preview image size and not the device screen size.
Note: Please make sure that the x-axis is always the longest side even though you orient the phone in portrait mode.
Please refer below Image for better understanding of the arguments.
This solution is specific to zbar for android.
Related
What I have done so far:
I have implemented custom camera for reading qr code which need to continue focus the camera for better qr reading.
My problem is when I use to focus in every one second with the handler the camera flash on\off button dont works or it takes too much time to turning on and off the camera flash light. Every thing works fine when I remove the code of auto focusing the camera every second (The runnable and the handler).
What I want is to focus automatically and quickly whenever camera moves and also able to turn on and off the flash on demand quickly without using Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE because its not available for API<14.
I have used Camera.Parameters.FOCUS_MODE_AUTO but its only focusing the camera once when started thats why i used handler to focus camera every second.
Min SDK Version of project is 9.
My Camera Activity is
public class CameraActivityNew extends Activity implements OnClickListener,
Camera.PreviewCallback {
CameraPreviewNew mPreview;
FrameLayout flCameraPreview;
ImageButton ibFlashButton;
Boolean isFlashOn = false;
Camera mCamera;
private Handler mAutoFocusHandler;
private boolean mPreviewing = true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
mAutoFocusHandler = new Handler();
setContentView(R.layout.activity_camera);
findSetupViews();
mPreview = new CameraPreviewNew(getApplicationContext(), this,
autoFocusCB);
flCameraPreview.addView(mPreview);
}
private Runnable doAutoFocus = new Runnable() {
public void run() {
if (mCamera != null && mPreviewing) {
mCamera.autoFocus(autoFocusCB);
}
}
};
Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
}
};
#Override
protected void onResume() {
super.onResume();
try {
mCamera = Camera.open();
if (mCamera == null) {
return;
}
} catch (Exception e) {
e.printStackTrace();
return;
}
mPreview.setCamera(mCamera);
mPreview.showSurfaceView();
mPreviewing = true;
}
#Override
protected void onPause() {
super.onPause();
if (mCamera != null) {
mPreview.setCamera(null);
mCamera.cancelAutoFocus();
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
mPreview.hideSurfaceView();
mPreviewing = false;
mCamera = null;
}
}
private void findSetupViews() {
flCameraPreview = (FrameLayout) findViewById(R.id.flCameraPreview);
ibFlashButton = (ImageButton) findViewById(R.id.ibFlash);
ibFlashButton.setOnClickListener(this);
if (getPackageManager().hasSystemFeature(
PackageManager.FEATURE_CAMERA_FLASH)) {
ibFlashButton.setVisibility(View.VISIBLE);
ibFlashButton.setOnClickListener(this);
} else {
ibFlashButton.setVisibility(View.GONE);
}
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.ibFlash:
if (isFlashOn) {
mPreview.setCameraFlashLight(false);
isFlashOn = false;
ibFlashButton.setImageResource(R.drawable.flashoff);
} else {
mPreview.setCameraFlashLight(true);
ibFlashButton.setImageResource(R.drawable.flashon);
isFlashOn = true;
}
break;
}
}
#Override
public void onPreviewFrame(final byte[] data, final Camera camera) {
// processed here qr code and works fine if camera focus
//now removed to narrow the code for posting the question
}
}
And the Camera Preview class is:
public class CameraPreviewNew extends ViewGroup implements Callback {
public static final int CAMERA_BACK = 0;
public static final int CAMERA_FRONT = 1;
public Camera mCamera = null;
private Context context = null;
SurfaceView mSurfaceView;
SurfaceHolder mSurfaceHolder;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
PreviewCallback mPreviewCallback;
AutoFocusCallback mAutoFocusCallback;
public CameraPreviewNew(Context context,
PreviewCallback previewCallback, AutoFocusCallback autoFocusCb) {
super(context);
mPreviewCallback = previewCallback;
mAutoFocusCallback = autoFocusCb;
this.context = context;
mSurfaceView = new SurfaceView(context);
addView(mSurfaceView);
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(this);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters()
.getSupportedPreviewSizes();
requestLayout();
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(),
widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(),
heightMeasureSpec);
setMeasuredDimension(width, height);
}
public void hideSurfaceView() {
mSurfaceView.setVisibility(View.INVISIBLE);
}
public void showSurfaceView() {
mSurfaceView.setVisibility(View.VISIBLE);
}
public void surfaceCreated(SurfaceHolder holder) {
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
}
} catch (IOException exception) {
Log.e("logtag", "IOException caused by setPreviewDisplay()",
exception);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
if (mCamera != null) {
mCamera.cancelAutoFocus();
mCamera.stopPreview();
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if (holder.getSurface() == null) {
return;
}
if (mCamera != null) {
Camera.Parameters parameters = mCamera.getParameters();
mPreviewSize = getBestPreviewSize(mCamera.getParameters(), w, h);
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
mCamera.setParameters(parameters);
mCamera.setPreviewCallback(mPreviewCallback);
mCamera.startPreview();
mCamera.autoFocus(mAutoFocusCallback);
setCameraDisplayOrientation(0);
}
}
private void setCameraDisplayOrientation(int cameraId) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
int rotation = ((WindowManager) context
.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
.getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
mCamera.setDisplayOrientation(result);
}
protected static Comparator<Size> newSizeComparator() {
return new Comparator<Size>() {
#Override
public int compare(Size lhs, Size rhs) {
return Integer.valueOf(rhs.height * rhs.width).compareTo(
lhs.height * lhs.width);
}
};
}
private Size getBestPreviewSize(Parameters parameters, int screenWidth,
int screenHeight) {
List<Size> supportedSizes = parameters.getSupportedPreviewSizes();
Collections.sort(supportedSizes, newSizeComparator());
int previewHeight = screenHeight;
int previewWidth = screenWidth;
if (previewHeight > previewWidth) {
int swap = previewWidth;
previewWidth = previewHeight;
previewHeight = swap;
}
Size bestSize = null;
float bestRatio = 999;
for (Size s : supportedSizes) {
if (s.height > s.width) {
int swap = s.width;
s.width = s.height;
s.height = swap;
}
float cameraRatio = ((float) s.height / (float) s.width);
float screenRatio = ((float) previewHeight)
/ ((float) previewWidth);
if ((s.height >= previewHeight) && (s.width >= previewWidth)) {
float ratioDiff = cameraRatio - screenRatio;
if ((ratioDiff < 0.19) && (ratioDiff > -0.19)
&& (Math.abs(bestRatio) > Math.abs(ratioDiff))) {
bestSize = s;
bestRatio = ratioDiff;
}
}
}
return bestSize;
}
public void setCameraFlashLight(Boolean setFlash) {
Parameters _parameters = mCamera.getParameters();
if (setFlash) {
_parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
} else {
_parameters.setFlashMode(Parameters.FLASH_MODE_OFF);
}
mCamera.setParameters(_parameters);
mCamera.startPreview();
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed && getChildCount() > 0) {
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null) {
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}
if (width * previewHeight > height * previewWidth) {
final int scaledChildWidth = previewWidth * height
/ previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
} else {
final int scaledChildHeight = previewHeight * width
/ previewWidth;
child.layout(0, (height - scaledChildHeight) / 2, width,
(height + scaledChildHeight) / 2);
}
}
}
}
I see some issue with your AutoFocus handling code.
Analysis Result
There is cycle in your autofocus.
Explanation
a) Camera Preview Class mAutoFocusCallback is set with the autoFocusCb of the Camera Activity.
public CameraPreviewNew(Context context,...,AutoFocusCallback autoFocusCb)
{
super(context);
mAutoFocusCallback = autoFocusCb;
...
}
b)surfaceChanged is called once, at the time of loading the activity. The camera is requested to Auto Focus.
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)
{
if (mCamera != null)
{
...
mCamera.startPreview();
/*Auto focus camera and call <code>mAutoFocusCallback</code> after autofocus.*/
mCamera.autoFocus(mAutoFocusCallback);
...
}
}
c) On completion of the autofocus the mAutoFocusCallback callback is called. mAutoFocusCallback->autoFocusCb->onAutoFocus()
Camera Activity
Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
}
};
d)onAutoFocus schedules one more autoFocus after 1000 millisecons, 1 sec.
Camera Activity
public void onAutoFocus(boolean success, Camera camera) {
mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
}
e)After one second the messages is passed to handler that calles the runnable doAutoFocus requesting camera to auto focus, similar to b) above.
private Runnable doAutoFocus = new Runnable() {
public void run() {
if (mCamera != null && mPreviewing) {
mCamera.autoFocus(autoFocusCB);
}
}
};
f) After completion of the autoFocus, the autoFocusCB is called again, similar to c) above. and cycle continues.
Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
}
};
Solution
I am confused why such implementation. The cycle may be reason behind not listening to the flash enable/disable calls. You need to remove the code below and do something meaningful else leave the onAutoFocus() empty.
Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
/*REMOVE LINE BELOW*/
mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
}
};
For auto focusing every time the camera moves you need to take help of the motion sensors provided with the phone. You can google it
Hope that helps.
Happy Coding...
It seems that you dont need to use AutoFocusCallBack for your app, because you did nothing else than delay 1 second.
What you can do to focus all the time is using FOCUS_MODE_CONTINUOUS_PICTURE(read more here) like that(setFocus method is in CameraPreview, not in Activity):
public void setFocus() {
Camera.Parameters p = mCamera.getParameters();
p.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
mCamera.setParameters(p);
mCamera.startPreview();
}
And call it in SurfaceChanged:
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<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
// You need to choose the most appropriate previewSize for your app
Camera.Size previewSize = previewSizes.get(0);
parameters.setPreviewSize(previewSize.width, previewSize.height);
parameters.setRotation(90);
mCamera.setParameters(parameters);
mCamera.startPreview();
setFlash(true);
setZoomLevel(5);
setFocus();
Log.w(TAG, "surfaceChanged()");
}
For flash you can use this method from CameraPreview:
public void setFlash(boolean isFlashOn) {
Camera.Parameters p = mCamera.getParameters();
if (isFlashOn) {
p.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
mCamera.setParameters(p);
mCamera.startPreview();
} else {
p.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
mCamera.setParameters(p);
mCamera.startPreview();
}
Log.w(TAG, "setFlash()");
}
Hope it helps you! If you have any questions about my answer feel free to comment.
While this must be late, if you are toggling Camera parameters, it is preferable to do the sequence of operation as below
mCamera.stopPreview();
mCamera.setParameters(params); // set flash on in Camera parameters
mCamera.startPreview();
I am developing an app that is going to be something like camscanner. In my app i have an camera api tha i call. When the app is first opened and i press the camera button it works, but when i click home button and open again my app it freezes and shows a black screen without the app crashing. I found similar questions but none could give me a right answer, i know i probably have to change something in the onResume or onPause and need help to figure out what.
below i have my CameraScreen activity:
public class CameraScreen extends Activity {
ImageView image;
Activity context;
Preview preview;
Camera camera;
Button exitButton;
ImageView fotoButton;
LinearLayout progressLayout;
String path = "/sdcard/KutCamera/cache/images/";
FrameLayout frame;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.camera_layout);
context=this;
fotoButton = (ImageView) findViewById(R.id.imageView_foto);
exitButton = (Button) findViewById(R.id.button_exit);
image = (ImageView) findViewById(R.id.imageView_photo);
progressLayout = (LinearLayout) findViewById(R.id.progress_layout);
preview = new Preview(this,
(SurfaceView) findViewById(R.id.KutCameraFragment));
frame = (FrameLayout) findViewById(R.id.preview);
frame.addView(preview);
preview.setKeepScreenOn(true);
fotoButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
try {
takeFocusedPicture();
} catch (Exception e) {
}
exitButton.setClickable(true);
fotoButton.setClickable(false);
progressLayout.setVisibility(View.VISIBLE);
}
});
}
#Override
protected void onPause() {
super.onPause();
//releaseMediaRecorder(); // if you are using MediaRecorder, release it first
//releaseCamera();
if(null != camera){
camera.release();
camera = null;
}
frame.removeView(preview);
preview = null;// release the camera immediately on pause event
}
private void releaseCamera(){
if (camera != null){
camera.release(); // release the camera for other applications
camera = null;
}
}
#Override
protected void onResume() {
super.onResume();
// TODO Auto-generated method stub
if(camera==null){
Log.d("Camera tes", "Camera==null");
//camera.setPreviewCallback(null);
camera = Camera.open();
camera.startPreview();
camera.setErrorCallback(new ErrorCallback() {
public void onError(int error, Camera mcamera) {
camera.release();
camera = Camera.open();
Log.d("Camera died", "error camera");
}
});
}
if (camera != null) {
//camera.setPreviewCallback(null);
Log.d("Camera tes", "Camera!=null");
if (Build.VERSION.SDK_INT >= 14)
setCameraDisplayOrientation(context,
CameraInfo.CAMERA_FACING_BACK, camera);
preview.setCamera(camera);
}
}
private void setCameraDisplayOrientation(Activity activity, int cameraId,
android.hardware.Camera camera) {
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().getDefaultDisplay()
.getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
}
Camera.AutoFocusCallback mAutoFocusCallback = new Camera.AutoFocusCallback() {
#Override
public void onAutoFocus(boolean success, Camera camera) {
try{
camera.takePicture(mShutterCallback, null, jpegCallback);
}catch(Exception e){
}
}
};
Camera.ShutterCallback mShutterCallback = new ShutterCallback() {
#Override
public void onShutter() {
// TODO Auto-generated method stub
}
};
public void takeFocusedPicture() {
camera.autoFocus(mAutoFocusCallback);
}
PictureCallback rawCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
// Log.d(TAG, "onPictureTaken - raw");
}
};
PictureCallback jpegCallback = new PictureCallback() {
#SuppressWarnings("deprecation")
public void onPictureTaken(byte[] data, Camera camera) {
FileOutputStream outStream = null;
Calendar c = Calendar.getInstance();
File videoDirectory = new File(path);
if (!videoDirectory.exists()) {
videoDirectory.mkdirs();
}
try {
// Write to SD Card
outStream = new FileOutputStream(path + c.getTime().getSeconds() + ".jpg");
outStream.write(data);
outStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
Bitmap realImage;
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 5;
options.inPurgeable=true; //Tell to gc that whether it needs free memory, the Bitmap can be cleared
options.inInputShareable=true; //Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future
realImage = BitmapFactory.decodeByteArray(data,0,data.length,options);
ExifInterface exif = null;
try {
exif = new ExifInterface(path + c.getTime().getSeconds()
+ ".jpg");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
Log.d("EXIF value",
exif.getAttribute(ExifInterface.TAG_ORIENTATION));
if (exif.getAttribute(ExifInterface.TAG_ORIENTATION)
.equalsIgnoreCase("1")) {
realImage = rotate(realImage, 90);
} else if (exif.getAttribute(ExifInterface.TAG_ORIENTATION)
.equalsIgnoreCase("8")) {
realImage = rotate(realImage, 90);
} else if (exif.getAttribute(ExifInterface.TAG_ORIENTATION)
.equalsIgnoreCase("3")) {
realImage = rotate(realImage, 90);
} else if (exif.getAttribute(ExifInterface.TAG_ORIENTATION)
.equalsIgnoreCase("0")) {
realImage = rotate(realImage, 90);
}
} catch (Exception e) {
}
image.setImageBitmap(realImage);
fotoButton.setClickable(true);
camera.startPreview();
progressLayout.setVisibility(View.GONE);
exitButton.setClickable(true);
}
};
public static Bitmap rotate(Bitmap source, float angle) {
Matrix matrix = new Matrix();
matrix.postRotate(angle);
return Bitmap.createBitmap(source, 0, 0, source.getWidth(),
source.getHeight(), matrix, false);
}
}
And here i have my Preview class:
class Preview extends ViewGroup implements SurfaceHolder.Callback {
private final String TAG = "Preview";
SurfaceView mSurfaceView;
SurfaceHolder mHolder;
int heightmax ;
int widthmax ;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
Camera mCamera;
#SuppressWarnings("deprecation")
Preview(Context context, SurfaceView sv) {
super(context);
mSurfaceView = sv;
// addView(mSurfaceView);
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPictureSizes();
requestLayout();
// get Camera parameters
Camera.Parameters params = mCamera.getParameters();
List<String> focusModes = params.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
// set the focus mode
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
// set Camera parameters
mCamera.setParameters(params);
}
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// We purposely disregard child measurements because act as a
// wrapper to a SurfaceView that centers the camera preview instead
// of stretching it.
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize=maxSize();
}
}
public Size maxSize(){
Size sizeMax=mSupportedPreviewSizes.get(0);
maxsize=mSupportedPreviewSizes.get(0)
.height*mSupportedPreviewSizes.get(0).width;
for(Size size:mSupportedPreviewSizes){
if(size.height*size.width>sizeMax.width*sizeMax.height){
sizeMax = size;
}
}
return sizeMax;
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed && getChildCount() > 0) {
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null) {
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}
// Center the child SurfaceView within the parent.
if (width * previewHeight > height * previewWidth) {
final int scaledChildWidth = previewWidth * height / previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
} else {
final int scaledChildHeight = previewHeight * width / previewWidth;
child.layout(0, (height - scaledChildHeight) / 2,
width, (height + scaledChildHeight) / 2);
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where
// to draw.
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
}
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
/*
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
if (mCamera != null) {
mCamera.stopPreview();
}
*/
}
Camera.AutoFocusCallback mnAutoFocusCallback = new Camera.AutoFocusCallback() {
#Override
public void onAutoFocus(boolean success, Camera camera) {
}
};
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
/*
if(mCamera != null) {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPictureSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
mCamera.setParameters(parameters);
mCamera.startPreview();
}
*/
}
}
I would appriciate any help or guides you can give me.
Below attached is the code I am trying. The CamPreview class is being used by the launcher activity. I was able to get preview fine before implementing PreviewCallback. When i try PreviewCallback by implementing onPreviewFrame, i am totally confused how it works internally. Below are the following things that are confusing me. Kindly clarify them.
1) Though i set camera parameters like ImageFormat and Previewsize, they don't seem to persist till the invokation of method onPreviewFrame. For example, the Log.i statements in surfaceChanged method (called immediately atleast once after surfaceCreated as per my understanding) prints the preview size as 1056x864. However, onPreviewFrame reports that the preview size as 1920x1080.
Even the picture format changes from NV21(17 in surfaceChanged) to JPEG(256 in onPreviewFrame).
I have verified and confirmed that the Camera instance passed to onPreviewFrame is same as the member variable mCamera declared in CamPreview class.
If i am able to successfully get preview format as NV21 in onPreviewFrame, how do i convert that to ARGB format ? I have tried the methods posted in stackoverflow but the data passed to onPreviewFrame fails due to index out of bounds, which lead to me to check the image formats in the first place. If anyone has tried something similar, pls do let me know what was i missing during the creation that is causing this mess :(.
I have tried to create bitmap by initially creating YuvImage from byte[] passed to onPreviewFrame which gave me green latern images(all green or garbage some times)!
2) You can see other Log.i stmts next to the ones i mentioned in point (1). They print out bits per pixel and bytes per pixel information of the preview in the methods surfaceChanged and onPreviewFrame. They turn out to be 12 and 1 respectively. How is that even possible ? Again, this could be a side effect of what is happening in (1)
public class CamPreview extends SurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback {
private static final String TAG = "CamPreview";
private SurfaceHolder mHolder;
private Camera mCamera;
private byte[] mVideoSource;
private Bitmap mBackBuffer;
private Paint mPaint;
private Context mContext;
public CamPreview(Context context) {
super(context);
mContext = context;
mCamera = getCameraInstance();
mHolder = getHolder();
mHolder.addCallback(this);
}
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(null);
mCamera.setPreviewCallbackWithBuffer(this);
this.setWillNotDraw(false);
Log.i(TAG, "#SurfaceCreated: initilization finished");
} catch (IOException eIOException) {
Log.i(TAG, "Error setting camera preview: " + eIOException.getMessage());
throw new IllegalStateException();
}
}
private Size findBestResolution(int pWidth, int pHeight) {
List<Size> lSizes = mCamera.getParameters().getSupportedPreviewSizes();
Size lSelectedSize = mCamera.new Size(0, 0);
for (Size lSize : lSizes) {
if ((lSize.width <= pWidth)
&& (lSize.height <= pHeight)
&& (lSize.width >= lSelectedSize.width)
&& (lSize.height >= lSelectedSize.height)) {
lSelectedSize = lSize;
}
}
if ((lSelectedSize.width == 0)
|| (lSelectedSize.height == 0)) {
lSelectedSize = lSizes.get(0);
}
return lSelectedSize;
}
private void createBuffers(String caller, Size prefSize) {
Camera.Parameters camParams = mCamera.getParameters();
int previewWidth = prefSize.width;
int previewHeight = prefSize.height;
mBackBuffer = Bitmap.createBitmap(previewWidth,
previewHeight,
Bitmap.Config.ARGB_8888);
Log.i(TAG,"#"+caller+": Piture Width " + Integer.toString(previewWidth));
Log.i(TAG,"#"+caller+": Piture Height " + Integer.toString(previewHeight));
Log.i(TAG,"#"+caller+": Piture format " + Integer.toString(ImageFormat.NV21));
camParams.setPreviewSize(previewWidth,previewHeight);
camParams.setPreviewFormat(ImageFormat.NV21);
mCamera.setParameters(camParams);
PixelFormat pxlFrmt = new PixelFormat();
PixelFormat.getPixelFormatInfo(camParams.getPreviewFormat(), pxlFrmt);
Log.i(TAG,"#"+caller+": Bits per pixel " + Integer.toString(pxlFrmt.bitsPerPixel));
Log.i(TAG,"#"+caller+": Bytes per pixel " + Integer.toString(pxlFrmt.bytesPerPixel));
int sz = previewWidth * previewHeight * pxlFrmt.bitsPerPixel/8;
mVideoSource = new byte[sz];
mCamera.addCallbackBuffer(mVideoSource);
Log.i(TAG, "#"+caller+": backbuffer initilization finished");
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
Log.i(TAG, "#SurfaceCreated: preview started");
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null) {
Log.i(TAG,"No proper holder");
return;
}
try {
mCamera.stopPreview();
} catch (Exception e){
Log.i(TAG,"tried to stop a non-existent preview");
return;
}
createBuffers("surfaceChanged",findBestResolution(w, h));
}
public void onPreviewFrame(byte[] data, Camera camera) {
Log.i(TAG,"#onPreviewFrame: Invoked");
Camera.Parameters params = camera.getParameters();
Camera.Size camSize = params.getPictureSize();
int w = camSize.width;
int h = camSize.height;
Log.i(TAG,"#onPreviewFrame: Piture Width " + Integer.toString(w));
Log.i(TAG,"#onPreviewFrame: Piture Height " + Integer.toString(h));
Log.i(TAG,"#onPreviewFrame: Piture format " + Integer.toString(params.getPictureFormat()));
PixelFormat pxlFrmt = new PixelFormat();
PixelFormat.getPixelFormatInfo(params.getPreviewFormat(), pxlFrmt);
Log.i(TAG,"#onPreviewFrame: Bits per pixel " + Integer.toString(pxlFrmt.bitsPerPixel));
Log.i(TAG,"#onPreviewFrame: Bytes per pixel " + Integer.toString(pxlFrmt.bytesPerPixel));
mBackBuffer = BitmapFactory.decodeByteArray(data, 0, data.length);
Log.i(TAG,"#onPreviewFrame: Back buffer set.");
invalidate();
}
#Override
protected void onDraw(Canvas pCanvas) {
super.onDraw(pCanvas);
Log.i(TAG,"#onDraw: Invoked");
if (mCamera != null) {
Log.i(TAG,"#onDraw: Bbefore draw call to canvas");
pCanvas.drawBitmap(mBackBuffer, 0, 0, mPaint);
mCamera.addCallbackBuffer(mVideoSource);
Log.i(TAG,"#onDraw: Draw finished");
}
}
/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
// this device has a camera
return true;
} else {
// no camera on this device
return false;
}
}
/** A safe way to get an instance of the Camera object. */
private Camera getCameraInstance(){
Camera c = null;
if(checkCameraHardware(mContext)) {
try {
Log.i(TAG, "Trying to open the camera");
c = Camera.open(0);
Log.i(TAG, "Camera opened successfully.");
}
catch (Exception e){
Log.i(TAG, e.getMessage());
}
}
return c;
}
private void releaseCamera(){
if (mCamera != null){
mCamera.release(); // release the camera for other applications
mCamera = null;
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
if (mCamera != null) {
mCamera.stopPreview();
releaseCamera();
mVideoSource = null;
mBackBuffer = null;
}
}
}
Ok, Figured out couple of things after careful reiteration of my reading through the android docs. Apparently preview[Size|Format] is completely different from picture[Size/Format], which i assumed to be one and the same earlier. So, that fixed my rendering issues and crashes due incorrect data format. It also clarifed my confusion of change in camera parameters automatically.
The whole example is working now. However, i am seeing two layers of preview, the one which directly rendered by the camera, and the one i am rendering though onDraw. I am not sure whether i should see both of them or not. Below is the fixed code.
Thank you if anyone who might have spent time on this. Now, i will work on moving the whole onPreviewFrame logic to native code to speed up things! :)
public class CamPreview extends SurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback {
private static final String TAG = "CamPreview";
private static final int mPreviewWidth = 1280;
private static final int mPreviewHeight = 720;
private static final int mFPSXOff = 72;
private static final int mFPSYOff = 72;
private static final int mFPSSize = 64;
private float mTotalTime;
private float mFrameCount;
private String mFPS;
private long mStart;
private Context mContext;
private SurfaceHolder mHolder;
private Camera mCamera;
private byte[] mVideoSource;
private Bitmap mBackBuffer;
private Paint mPaint;
public CamPreview(Context context) {
super(context);
mContext = context;
mHolder = getHolder();
mCamera = getCameraInstance();
mHolder.addCallback(this);
mFrameCount = 0;
mTotalTime = 0;
mFPS = "0 FPS";
mStart = 0;
mPaint = new Paint();
mPaint.setColor(0xFFFF0000);
mPaint.setTextSize(mFPSSize);
}
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(null);
mCamera.setPreviewCallbackWithBuffer(this);
this.setWillNotDraw(false);
} catch (IOException eIOException) {
Log.i(TAG, "Error setting camera preview: " + eIOException.getMessage());
throw new IllegalStateException();
}
}
private Size findBestResolution(int pWidth, int pHeight) {
List<Size> lSizes = mCamera.getParameters().getSupportedPreviewSizes();
Size lSelectedSize = mCamera.new Size(0, 0);
for (Size lSize : lSizes) {
if ((lSize.width <= pWidth)
&& (lSize.height <= pHeight)
&& (lSize.width >= lSelectedSize.width)
&& (lSize.height >= lSelectedSize.height)) {
lSelectedSize = lSize;
}
}
if ((lSelectedSize.width == 0)
|| (lSelectedSize.height == 0)) {
lSelectedSize = lSizes.get(0);
}
return lSelectedSize;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if (mHolder.getSurface() == null) {
Log.i(TAG,"No proper holder");
return;
}
try {
mCamera.stopPreview();
} catch (Exception e) {
Log.i(TAG,"tried to stop a non-existent preview");
return;
}
PixelFormat pxlFrmt = new PixelFormat();
Camera.Parameters camParams = mCamera.getParameters();
Size previewSize = findBestResolution(w, h);
int previewWidth = previewSize.width;
int previewHeight = previewSize.height;
camParams.setPreviewSize(previewWidth,previewHeight);
camParams.setPreviewFormat(ImageFormat.NV21);
mCamera.setParameters(camParams);
mCamera.setDisplayOrientation(90);
mBackBuffer = Bitmap.createBitmap(previewWidth, previewHeight, Bitmap.Config.ARGB_8888);
PixelFormat.getPixelFormatInfo(camParams.getPreviewFormat(), pxlFrmt);
int sz = previewWidth * previewHeight * pxlFrmt.bitsPerPixel/8;
mVideoSource = new byte[sz];
mCamera.addCallbackBuffer(mVideoSource);
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
Log.i(TAG, "#SurfaceChanged: preview started");
} catch (Exception e){
Log.d(TAG, "#SurfaceChanged:Error starting camera preview: " + e.getMessage());
}
mFrameCount = 0;
mTotalTime = 0;
mStart = SystemClock.elapsedRealtime();
}
public void onPreviewFrame(byte[] data, Camera camera) {
Log.i(TAG,"#onPreviewFrame: Invoked");
Camera.Parameters params = camera.getParameters();
Camera.Size camSize = params.getPreviewSize();
int w = camSize.width;
int h = camSize.height;
PixelFormat pxlFrmt = new PixelFormat();
PixelFormat.getPixelFormatInfo(params.getPreviewFormat(), pxlFrmt);
try {
YuvImage yuv = new YuvImage(data,ImageFormat.NV21,w,h,null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
yuv.compressToJpeg(new Rect(0,0,w,h), 100, baos);
byte[] jpgData = baos.toByteArray();
mBackBuffer = BitmapFactory.decodeByteArray(jpgData, 0, jpgData.length);
} catch (Exception e) {
;
}
Log.i(TAG,"#onPreviewFrame: Backbuffer set.");
postInvalidate();
mFrameCount++;
long end = SystemClock.elapsedRealtime();
mTotalTime += (end-mStart);
mStart = end;
mFPS = Float.toString((1000*mFrameCount/mTotalTime))+" fps";
}
#Override
protected void onDraw(Canvas pCanvas) {
Log.i(TAG,"#onDraw: Invoked");
if (mCamera != null) {
if(mBackBuffer==null) {
Log.i(TAG, "Back buffer is null :((((((( ");
} else {
pCanvas.drawBitmap(mBackBuffer, 0, 0, null);
pCanvas.drawText(mFPS, mFPSXOff, mFPSYOff, mPaint);
mCamera.addCallbackBuffer(mVideoSource);
}
}
}
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
return true;
} else {
return false;
}
}
private Camera getCameraInstance(){
Camera c = null;
if(checkCameraHardware(mContext)) {
try {
c = Camera.open(0);
Log.i(TAG, "Camera opened successfully");
Camera.Parameters params = c.getParameters();
params.setPreviewFormat(ImageFormat.NV21);
params.setPreviewSize(mPreviewWidth, mPreviewHeight);
c.setParameters(params);
Log.i(TAG, "NV21 format set to camera with resolution 1280x720");
}
catch (Exception e){
Log.i(TAG, e.getMessage());
}
}
return c;
}
private void releaseCamera(){
if (mCamera != null){
mCamera.release();
Log.i(TAG,"#releaseCamera:");
mCamera = null;
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
releaseCamera();
mVideoSource = null;
mBackBuffer = null;
}
}
}
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Capture image with front camera without opening the camera application in android
my problem is I can do capturing only by using Intent to launch the camera and click the button to capture image. Is it possible to do it automatically by not clicking a button or what codes can I add to do this? thanks in advance.
public class CameraView extends Activity implements SurfaceHolder.Callback, OnClickListener{
private static final String TAG = "CameraTest";
Camera mCamera;
boolean mPreviewRunning = false;
#SuppressWarnings("deprecation")
public void onCreate(Bundle icicle){
super.onCreate(icicle);
Log.e(TAG, "onCreate");
getWindow().setFormat(PixelFormat.TRANSLUCENT);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.cameraview);
ImageView img = (ImageView) findViewById(R.id.blankImage);
if(CaptureCameraImage.isBlack)
img.setBackgroundResource(android.R.color.black);
else
img.setBackgroundResource(android.R.color.white);
mSurfaceView = (SurfaceView) findViewById(R.id.surface_camera);
mSurfaceView.setOnClickListener(this);
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState){
super.onRestoreInstanceState(savedInstanceState);
}
Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
// TODO Auto-generated method stub
if (data != null){
//Intent mIntent = new Intent();
//mIntent.putExtra("image",imageData);
mCamera.stopPreview();
mPreviewRunning = false;
mCamera.release();
try{
BitmapFactory.Options opts = new BitmapFactory.Options();
Bitmap bitmap= BitmapFactory.decodeByteArray(data, 0, data.length,opts);
bitmap = Bitmap.createScaledBitmap(bitmap, 300, 300, false);
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int newWidth = 300;
int newHeight = 300;
// calculate the scale - in this case = 0.4f
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// createa matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(scaleWidth, scaleHeight);
// rotate the Bitmap
matrix.postRotate(-90);
Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
width, height, matrix, true);
CaptureCameraImage.image.setImageBitmap(resizedBitmap);
}catch(Exception e){
e.printStackTrace();
}
//StoreByteImage(mContext, imageData, 50,"ImageName");
//setResult(FOTO_MODE, mIntent);
setResult(585);
finish();
}
}
};
protected void onResume(){
Log.e(TAG, "onResume");
super.onResume();
}
protected void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
}
protected void onStop(){
Log.e(TAG, "onStop");
super.onStop();
}
#TargetApi(9)
public void surfaceCreated(SurfaceHolder holder){
Log.e(TAG, "surfaceCreated");
mCamera = Camera.open(CaptureCameraImage.cameraID);
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Log.e(TAG, "surfaceChanged");
// XXX stopPreview() will crash if preview is not running
if (mPreviewRunning){
mCamera.stopPreview();
}
Camera.Parameters p = mCamera.getParameters();
p.setPreviewSize(300, 300);
if(CaptureCameraImage.cameraID == 0){
String stringFlashMode = p.getFlashMode();
if (stringFlashMode.equals("torch"))
p.setFlashMode("on"); // Light is set off, flash is set to normal 'on' mode
else
p.setFlashMode("torch");
}
mCamera.setParameters(p);
try{
mCamera.setPreviewDisplay(holder);
}catch (Exception e){
// TODO Auto-generated catch block
e.printStackTrace();
}
mCamera.startPreview();
mPreviewRunning = true;
mCamera.takePicture(null, mPictureCallback, mPictureCallback);
}
public void surfaceDestroyed(SurfaceHolder holder) {
Log.e(TAG, "surfaceDestroyed");
//mCamera.stopPreview();
//mPreviewRunning = false;
//mCamera.release();
}
private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
public void onClick(View v) {
// TODO Auto-generated method stub
mCamera.takePicture(null, mPictureCallback, mPictureCallback);
}
}
You need to call this activity Also check below line of code
mCamera.takePicture(null, mPictureCallback, mPictureCallback);
It's called twice
1) If you want user interaction to take picture you need to commit first occurrence
2) If you want no user interaction (It will take photo as soon as it start)
You can find whole project at
https://github.com/sandipmjadhav/CaptureImage
Thank You
Yes, you can take images automatically without pressing the capture button. Your Activity which you are going to capture the image should extends Activity and implements PictureCallback, ShutterCallback.
You have to use following method
videoPreview.getCamera().takePicture(this, null, this);
videoPreview is an instance of the class that I have created, which extends SurfaceView and implements SurfaceHolder.Callback
Camera.open(); is also in VideoPriview class
I am trying to make a custom camera application
I want to let the users can choose the focus mode in this application.
The focus mode is auto and touch-to-focus
If we want to use touch-to-focus in the camera , how can be start with?
The feature is software/hardware/manufacture dependent, my suggestion is that you first find a phone like Galaxy Nexus flashed with Android 4.x, then try the android.hardware.Camera.Parameters.getMaxNumFocusAreas() on it, if the return value is greater than zero then you are lucky, and can then use the setFocusAreas() to implement your "touch to focus" feature.
Why:
In old Android versions there is no public API to set the focus areas. Although many manufacturers managed to create their own API and implementation, they won't share.
Android introduced the focus areas API in API level 14, however the phone manufacturers may choose not to implement it (i.e. choose to stick to their own solutions). To check if the API is supported you can call getMaxNumFocusAreasa() first, if it returns a positive integer that means the phone does implement the API and you can go on enabling the "touch focus" feature in your camera app. (The API is also one of the enablers of the "face detection" feature, when faces are recognized the camera app uses the API to let the camera do auto focus on the them.)
You may refer to the vanilla Android Camera app source code for how to use the API properly.
References:
Android Camera API
getMaxNumFocusAreas()
setFocusAreas()
Android 4.0 Camera app source code
mInitialParams.getMaxNumFocusAreas()
mParameters.setFocusAreas()
Regards
Ziteng Chen
Try this:
public void takePhoto(File photoFile, String workerName, int width, int height, int quality) {
if (getAutoFocusStatus()){
camera.autoFocus(new AutoFocusCallback() {
#Override
public void onAutoFocus(boolean success, Camera camera) {
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}
});
}else{
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}
However, I've also seen this to work, possibly more accurately:
if (getAutoFocusStatus()){
camera.autoFocus(new AutoFocusCallback() {
#Override
public void onAutoFocus(boolean success, Camera camera) {
if(success) camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}
});
}else{
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}
The last one takes the picture at the moment the focussing is successfully completed. It works very well for using with QR scanning codes. I believe the same applies to cases like this.
It is already implemented buthow to modify this if I want to add touch to focus?
public void takePhoto(File photoFile, String workerName, int width, int height, int quality) {
if (getAutoFocusStatus()){
camera.autoFocus(new AutoFocusCallback() {
#Override
public void onAutoFocus(boolean success, Camera camera) {
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}
});
}else{
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}
this.photoFile = photoFile;
this.workerName = workerName;
this.imageOutputWidth = width;
this.imageOutputHeight = height;
}
public void takePhoto(File photoFile, int width, int height, int quality) {
takePhoto(photoFile, null, width, height, quality);
}
I was trying to implement focus functionality in my app and achieved this functionality in the way i wanted. To implement Touch to Focus please refer the code below.
CameraPreview.java
public class CameraPreview extends SurfaceView implements
SurfaceHolder.Callback {
private SurfaceHolder mSurfaceHolder;
private Camera mCamera;
private OnFocusListener onFocusListener;
private boolean needToTakePic = false;
private Camera.AutoFocusCallback myAutoFocusCallback = new Camera.AutoFocusCallback() {
#Override
public void onAutoFocus(boolean arg0, Camera arg1) {
if (arg0) {
mCamera.cancelAutoFocus();
}
}
};
// 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);
this.onFocusListener = (OnFocusListener) context;
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.getParameters().setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
mCamera.setDisplayOrientation(90);
mCamera.startPreview();
} catch (IOException e) {
// left blank for now
e.printStackTrace();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
mCamera.stopPreview();
this.mSurfaceHolder.removeCallback(this);
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();
} catch (Exception e) {
// intentionally left blank for a test
e.printStackTrace();
}
}
/**
* Called from PreviewSurfaceView to set touch focus.
*
* #param - Rect - new area for auto focus
*/
public void doTouchFocus(final Rect tfocusRect) {
try {
List<Camera.Area> focusList = new ArrayList<Camera.Area>();
Camera.Area focusArea = new Camera.Area(tfocusRect, 1000);
focusList.add(focusArea);
Camera.Parameters param = mCamera.getParameters();
param.setFocusAreas(focusList);
param.setMeteringAreas(focusList);
mCamera.setParameters(param);
mCamera.autoFocus(myAutoFocusCallback);
} catch (Exception e) {
e.printStackTrace();
}
if (isNeedToTakePic()) {
onFocusListener.onFocused();
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
float x = event.getX();
float y = event.getY();
Rect touchRect = new Rect(
(int) (x - 100),
(int) (y - 100),
(int) (x + 100),
(int) (y + 100));
final Rect targetFocusRect = new Rect(
touchRect.left * 2000 / this.getWidth() - 1000,
touchRect.top * 2000 / this.getHeight() - 1000,
touchRect.right * 2000 / this.getWidth() - 1000,
touchRect.bottom * 2000 / this.getHeight() - 1000);
doTouchFocus(targetFocusRect);
}
return false;
}
public boolean isNeedToTakePic() {
return needToTakePic;
}
public void setNeedToTakePic(boolean needToTakePic) {
this.needToTakePic = needToTakePic;
}
}
MainActivity.java
public class MainActivity extends Activity
implements OnFocusListener {
private Button captureButton, switchCameraButton;
private Camera mCamera;
private CameraPreview mCameraPreview;
private int currentCameraId;
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (getIntent().hasExtra("camera_id")) {
currentCameraId = getIntent().getIntExtra("camera_id", Camera.CameraInfo.CAMERA_FACING_BACK);
} else {
currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
}
captureButton = (Button) findViewById(R.id.button_capture);
captureButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
// Obtain MotionEvent object
v.setEnabled(false);
mCameraPreview.setNeedToTakePic(true);
long downTime = SystemClock.uptimeMillis();
long eventTime = SystemClock.uptimeMillis() + 100;
float x = mCameraPreview.getWidth() / 2;
float y = mCameraPreview.getHeight() / 2;
// List of meta states found here: developer.android.com/reference/android/view/KeyEvent.html#getMetaState()
int metaState = 0;
MotionEvent motionEvent = MotionEvent.obtain(
downTime,
eventTime,
MotionEvent.ACTION_DOWN,
x,
y,
metaState
);
// Dispatch touch event to view
mCameraPreview.dispatchTouchEvent(motionEvent);
}
});
switchCameraButton = (Button) findViewById(R.id.button_switch_camera);
switchCameraButton.setVisibility(
Camera.getNumberOfCameras() > 1 ? View.VISIBLE : View.GONE);
switchCameraButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mCamera.stopPreview();
//NB: if you don't release the current camera before switching, you app will crash
mCameraPreview.getHolder().removeCallback(mCameraPreview);
mCamera.release();
//swap the id of the camera to be used
if (currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
} else {
currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
}
mCamera = getCameraInstance(currentCameraId);
mCameraPreview = new CameraPreview(MainActivity.this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.removeAllViews();
preview.addView(mCameraPreview);
}
});
}
#Override
protected void onResume() {
super.onResume();
mCamera = getCameraInstance(currentCameraId);
mCameraPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mCameraPreview);
}
/**
* Helper method to access the camera returns null if it cannot get the
* camera or does not exist
*
* #return
*/
private Camera getCameraInstance(int currentCameraId) {
Camera camera = null;
try {
camera = Camera.open(currentCameraId);
} catch (Exception e) {
// cannot get camera or does not exist
}
return camera;
}
Camera.PictureCallback mPicture = new Camera.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 (IOException e) {
e.printStackTrace();
}
}
};
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_" + "DEMO_" + ".jpg");
if (mediaFile.exists()) mediaFile.delete();
return mediaFile;
}
#Override
public void onFocused() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
mCamera.takePicture(null, null, mPicture);
mCameraPreview.setNeedToTakePic(false);
captureButton.setEnabled(true);
}
}, 1500);
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<FrameLayout
android:id="#+id/camera_preview"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<Button
android:id="#+id/button_switch_camera"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Switch Camera" />
<Button
android:id="#+id/button_capture"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Capture" />
</LinearLayout>
You can find sample app on Github - Custom Camera App
Call this to enable Touch-To-Focus mode:
private void setTouchToFocusMode(Camera.Parameters parameters){
String focusMode;
if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
focusMode = Camera.Parameters.FOCUS_MODE_AUTO;
}
if (focusMode != null && focusMode.length() > 0){
parameters.setFocusMode(focusMode);
}
}
When user taps on screen, call this below to set focus area:
private static final int FOCUS_WIDTH = 80;
private static final int FOCUS_HEIGHT = 80;
public static String setFocalPoint(Camera.Parameters params, int x, int y){
String focusMode = "";
if (params != null && params.getMaxNumFocusAreas() > 0) {
List<Camera.Area> focusArea = new ArrayList<Camera.Area>();
focusArea.add(new Camera.Area(new Rect(x, y, x + FOCUS_WIDTH, y + FOCUS_HEIGHT), 1000));
params.setFocusAreas(focusArea);
if(params.getMaxNumMeteringAreas() > 0) {
params.setMeteringAreas(focusArea);
}
if(params.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
focusMode = Camera.Parameters.FOCUS_MODE_AUTO;
}
}
return focusMode;
}
Call autoFocus/cancelAutoFocus for action:
mCamera.cancelAutoFocus();
mCamera.autoFocus(mAutoFocusCallback);