I want to make an app where user can take picture with back camera, and then with front camera.
So, after that I get two bitmaps and I want to combine them into one image.
This code I use for front Camera parameters:
//Set up picture orientation for saving...
Camera.Parameters parameters = theCamera.getParameters();
parameters.setRotation(90);
frontCamera.setParameters(parameters);
//Set up camera preview and set orientation to PORTRAIT
frontCamera.stopPreview();
frontCamera.setDisplayOrientation(90);
frontCamera.setPreviewDisplay(holder);
frontCamera.startPreview();
This code I use for taking picture with front camera
cameraObject.takePicture(shutterCallback, rawCallback, jpegCallback);
Callback for taking picture with back camera
PictureCallback jpegCallback = new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
backBitmap = decodeBitampFromByte(data, 0, 800, 800);
frontCameraObject.release();
initFrontCamera();
}
};
NOTE: Similar code is for taking picture with front camera. I get two bitmaps, and then I try to combine them with code below, but I get saved bitmap with wrong orientation.
This code I use for combing two bitamps: frontBitmap, backBitmap.
public Bitmap combineImages(Bitmap c, Bitmap s, String loc)
{
Bitmap cs = null;
int w = c.getWidth() + s.getWidth();
int h;
if(c.getHeight() >= s.getHeight()){
h = c.getHeight();
}else{
h = s.getHeight();
}
cs = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas comboImage = new Canvas(cs);
comboImage.drawBitmap(c, 0f, 0f, null);
comboImage.drawBitmap(s, c.getWidth, 0f, null);
String tmpImg = String.valueOf(System.currentTimeMillis()) + ".png";
OutputStream os = null;
try {
os = new FileOutputStream(loc + tmpImg);
cs.compress(CompressFormat.PNG, 100, os);
} catch (IOException e) {
Log.e("combineImages", "problem combining images", e);
}
return cs;
}
NOTE Image with bottle of the water is taken with back camera, and other is with front camera.
Try changing comboImage.drawBitmap(s, c.getWidth, 0f, null); to
comboImage.drawBitmap(s, 0f,c.getHeigh, null);
Related
I have an old Android device (Android 4.1.2, API 16) which I want to use as a "CCTV-like" device. I need to take a picture every 20 seconds and to do this I have implemented the following code on an Activity.
The onCreate() method is as the following:
//To keep the display on (the phone is always attached to the power supply)
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
FrameLayout preview = findViewById(R.id.camera_preview);
initializeCamera();
Timer timerPhoto = new Timer();
timerPhoto.schedule(new TimerTask() {
#Override
public void run() {
mCamera.takePicture(null, null, mPictureCallback);
mCamera.startPreview();
}
}, 5000, 20000); //start after 5 seconds, take pic every 20 secs
The following method for the camera initialisation:
private void initializeCamera() {
if (mCamera == null) {
mCamera = getCameraInstance();
Timber.d("Camera initialized");
}
mCameraPreview = new IaCameraHelper(this, mCamera);
preview.addView(mCameraPreview);
}
And this is the callback which handles the picture:
private static Bitmap originalPhotoBitmap = null;
Camera.PictureCallback mPictureCallback = (data, camera) -> {
originalPhotoBitmap = addDateTimeToImage(rotateBitmap(BitmapFactory.decodeByteArray(data, 0, data.length), 180));
//Sending the bitmap string to the server
controller.sendImage(bitmapToString(originalPhotoBitmap));
originalPhotoBitmap.recycle();
BitmapManager.rotatedBitmap.recycle();
BitmapManager.modBitmap.recycle();
originalPhotoBitmap = null;
BitmapManager.rotatedBitmap = null;
BitmapManager.modBitmap = null;
};
In the BitmapManager, I have the following methods which have been used to manipulate the bitmap:
public static Bitmap rotatedBitmap = null;
public static Bitmap modBitmap = null;
public static Bitmap rotateBitmap(Bitmap source, float angle) {
Matrix matrix = new Matrix();
matrix.postRotate(angle);
rotatedBitmap = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
return rotatedBitmap;
}
public static Bitmap addDateTimeToImage(Bitmap originalPhoto) {
modBitmap = Bitmap.createBitmap(originalPhoto.getWidth(), originalPhoto.getHeight(), Bitmap.Config.ARGB_8888);
String dateTime = sdf.format(Calendar.getInstance().getTime());
Canvas cs = new Canvas(modBitmap);
Paint tPaint = new Paint();
tPaint.setTextSize(30);
tPaint.setColor(Color.RED);
tPaint.setStyle(Paint.Style.FILL);
cs.drawBitmap(originalPhoto, 0f, 0f, null);
float height = tPaint.measureText("yY");
cs.drawText(dateTime, 20f, height + 15f, tPaint);
return modBitmap;
}
public static String bitmapToString(Bitmap bitmap) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] b = baos.toByteArray();
return Base64.encodeToString(b, Base64.DEFAULT);
}
As you can see, I send the bitmap string to a controller which sends the image to a local server in the network.
Generally, the application works like a charm, but sometimes (generally after 6-7 hours) I face the following errors (out-of-memory) that I don't know how to solve.
02-21 13:12:03.292 29621-29632/com.rbapp E/dalvikvm-heap: Out of memory on a 127547-byte allocation.
02-21 13:12:03.302 29621-29632/com.rbapp E/Camera-JNI: Couldn't allocate byte array for JPEG data
As you can see, I try to recycle all the generated bitmaps and I set them to null as soon as I send them to the controller, but the error persists.
When the errors occur, the application continues to run (also the camera preview), but the images are not sent (there are try-catches which allows the execution of the app) but as I press the "back" button on the phone, the application doesn't respond at all.
I have programmed an App with a CameraPreview. When I take a Photo now, the App save it with 176 x 144 Pixels. Can I Change the width an the height?
I use the Camera Api, not Camera2.
When I took photos with the normal Camera-App, it saved Images with 2368x4208 Pixels.
This is where the Photos where taken
public void onPictureTaken(byte[] data, Camera camera) {
Bitmap rawImg = BitmapFactory.decodeByteArray(data, 0, data.length);
Log.e("TakePicture", "Picture Callback erreicht");
shotAnalyser.startAnalysation(rawImg, data);
}
Here I grab the Data and make a Bitmap
public void startAnalysation(final Bitmap rawImg, final byte[] data){
Bitmap rawBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
// Ermitteln der nötigen Bild-Eigenschaften
int width = rawBitmap.getWidth();
int height = rawBitmap.getHeight();
}
Here I tried to Change the PictureSize
public Camera getCameraInstance(){
Camera c = null;
try {
releaseCameraAndPreview();
c = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK); // attempt to get a Camera instance
Log.e(LOG, "CameraInstance: " + c + " RUNS");
Camera.Parameters parameters = c.getParameters();
parameters.set("jpeg-quality", 70);
parameters.setPictureFormat(PixelFormat.JPEG);
parameters.setPictureSize(2048, 1232);
c.setParameters(parameters);
}
catch (Exception e){
}
return c; // returns null if camera is unavailable
}
I've googled a lot, but I can't find anything.
When I use following code, it ends up with outofmemory exception. After doing researh Render script looks like a good candidate. Where can I find sample code for similar operation and how can integrate it to my project.
public Bitmap rotateBitmap(Bitmap image, int angle) {
if (image != null) {
Matrix matrix = new Matrix();
matrix.postRotate(angle, (image.getWidth()) / 2,
(image.getHeight()) / 2);
return Bitmap.createBitmap(image, 0, 0, image.getWidth(),
image.getHeight(), matrix, true);
}
return null;
}
Basically rotating bitmap is a task of rotating 2D array without using additional memory. And this is the correct implementation with RenderScript: Android: rotate image without loading it to memory .
But this is not necessary if all you want is just to display rotated Bitmap. You can simply extend ImageView and rotate the Canvas while drawing on it:
canvas.save();
canvas.rotate(angle, X + (imageW / 2), Y + (imageH / 2));
canvas.drawBitmap(imageBmp, X, Y, null);
canvas.restore();
What about ScriptIntrinsic, since it's just a built-in RenderScript kernels for common operations you cannot do nothing above the already implemented functions: ScriptIntrinsic3DLUT, ScriptIntrinsicBLAS, ScriptIntrinsicBlend, ScriptIntrinsicBlur, ScriptIntrinsicColorMatrix, ScriptIntrinsicConvolve3x3, ScriptIntrinsicConvolve5x5, ScriptIntrinsicHistogram, ScriptIntrinsicLUT, ScriptIntrinsicResize, ScriptIntrinsicYuvToRGB. They do not include functionality to rotate bitmap at the moment so you should create your own ScriptC script.
Try this code..
private Bitmap RotateImage(Bitmap _bitmap, int angle) {
Matrix matrix = new Matrix();
matrix.postRotate(angle);
_bitmap = Bitmap.createBitmap(_bitmap, 0, 0, _bitmap.getWidth(), _bitmap.getHeight(), matrix, true);
return _bitmap;
}
Use this code when select image from gallery.
like this..
File _file = new File(file_name);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
Bitmap bitmap = BitmapFactory.decodeFile(file_name, options);
try {
ExifInterface exif = new ExifInterface(file_name);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
bitmap = RotateImage(bitmap, 90);
} else if (orientation ==ExifInterface.ORIENTATION_ROTATE_270) {
bitmap = RotateImage(bitmap, 270);
}
} catch (Exception e) {
e.printStackTrace();
}
image_holder.setImageBitmap(bitmap);
I'm working with a set of layered images (think stacked) and I need to combine them into one element.
I'm basing my solution off Combine multiple bitmap into one
//send a map to the method that has my stored image locations in order
private Bitmap combineImageIntoOne(NavigableMap<Integer, String> layerImages) {
//size of my bitmaps
int w = 400, h = 400;
//bitmap placeholder
Bitmap productIndex = null;
//flattened layers
Bitmap temp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
//canvas to write layers to
Canvas canvas = new Canvas(temp);
int top = 0;
for (Map.Entry<Integer, String> e : layerImages.entrySet()) {
//create the layer bitmap
productIndex = decodeSampledBitmapFromResource(getResources(), e.getValue(), 400, 400);
//add layer to canvas
canvas.drawBitmap(productIndex, 0f, top, null);
}
//convert temp to a BitmapDrawable
Drawable d = new BitmapDrawable(getResources(),temp);
//set my image view to have the flattened image
carBase.setImageDrawable(d);
return temp;
}
The decodeSampledBitmapFromResource come from the Android docs about loading large bitmaps: Loading Large Bitmaps Efficiently You can review the code on that doc to see what I"m doing. I didn't edit the Android code much.
I've been using the Android code just fine to add layers to the FrameLayout but ended up running out of memory when the layers starting getting pretty high in number. This combining method is being used to conserve memory space.
Any ideas why the final bitmap doesn't have any content?
Reference LINK <-------------------------
public Bitmap combineImages(Bitmap c, Bitmap s) { // can add a 3rd parameter 'String loc' if you want to save the new image - left some code to do that at the bottom
Bitmap cs = null;
int width, height = 0;
if(c.getWidth() > s.getWidth()) {
width = c.getWidth() + s.getWidth();
height = c.getHeight();
} else {
width = s.getWidth() + s.getWidth();
height = c.getHeight();
}
cs = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas comboImage = new Canvas(cs);
comboImage.drawBitmap(c, 0f, 0f, null);
comboImage.drawBitmap(s, c.getWidth(), 0f, null);
// this is an extra bit I added, just incase you want to save the new image somewhere and then return the location
/*String tmpImg = String.valueOf(System.currentTimeMillis()) + ".png";
OutputStream os = null;
try {
os = new FileOutputStream(loc + tmpImg);
cs.compress(CompressFormat.PNG, 100, os);
} catch(IOException e) {
Log.e("combineImages", "problem combining images", e);
}*/
return cs;
}
When you take a picture with the front facing camera in Android the preview is reflected along the Y axis to make the image seen appear as if the user was looking in the mirror. I want to undo this effect (apply a second reflection) or just stop the one thats done automatically.
I though to use this:
Camera mCamera;
....
mCamera.setPreviewCallback(...);
But I dont really know what to do with the overriding of
onPreviewFrame(byte[] data, Camera camera){...}
Whats the best way I can achieve what I've described?
Note I am trying to apply this effect to the live preview, not images that are already taken.
First when you open your camera instance with Camera.open() you should open front camera with Camera.open(getSpecialFacingCamera())
private int getSpecialFacingCamera() {
int cameraId = -1;
// Search for the front facing camera
int numberOfCameras = Camera.getNumberOfCameras();
for (int i = 0; i < numberOfCameras; i++) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(i, info);
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
cameraId = i;
break;
}
}
return cameraId;
}
Then in your callback method where camera data is converting in to image
you can use this code to keep it normal
public void onPictureTaken(byte[] data, Camera camera){
Bitmap newImage = null;
Bitmap cameraBitmap;
if (data != null) {
cameraBitmap = BitmapFactory.decodeByteArray(data, 0, (data != null) ? data.length : 0);
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
// use matrix to reverse image data and keep it normal
Matrix mtx = new Matrix();
//this will prevent mirror effect
mtx.preScale(-1.0f, 1.0f);
// Setting post rotate to 90 because image will be possibly in landscape
mtx.postRotate(90.f);
// Rotating Bitmap , create real image that we want
newImage = Bitmap.createBitmap(cameraBitmap, 0, 0, cameraBitmap.getWidth(), cameraBitmap.getHeight(), mtx, true);
}else{// LANDSCAPE MODE
//No need to reverse width and height
newImage = Bitmap.createScaledBitmap(cameraBitmap, screenWidth, screenHeight, true);
cameraBitmap = newImage;
}
}
}
you can pass newImage in canvas and create jpeg image and save it on device.
Do not forgot Camera is deprecated in Api level 21...
You can use Matrix to flip the image data, something like:
byte[] baImage = null;
Size size = camera.getParameters().getPreviewSize();
ByteArrayOutputStream os = new ByteArrayOutputStream();
YuvImage yuv = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
yuv.compressToJpeg(new Rect(0, 0, size.width, size.height), 100, os);
baImage = os.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length);
Matrix matrix = new Matrix();
matrix.preScale(-1.0f, 1.0f);
Bitmap mirroredBitmap = Bitmap.createBitmap(bitmap, 0, 0, size.width, size.height, matrix, false);