Reputation: 16544
I have an activity layed out as a FrameLayout
which serves as a container view for a fragment. This fragment contains a SurfaceView in whose SurfaceHolder I show the camera preview.
On click/tap of the SurfaceView takePicture for the camera is being called with a PhotoHandler
callback which implements PictureCallback
. The overridden method onPictureTaken
receives a byte array containing the image data, which it stores using a FileOutputStream.
I restricted the activity to portrait orientation (in manifest) and used a method setCameraDisplayOrientation
(found on stackoverflow) which will show the camera preview with portrait orientation, too.
Everything is working quite well ... except for two things:
So my questions are
Can I increase image quality (to full size)?
Can I make sure that the resulting image files have portrait orientation?
The following is some of my code
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.xxxxxxxxxxxxxxx" >
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".xxxxxxxxxx"
android:label="@string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
onPictureTaken
@Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFileDir = getDir();
if (!pictureFileDir.exists() && !pictureFileDir.mkdirs()) {
Toast.makeText(context, "Can't create directory to save image.",
Toast.LENGTH_LONG).show();
return;
}
String filename = pictureFileDir.getPath() + File.separator + photoFile;
File pictureFile = new File(filename);
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (Exception error) {
Toast.makeText(context, "Image could not be saved.",
Toast.LENGTH_LONG).show();
}
}
Please let me know if you need anything else ...
EDIT: I found a solution for the size issue (see answer below). But I still have the issue of the rotated resulting image file. After a lot of testing I get the impression that images are always stored in landscape format even if shot in portrait mode. Maybe some EXIF information in the file marks it as portrait ... I keep testing, but you might still be able to help me here :-)
EDIT2: My idea regarding Exif information seems to be the correct starting point. The standard orientation (at least on my phone's camera) seems to be "landscape rotated 90 degrees to the left". At least, this is what the Exif information of the image file tells me: 0th row of the image is on the top, 0th column is on the left (TAG_ORIENTATION is 1)
Even though I clearly took the photo in portrait mode, the Exif information doesn't reflect that. It seems to "think" that the image is in landscape mode, so I have to rotate it 90 degrees to the right in order to display it. This seems to be wrong to me ... how can I make sure that Exif information in the image reflects the camera/app orientation?? (TAG_ORIENTATION should obviously be 6)
Don't get me wrong: I'd still need to rotate 90 degrees to the right, but TAG_ORIENTATION of the Exif information should tell me to do so. Currently I have to rely on my knowledge about how the photo was taken in the first place.
See: Android: Bitmaps loaded from gallery are rotated in ImageView
and: http://sylvana.net/jpegcrop/exif_orientation.html
EDIT3: Solution ... see below
Upvotes: 0
Views: 1982
Reputation: 16544
Ok, I was able to at least solve the size issue. I discovered the PictureSize
parameter with which I can set the desired resulting image size depending on the phone/camera capabilities
Camera.Parameters params = camera.getParameters();
List<Camera.Size> sizeList = params.getSupportedPictureSizes();
int chosenSize = Helper.getPictureSizeIndexForHeight(sizeList, 800);
params.setPictureSize(sizeList.get(chosenSize).width, sizeList.get(chosenSize).height);
camera.setParameters(params);
and the Helper method which helps me choose the picture size for the minimum height greather than the second parameter (or the maximum available size)
public static int getPictureSizeIndexForHeight(List<Camera.Size> sizeList, int height) {
int chosenHeight = -1;
for(int i=0; i<sizeList.size(); i++) {
if(sizeList.get(i).height < height) {
chosenHeight = i-1;
if(chosenHeight==-1)
chosenHeight = 0;
break;
}
}
return chosenHeight;
}
This works, but I sill have the issue of the rotated image result file
EDIT: I found out that I need to set another parameter called Rotation
depending on the phone orientation and the UI orientation. In that case, the phone will set the correct exif information, so that the image will not be shown in landscape if taken in portrait. I don't need to rotate any more, and the image is also shown correctly in the album.
public static void setRotationParameter(Activity activity, int cameraId, Camera.Parameters param) {
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().getDefaultDisplay()
.getRotation();
rotation = (rotation + 45) / 90 * 90;
int toRotate = (info.orientation + rotation) % 360;
param.setRotation(toRotate);
}
Upvotes: 4