I've requirement that i need to create a custom camera and allow user to place a logo while capturing image. The logo can be zoomed in/out and moved on camera view anywhere. I've written following code to do this, i was able to successfully zoom in/out and move logo image, but when i combine both logo and picture taken from camera it's not correctly combined. The logo image placed in different location and it's size got reduced. Please someone help me on this as i've stuck here and couldn't able to find what is wrong. I've also attached the screenshots taken in my phone for reference. Please check it.
I've moved logo to bottom left corner before tapping on capture button
After tapping on capture button both images combined like this.
public class CustomCamera extends Activity implements OnTouchListener,
SurfaceHolder.Callback {
private Matrix matrix = new Matrix();
private Matrix savedMatrix = new Matrix();
private static final int NONE = 0;
private static final int DRAG = 1;
private static final int ZOOM = 2;
private int mode = NONE;
private PointF start = new PointF();
private PointF mid = new PointF();
private float oldDist = 1f;
private float d = 0f;
private float newRot = 0f;
private float[] lastEvent = null;
String logoImageId = "";
Bitmap bitmap = null;
private Camera camera = null;
private SurfaceView cameraSurfaceView = null;
private SurfaceHolder cameraSurfaceHolder = null;
private boolean previewing = false;
RelativeLayout relativeLayout;
int currentCameraId = 0;
private Button btnCapture = null;
ImageButton useOtherCamera = null;
ImageView logoImageView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFormat(PixelFormat.TRANSLUCENT);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.camera_layout);
logoImageView = (ImageView) findViewById(R.id.logoImageView);
Bundle extras = getIntent().getExtras();
if (extras != null) {
logoImageId = extras.getString("logoImageId ");
}
try {
File file = new File(Environment.getExternalStorageDirectory()
+ "/" + getPackageName() + "/logo/" + logoImageId
+ ".jpg");
bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
logoImageView.setImageBitmap(bitmap);
logoImageView.setOnTouchListener(this);
relativeLayout = (RelativeLayout) findViewById(R.id.containerImg);
relativeLayout.setDrawingCacheEnabled(true);
cameraSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
cameraSurfaceHolder = cameraSurfaceView.getHolder();
cameraSurfaceHolder.addCallback(this);
btnCapture = (Button) findViewById(R.id.button);
btnCapture.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
camera.takePicture(null, null, cameraPictureCallbackJpeg);
}
});
}
public boolean onTouch(View v, MotionEvent event) {
// handle touch events here
ImageView view = (ImageView) v;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = DRAG;
lastEvent = null;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
lastEvent = new float[4];
lastEvent[0] = event.getX(0);
lastEvent[1] = event.getX(1);
lastEvent[2] = event.getY(0);
lastEvent[3] = event.getY(1);
d = rotation(event);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
lastEvent = null;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
matrix.set(savedMatrix);
float dx = event.getX() - start.x;
float dy = event.getY() - start.y;
matrix.postTranslate(dx, dy);
} else if (mode == ZOOM) {
float newDist = spacing(event);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = (newDist / oldDist);
matrix.postScale(scale, scale, mid.x, mid.y);
}
if (lastEvent != null && event.getPointerCount() == 3) {
newRot = rotation(event);
float r = newRot - d;
float[] values = new float[9];
matrix.getValues(values);
float tx = values[2];
float ty = values[5];
float sx = values[0];
float xc = (view.getWidth() / 2) * sx;
float yc = (view.getHeight() / 2) * sx;
matrix.postRotate(r, tx + xc, ty + yc);
}
}
break;
}
view.setImageMatrix(matrix);
return true;
}
/**
* Determine the space between the first two fingers
*/
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
/**
* Calculate the mid point of the first two fingers
*/
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
/**
* Calculate the degree to be rotated by.
*
* @param event
* @return Degrees
*/
private float rotation(MotionEvent event) {
double delta_x = (event.getX(0) - event.getX(1));
double delta_y = (event.getY(0) - event.getY(1));
double radians = Math.atan2(delta_y, delta_x);
return (float) Math.toDegrees(radians);
}
PictureCallback cameraPictureCallbackJpeg = new PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
// TODO Auto-generated method stub
Bitmap cameraBitmap = BitmapFactory.decodeByteArray(data, 0,
data.length);
int wid = cameraBitmap.getWidth();
int hgt = cameraBitmap.getHeight();
Bitmap newBitmap = Bitmap.createBitmap(wid, hgt,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(newBitmap);
canvas.drawBitmap(cameraBitmap, 0f, 0f, null);
canvas.drawBitmap(bitmap, matrix, null);
File storagePath = new File(
Environment.getExternalStorageDirectory() + "/PhotoAR/");
storagePath.mkdirs();
File myImage = new File(storagePath, Long.toString(System
.currentTimeMillis()) + ".jpg");
try {
FileOutputStream out = new FileOutputStream(myImage);
newBitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
out.flush();
out.close();
} catch (FileNotFoundException e) {
Log.d("In Saving File", e + "");
} catch (IOException e) {
Log.d("In Saving File", e + "");
}
}
};
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
if (previewing) {
camera.stopPreview();
previewing = false;
}
try {
if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
camera.setDisplayOrientation(90);
}
camera.setPreviewDisplay(cameraSurfaceHolder);
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
try {
camera = Camera.open();
} catch (RuntimeException e) {
Toast.makeText(
getApplicationContext(),
"Device camera is not working properly, please try after sometime.",
Toast.LENGTH_LONG).show();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
camera.stopPreview();
camera.release();
camera = null;
previewing = false;
}
}
and this is my xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<RelativeLayout
android:id="@+id/containerImg"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true" />
<ImageView
android:id="@+id/logoImageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/app_name"
android:scaleType="matrix" />
</RelativeLayout>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|center_vertical"
android:background="@drawable/camera" />
Thanks in advance.
Ok there are few things to fix
I know you want to see working code so here you go:
public class CameraActivity extends FragmentActivity implements OnTouchListener,
SurfaceHolder.Callback {
private Matrix matrix = new Matrix();
private Matrix savedMatrix = new Matrix();
private static final int NONE = 0;
private static final int DRAG = 1;
private static final int ZOOM = 2;
private int mode = NONE;
private PointF start = new PointF();
private PointF mid = new PointF();
private float oldDist = 1f;
private float d = 0f;
private float newRot = 0f;
private float[] lastEvent = null;
String logoImageId = "";
Bitmap bitmap = null;
private Camera camera = null;
private SurfaceView cameraSurfaceView = null;
private SurfaceHolder cameraSurfaceHolder = null;
private boolean previewing = false;
RelativeLayout relativeLayout;
int currentCameraId = 0;
private Button btnCapture = null;
ImageButton useOtherCamera = null;
ImageView logoImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFormat(PixelFormat.TRANSLUCENT);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_camera);
logoImageView = (ImageView) findViewById(R.id.logoImageView);
Bundle extras = getIntent().getExtras();
if (extras != null) {
logoImageId = extras.getString("logoImageId ");
}
try {
/*File file = new File(Environment.getExternalStorageDirectory()
+ "/" + getPackageName() + "/logo/" + logoImageId
+ ".jpg");
bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());*/
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
logoImageView.setImageBitmap(bitmap);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
logoImageView.setOnTouchListener(this);
relativeLayout = (RelativeLayout) findViewById(R.id.containerImg);
relativeLayout.setDrawingCacheEnabled(true);
cameraSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
cameraSurfaceHolder = cameraSurfaceView.getHolder();
cameraSurfaceHolder.addCallback(this);
btnCapture = (Button) findViewById(R.id.button);
btnCapture.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
camera.takePicture(null, null, cameraPictureCallbackJpeg);
}
});
}
public boolean onTouch(View v, MotionEvent event) {
// handle touch events here
ImageView view = (ImageView) v;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = DRAG;
lastEvent = null;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
lastEvent = new float[4];
lastEvent[0] = event.getX(0);
lastEvent[1] = event.getX(1);
lastEvent[2] = event.getY(0);
lastEvent[3] = event.getY(1);
d = rotation(event);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
lastEvent = null;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
matrix.set(savedMatrix);
float dx = event.getX() - start.x;
float dy = event.getY() - start.y;
matrix.postTranslate(dx, dy);
} else if (mode == ZOOM) {
float newDist = spacing(event);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = (newDist / oldDist);
matrix.postScale(scale, scale, mid.x, mid.y);
}
if (lastEvent != null && event.getPointerCount() == 3) {
newRot = rotation(event);
float r = newRot - d;
float[] values = new float[9];
matrix.getValues(values);
float tx = values[2];
float ty = values[5];
float sx = values[0];
float xc = (view.getWidth() / 2) * sx;
float yc = (view.getHeight() / 2) * sx;
matrix.postRotate(r, tx + xc, ty + yc);
}
}
break;
}
view.setImageMatrix(matrix);
return true;
}
/**
* Determine the space between the first two fingers
*/
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
/**
* Calculate the mid point of the first two fingers
*/
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
/**
* Calculate the degree to be rotated by.
*
* @param event
* @return Degrees
*/
private float rotation(MotionEvent event) {
double delta_x = (event.getX(0) - event.getX(1));
double delta_y = (event.getY(0) - event.getY(1));
double radians = Math.atan2(delta_y, delta_x);
return (float) Math.toDegrees(radians);
}
Camera.PictureCallback cameraPictureCallbackJpeg = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
// TODO Auto-generated method stub
BitmapFactory.Options options = new BitmapFactory.Options();
//o.inJustDecodeBounds = true;
Bitmap cameraBitmapNull = BitmapFactory.decodeByteArray(data, 0,
data.length, options);
int wid = options.outWidth;
int hgt = options.outHeight;
Matrix nm = new Matrix();
Camera.Size cameraSize = camera.getParameters().getPictureSize();
float ratio = relativeLayout.getHeight()*1f/cameraSize.height;
if (getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
nm.postRotate(90);
nm.postTranslate(hgt, 0);
wid = options.outHeight;
hgt = options.outWidth;
ratio = relativeLayout.getWidth()*1f/cameraSize.height;
}else {
wid = options.outWidth;
hgt = options.outHeight;
ratio = relativeLayout.getHeight()*1f/cameraSize.height;
}
float[] f = new float[9];
matrix.getValues(f);
f[0] = f[0]/ratio;
f[4] = f[4]/ratio;
f[5] = f[5]/ratio;
f[2] = f[2]/ratio;
matrix.setValues(f);
Bitmap newBitmap = Bitmap.createBitmap(wid, hgt,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(newBitmap);
Bitmap cameraBitmap = BitmapFactory.decodeByteArray(data, 0,
data.length, options);
canvas.drawBitmap(cameraBitmap, nm, null);
cameraBitmap.recycle();
canvas.drawBitmap(bitmap, matrix, null);
bitmap.recycle();
File storagePath = new File(
Environment.getExternalStorageDirectory() + "/PhotoAR/");
storagePath.mkdirs();
File myImage = new File(storagePath, Long.toString(System
.currentTimeMillis()) + ".jpg");
try {
FileOutputStream out = new FileOutputStream(myImage);
newBitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
out.flush();
out.close();
} catch (FileNotFoundException e) {
Log.d("In Saving File", e + "");
} catch (IOException e) {
Log.d("In Saving File", e + "");
}
}
};
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
if (previewing) {
camera.stopPreview();
previewing = false;
}
try {
if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
camera.setDisplayOrientation(90);
Camera.Size cameraSize = camera.getParameters().getPictureSize();
int wr = relativeLayout.getWidth();
int hr = relativeLayout.getHeight();
float ratio = relativeLayout.getWidth()*1f/cameraSize.height;
float w = cameraSize.width*ratio;
float h = cameraSize.height*ratio;
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams((int)h, (int)w);
cameraSurfaceView.setLayoutParams(lp);
}else {
camera.setDisplayOrientation(0);
Camera.Size cameraSize = camera.getParameters().getPictureSize();
float ratio = relativeLayout.getHeight()*1f/cameraSize.height;
float w = cameraSize.width*ratio;
float h = cameraSize.height*ratio;
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams((int)w, (int)h);
cameraSurfaceView.setLayoutParams(lp);
}
camera.setPreviewDisplay(cameraSurfaceHolder);
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
try {
camera = Camera.open();
Camera.Parameters params = camera.getParameters();
// Check what resolutions are supported by your camera
List<Camera.Size> sizes = params.getSupportedPictureSizes();
// setting small image size in order to avoid OOM error
Camera.Size cameraSize = null;
for (Camera.Size size : sizes) {
//set whatever size you need
//if(size.height<500) {
cameraSize = size;
break;
//}
}
if (cameraSize != null) {
params.setPictureSize(cameraSize.width, cameraSize.height);
camera.setParameters(params);
float ratio = relativeLayout.getHeight()*1f/cameraSize.height;
float w = cameraSize.width*ratio;
float h = cameraSize.height*ratio;
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams((int)w, (int)h);
cameraSurfaceView.setLayoutParams(lp);
}
} catch (RuntimeException e) {
Toast.makeText(
getApplicationContext(),
"Device camera is not working properly, please try after sometime.",
Toast.LENGTH_LONG).show();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
camera.stopPreview();
camera.release();
camera = null;
previewing = false;
}
}
note I took small camera resolution in order to avoid OOM error
The camera preview and the final picture taken usually use different resolution and aspect ratio; thus you need to consider this when you apply your overlay in post-process.
More precisely, you need to consider the following factors in your "apply overlay" process:
Instead Putting Ovelay on Camera you can load the captured image as a bitmap and draw the overlay logo on the bitmap. Save the bitmap.
Below code will combine the Two bitmap images that's is your captured image and your logo.
public Bitmap combineImages(Bitmap frame, Bitmap image) {
Bitmap cs = null;
Bitmap rs = null;
rs = Bitmap.createScaledBitmap(frame, image.getWidth() + 50,
image.getHeight() + 50, true);
cs = Bitmap.createBitmap(rs.getWidth(), rs.getHeight(),
Bitmap.Config.RGB_565);
Canvas comboImage = new Canvas(cs);
comboImage.drawBitmap(image, 25, 25, null);
comboImage.drawBitmap(rs, 0, 0, null);
if (rs != null) {
rs.recycle();
rs = null;
}
Runtime.getRuntime().gc();
return cs;
}
Hope this will give you some idea regarding it.
Some links which can help you.
1) Merge two bitmaps in android
2) Merging image from camera with image from drawables
3) how to merge to two bitmap one over another
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With