If I use standard camera via Intent to capture image:
Open Camera:
val takePicture = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
if (takePicture.resolveActivity(packageManager) != null) {
startActivityForResult(takePicture, TAKE_PICTURE)
}
Camera Preview
Result display on ImageView
If I use Camera2 API at: git: https://github.com/googlesamples/android-Camera2Basic
Result of Image not display portrait
Camera 2 Preview
Result display on ImageView
My code display Image:
val bitmap = BitmapFactory.decodeFile(file.toString())
imagePreview.setImageBitmap(bitmap)
}
How setting Camera2 API to display result the same standard camera?
In Camera2Basic example, the ImageSaver does not rotate the captured JPEG with regards to device orientation. Instead, Camera2BasicFragment.captureStillPicture() sets CaptureRequest.JPEG_ORIENTATION, which is only a recommendation for the camera firmware.
Camera devices may either encode this value into the JPEG EXIF header, or rotate the image data to match this orientation. When the image data is rotated, the thumbnail data will also be rotated.
Most often, this recommendation 'only' sets the header, but some devices miss even that. See a recent article on this feature and its reliability.
Please note that the EXIF orientation tag is not respected by all viewer software, therefore often the stock Camera applications do rotate the actual JPEG to default orientation.
Your code that loads the captured picture to ImageView currently ignores this tag. You can use ExifInterface.getAttributeInt(TAG_ORIENTATION) to extract the orientation from the file or input stream. Or, if you capture an image and immediately display it, you can get device orientation directly from the sensor. Now it's time to decide if the camera stored the image as portrait (i.e. width is smaller than height), or as landscape, in which case it's your duty to rotate it for display. Don't rotate the bitmap according to this orientation. Instead, you can call imagePreview.setImageMatrix() to display the image correctly.
By the way, please don't decode the JPEG to full-scale bitmap in memory if you only need it to be passed to your ImageView: this may consume too much RAM. The easiest one-liner is to call setImageURI() instead.
Related
I have made an app which takes pictures (portrait, landscape or selfie) using the Google Camera2 sample. Everything works, I can take the pictures, they are saved, etc.
But when I open my phone's (Samsung S7) gallery then all the selfies and portrait pictures are rotated 90 degrees. The landscape pictures are fine though. I have seen a lot of post about how to read images in the correct orientation, but what about saving them properly?
I have my own gallery in my app and there the pictures are loaded correctly (using Glide) without any special rotation fixing, so I am not sure what I did wrong and most importantly, how do I fix this?
Are you using the JPEG_ORIENTATION control in your still capture request? If not, that may be the issue - that control tells the camera device how to rotate the final JPEG image to be right-side-up.
So you need to update the value in that control to describe how the image sensor currently lines up relative to the world.
To do that calculation, you'll need input from the accelerometer (which tells you which way is down), and then some basic math - reproducing this from the link above:
private int getJpegOrientation(CameraCharacteristics c, int deviceOrientation) {
if (deviceOrientation == android.view.OrientationEventListener.ORIENTATION_UNKNOWN) return 0;
int sensorOrientation = c.get(CameraCharacteristics.SENSOR_ORIENTATION);
// Round device orientation to a multiple of 90
deviceOrientation = (deviceOrientation + 45) / 90 * 90;
// Reverse device orientation for front-facing cameras
boolean facingFront = c.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT;
if (facingFront) deviceOrientation = -deviceOrientation;
// Calculate desired JPEG orientation relative to camera orientation to make
// the image upright relative to the device orientation
int jpegOrientation = (sensorOrientation + deviceOrientation + 360) % 360;
return jpegOrientation;
}
where the input deviceOrientation comes from the sensors API.
An image viewer is supposed to examine the EXIF tag and rotate the image in accordance with the orientation tag. This allows camera apps and similar software to save the images in whatever orientation they come in, without having to rotate the image before saving it.
Libraries like Glide and Picasso will do this for you, if you give them access to the full JPEG (e.g., file Uri, content Uri, https URL). That is because they have access to both the EXIF tags and the resulting ImageView, and so they can tell the ImageView to rotate the image.
However, not everybody uses such libraries. ImageView on its own deals with things like Bitmap, where those EXIF tags have been lost in the decoding process.
You, as the author of a camera app, have two main options here:
You could examine the EXIF tags, see that the image needs to be rotated, rotate it yourself, and save the rotated image (removing the orientation tag but arranging to retain the others). However, this may fail with an OutOfMemoryError, particular for camera images, as these images tend to be big.
You could shrug your shoulders and move on, as it's really not your problem. As you note, other gallery apps do not exhibit the issue, because they were tested adequately, and the original gallery app that you tried did not.
If you go with option #1, it turns into option #2 if you get the OutOfMemoryError.
I've been trying to use the Android ACTION_IMAGE_CAPTURE intent and ACTION_GET_CONTENT intent to either take a photo or pick one. The problem I'm having is that when I when I try to take a photo using the Android photo intent in portrait mode, it saves it in landscape orientation.
I'm trying to save the Bitmap of the correctly orientated photo from a URI string.
I found this question: Android Camera Intent Saving Image Landscape When Taken Portrait, which is the exact same problem I'm having, but the answer is incomplete and didn't work for me. For example, what is the resizedBitmap, opts, and is file Uri.getPath()?
Well some cameras lock the landscape mode as default mode of camera(Samsung note 2) so if you take a picture in potrait mode the image is still saved in landscape mode. Most of the camera will add metadata into the image like the camera vendor, model,etc. Amongst various metadata that can be present the one we are intrested in is the rotation data. It specifies by what degrees the image is to be rotated. For knowing the rotation you can use ExifInterface class.
resizedBitmap Images are stored as bitmap objects in android. As an image can be large loading them whole into memory can lead to outofmemory error's and make your app consume more memory. So a bitmap is first resized to appropriate size and then loaded into memory.
opts By opts you must be referring to BitmapFactory.Options method. It is a class that provides methods to change the behaviour of bitmaps like making it mutable(is set to true you can apply effects like grayscale to this bitmap) , find its height and width in pixels without loading it to RAM,etc.
file Its a class used to perform CRUD operations in any file stored in the system.
Uri.getPath() this method returns the path where your image is stored or null.
I looked everywhere for a solution but couldn't use anything useful. I'm using SurfaceView and FrameLayout for custom in-app camera. I have a button that calls "mCamera.takePicture()" function. In the Callback, I save the picture as it is; the problem is that the picture is rotated and flipped, and scaled in weird ratio.
I know that it is happening mostly because I set the camera parameter's setPreviewSize to an optimal size, and rotated it using mCamera.setDisplayOrientation(). The preview looks beautiful. But when I take a picture and save it, that's where it gets messed up.
Camera.Parameters cp = mCamera.getParameters();
Size theSize = getOptimalPreviewSize(opt, w, h);
cp.setPreviewSize(theSize.width, theSize.height);
mCamera.setDisplayOrientation(90);
mCamera.setParameters(cp);
The above code is written in surfaceChanged function.
How do I make the saved picture as it's shown in the preview?
Screenshot of what is shown in the preview of the camera. Size fine, rotation fine:
This is after the picture has been taken. Look at the monitor, collection of CDs and the plug. It's squashed and the monitor looks like a wave:
The image returned in pictureTaken() is not effected by Camera.setDisplayOrientation(). It is in Jpeg compressed format, so you can set JPEG rotation via Exif header without decoding it. This is what Camera.setRotation() often does, but on some devices it actually performs rotation in hardware. This is the most efficient method, but some viewers may still show a rotated image.
Alternatively, you can use JPEG lossless rotation, using jpegtran.
On SourceForge, there is a Java open source class LLJTran. The Android port is on GitHub.
I'm an intermediate android programmer. I've a simple application created for learning camera. My app is using camera.takePicture() method to register callbacks for JPEG callback and eventually capture the picture.
But I feel that it may also be possible to capture the image using setOneShotPreviewCallback() and providing a callback.
My question is:
Will there be any differences in image quality between the 2 approaches?
Any additional things to be taken care of when trying to construct image using setOneShotPreviewCallback()?
Thanks in advance.
takePicture() uses (potentially) the camera's full resolution. The preview gives you the image shown on screen which is more usually the screen's resolution. The picture will be higher resolution in general and higher quality. Note that you get something like JPEG-encoded data from the picture callback, but raw image buffer data in the preview callback.
The person is using the surface view to capture the image by camera its quality will be good
Is it possible to take a thumbnail photo using the camera? I see methods like getJpegThumbnailQuality but I don't see anything for taking the actual thumbnail. I must do this using the Camera API and not using an Intent.
By any means, Camera itself will not directly produce a Bitmap of thumbnail size. Most devices have limited set of picture resolutions for camera. However you can create another scaled down bitmap from the picture camera provides you.