フロントエンドカメラとバックエンドカメラの両方から写真を撮るポートレートモードのカメラアプリがあります.SDカードに画像を保存し、常に0を与える対応するexif値を見つけようとしていますが、期待されるexif方向を取得していますデバイスに保存されている他の画像の値(ダウンロードされた画像など)。
どうすれば修正できますか?誰でも私を助けることができますか?
写真を保存し、向きを見つけるために使用されるコードは次のとおりです
PictureCallback myPictureCallback_JPG = new PictureCallback() {
@Override
public void onPictureTaken(byte[] arg0, Camera arg1) {
// TODO Auto-generated method stub
try {
File APP_FILE_PATH = new File(Environment.getExternalStorageDirectory()
.getPath() + "/Myapp/");
if (!APP_FILE_PATH.exists()) {
APP_FILE_PATH.mkdirs();
}
File file = new File(APP_FILE_PATH, "image.jpg");
FileOutputStream fos = new FileOutputStream(file);
fos.write(arg0);
fos.close();
imageFileUri=Uri.fromfile(file); getApplicationContext().getContentResolver().notifyChange(
imageFileUri, null);
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://"
+ Environment.getExternalStorageDirectory())));
ExifInterface exif = new ExifInterface(file.getAbsolutePath());
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
} catch (Exception e) {
}
}
};
以下は、作成および変更された機能のコードのコードです。
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
List<Size> sizes = parameters.getSupportedPreviewSizes();
Size optimalSize = getOptimalPreviewSize(sizes, width, height);
parameters.setPreviewSize(optimalSize.width, optimalSize.height);
camera.setParameters(parameters);
camera.startPreview();
startPreview();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Gingerbread) {
Camera.CameraInfo info=new Camera.CameraInfo();
for (int i=0; i < Camera.getNumberOfCameras(); i++) {
Camera.getCameraInfo(i, info);
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
camera=Camera.open(i);
defaultCameraId = i;
}
}
}
if (camera == null) {
camera=Camera.open();
}
try {
camera.setPreviewDisplay(surfaceHolder);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Camera.Parameters parameters = camera.getParameters();
Android.hardware.Camera.CameraInfo info =
new Android.hardware.Camera.CameraInfo();
Android.hardware.Camera.getCameraInfo(defaultCameraId, info);
int rotation = this.getWindowManager().getDefaultDisplay()
.getRotation();
if (Integer.parseInt(Build.VERSION.SDK) >= 8)
{
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;
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
}
else
{
parameters.set("orientation", "portrait");
}
camera.setParameters(parameters);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
if (sizes == null) return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
また、Samsungデバイスでも同じ問題に直面しました。後で ExifInterface を実装し、正常に解決しました。
どのモードでも画像は撮影され、常にポートレートモードでのみ保存され、フェッチ中はポートレートモードで戻ります。私が目標を達成するために使用したコードの下に、私はバックカメラ内に実装しました。
カメラの意図@
Intent intent = new Intent(Android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
startActivityForResult(intent, 1212);
onActivityResult @
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1212) {
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));
Bitmap bitmap;
//bitmap=GlobalMethods.decodeSampledBitmapFromResource(_path, 80, 80);
bitmap=GlobalMethods.decodeFile(_path);
if (bitmap == null) {
imgMed.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.add_photo));
}
else {
imgMed.setImageBitmap(bitmap);
imgMed.setScaleType(ScaleType.FIT_XY);
}
}
}
decodeFile @
public static Bitmap decodeFile(String path) {
int orientation;
try {
if(path==null){
return null;
}
// decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
// Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE = 70;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 4;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale++;
}
// decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
Bitmap bm = BitmapFactory.decodeFile(path,o2);
Bitmap bitmap = bm;
ExifInterface exif = new ExifInterface(path);
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
Log.e("orientation",""+orientation);
Matrix m=new Matrix();
if((orientation==3)){
m.postRotate(180);
m.postScale((float)bm.getWidth(), (float)bm.getHeight());
// if(m.preRotate(90)){
Log.e("in orientation",""+orientation);
bitmap = Bitmap.createBitmap(bm, 0, 0,bm.getWidth(),bm.getHeight(), m, true);
return bitmap;
}
else if(orientation==6){
m.postRotate(90);
Log.e("in orientation",""+orientation);
bitmap = Bitmap.createBitmap(bm, 0, 0,bm.getWidth(),bm.getHeight(), m, true);
return bitmap;
}
else if(orientation==8){
m.postRotate(270);
Log.e("in orientation",""+orientation);
bitmap = Bitmap.createBitmap(bm, 0, 0,bm.getWidth(),bm.getHeight(), m, true);
return bitmap;
}
return bitmap;
}
catch (Exception e) {
}
return null;
}
この問題はかなり前に解決されましたが、カメラを正しく動作させるのにいくつかの困難に直面したため、exifを使用せずに最終的な解決策を示します。これが他の人に役立つことを願っています:
public void startPreview() {
try {
Log.i(TAG, "starting preview: " + started);
// ....
Camera.CameraInfo camInfo = new Camera.CameraInfo();
Camera.getCameraInfo(cameraIndex, camInfo);
int cameraRotationOffset = camInfo.orientation;
// ...
Camera.Parameters parameters = camera.getParameters();
List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
Camera.Size previewSize = null;
float closestRatio = Float.MAX_VALUE;
int targetPreviewWidth = isLandscape() ? getWidth() : getHeight();
int targetPreviewHeight = isLandscape() ? getHeight() : getWidth();
float targetRatio = targetPreviewWidth / (float) targetPreviewHeight;
Log.v(TAG, "target size: " + targetPreviewWidth + " / " + targetPreviewHeight + " ratio:" + targetRatio);
for (Camera.Size candidateSize : previewSizes) {
float whRatio = candidateSize.width / (float) candidateSize.height;
if (previewSize == null || Math.abs(targetRatio - whRatio) < Math.abs(targetRatio - closestRatio)) {
closestRatio = whRatio;
previewSize = candidateSize;
}
}
int rotation = getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break; // Natural orientation
case Surface.ROTATION_90:
degrees = 90;
break; // Landscape left
case Surface.ROTATION_180:
degrees = 180;
break;// Upside down
case Surface.ROTATION_270:
degrees = 270;
break;// Landscape right
}
int displayRotation;
if (isFrontFacingCam) {
displayRotation = (cameraRotationOffset + degrees) % 360;
displayRotation = (360 - displayRotation) % 360; // compensate
// the
// mirror
} else { // back-facing
displayRotation = (cameraRotationOffset - degrees + 360) % 360;
}
Log.v(TAG, "rotation cam / phone = displayRotation: " + cameraRotationOffset + " / " + degrees + " = "
+ displayRotation);
this.camera.setDisplayOrientation(displayRotation);
int rotate;
if (isFrontFacingCam) {
rotate = (360 + cameraRotationOffset + degrees) % 360;
} else {
rotate = (360 + cameraRotationOffset - degrees) % 360;
}
Log.v(TAG, "screenshot rotation: " + cameraRotationOffset + " / " + degrees + " = " + rotate);
Log.v(TAG, "preview size: " + previewSize.width + " / " + previewSize.height);
parameters.setPreviewSize(previewSize.width, previewSize.height);
parameters.setRotation(rotate);
camera.setParameters(parameters);
camera.setPreviewDisplay(mHolder);
camera.startPreview();
Log.d(TAG, "preview started");
started = true;
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
問題は、onPictureTaken
関数にexif情報を手動で入力する必要があることです。
画像(jpg)を保存したら、Exifインターフェースを作成し、パラメーターを自分で入力する必要があります。
....
exif = new ExifInterface(file.getAbsolutePath());
exif.setAttribute(ExifInterface.TAG_ORIENTATION, orientation_detected_by_you_application);
exif.saveAttributes();
携帯電話にある他の写真は、撮影した写真にexif情報を入れるアプリケーションで作成されています。
向きを検出するには:
public void enableOrientationListener(){
if (mOrientationEventListener == null) {
mOrientationEventListener = new OrientationEventListener(getContext(), SensorManager.SENSOR_DELAY_NORMAL) {
@Override
public void onOrientationChanged(int orientation) {
// determine our orientation based on sensor response
int lastOrientation = mOrientation;
Display display = null;
if(parentActivity == null){
display = ((WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
}else{
display = parentActivity.getWindowManager().getDefaultDisplay();
}
if (display.getOrientation() == Surface.ROTATION_0) { // landscape oriented devices
if (orientation >= 315 || orientation < 45) {
if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {
mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
}
} else if (orientation < 315 && orientation >= 225) {
if (mOrientation != ORIENTATION_PORTRAIT_INVERTED) {
mOrientation = ORIENTATION_PORTRAIT_INVERTED;
}
} else if (orientation < 225 && orientation >= 135) {
if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
}
} else if (orientation <135 && orientation > 45) {
if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {
mOrientation = ORIENTATION_PORTRAIT_NORMAL;
}
}
} else { // portrait oriented devices
if (orientation >= 315 || orientation < 45) {
if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {
mOrientation = ORIENTATION_PORTRAIT_NORMAL;
}
} else if (orientation < 315 && orientation >= 225) {
if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {
mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
}
} else if (orientation < 225 && orientation >= 135) {
if (mOrientation != ORIENTATION_PORTRAIT_INVERTED) {
mOrientation = ORIENTATION_PORTRAIT_INVERTED;
}
} else if (orientation <135 && orientation > 45) {
if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
}
}
}
}
};
}
if (mOrientationEventListener.canDetectOrientation()) {
mOrientationEventListener.enable();
}
}
private static final int ORIENTATION_PORTRAIT_NORMAL = 1;
private static final int ORIENTATION_PORTRAIT_INVERTED = 2;
private static final int ORIENTATION_LANDSCAPE_NORMAL = 3;
private static final int ORIENTATION_LANDSCAPE_INVERTED = 4;
public void disableOrientationListener(){
if(mOrientationEventListener != null){
mOrientationEventListener.disable();
}
}
また、画像の方向属性としてmOrientation
を設定する必要があります。
で例外を無視しています:
try {
// Code
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
} catch (Exception e) {
}
試してください:
try {
// Code
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
} catch (Exception e) {
e.printStackTrace();
}
そしてlogcatを投稿してください。例外を遠ざけることは決して賢明ではありません。