Kamera amacı kullanılarak yakalanan bir görüntü Android'deki bazı cihazlarda neden döndürülüyor?


376

Bir görüntü yakalıyorum ve görüntü görünümüne ayarlıyorum.

public void captureImage() {

    Intent intentCamera = new Intent("android.media.action.IMAGE_CAPTURE");
    File filePhoto = new File(Environment.getExternalStorageDirectory(), "Pic.jpg");
    imageUri = Uri.fromFile(filePhoto);
    MyApplicationGlobal.imageUri = imageUri.getPath();
    intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
    startActivityForResult(intentCamera, TAKE_PICTURE);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intentFromCamera) {
    super.onActivityResult(requestCode, resultCode, intentFromCamera);

    if (resultCode == RESULT_OK && requestCode == TAKE_PICTURE) {

        if (intentFromCamera != null) {
            Bundle extras = intentFromCamera.getExtras();
            if (extras.containsKey("data")) {
                bitmap = (Bitmap) extras.get("data");
            }
            else {
                bitmap = getBitmapFromUri();
            }
        }
        else {
            bitmap = getBitmapFromUri();
        }
        // imageView.setImageBitmap(bitmap);
        imageView.setImageURI(imageUri);
    }
    else {
    }
}

public Bitmap getBitmapFromUri() {

    getContentResolver().notifyChange(imageUri, null);
    ContentResolver cr = getContentResolver();
    Bitmap bitmap;

    try {
        bitmap = android.provider.MediaStore.Images.Media.getBitmap(cr, imageUri);
        return bitmap;
    }
    catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

Ancak sorun, her döndürüldüğünde bazı cihazlardaki görüntü. Örneğin, bir Samsung cihazında iyi çalışır, ancak Sony Xperia'da görüntü 90 derece ve Toshiba Thrive'da (tablet) 180 derece döndürülür.


1
bunu sizde deneyin etkinlik menifest android: configChanges = "yönlendirme" android: screenOrientation = "portre"
Narendra Pal

@nick çalışmıyor, şimdi görüntü sekmede 180 derece yerine 90 dereceye döndürülüyor
Shirish Herwade

1
kamera uygulaması ile uğraşmak için iç amacı kullandığınızda düşünüyorum, o zaman görüntüyü döndürür.Bu görüntü yakalamak için cihazı nasıl tuttuğunuz bağlıdır. Böylece, kullanıcının belirli bir şekilde görüntü çekmesini kısıtlayabilirsiniz, kullanıcının cihazı her zaman dikey veya yatay tutarak görüntü yakalayacağı anlamına gelir. Bundan sonra istediğiniz gibi görüntü almak için belirli bir açıya değiştirebilirsiniz .. VEYA BAŞKA BİR SEÇENEK, KENDİ KAMERA APP olun.
Narendra Pal

@nick "kullanıcının görüntüyü belirli bir şekilde çekmesini kısıtlayabilirsiniz", yönelim ayarı = "potrait" ile aynı olduğu anlamına mı gelir? Ve nasıl "Bundan sonra istediğiniz gibi görüntü elde etmek için belirli bir açıya değiştirebilirsiniz" elde etmek? Lütfen bazı yararlı bağlantılar verebilir misiniz
Shirish Herwade

3
Çekim amacının her cihazda belirli bir yönelime ve sonuç olarak sabit fotoğraf yönelime sahip olan varsayılan kamera uygulamasını getirdiğine inanıyorum. Kullanıcının cihazı tutma biçimine veya amacınızı başlatan etkinliğinizin yönüne bağlı değildir.
Alex Cohn

Yanıtlar:


440

Çoğu telefon kamerası manzaradır, yani fotoğrafı dikey olarak çekerseniz ortaya çıkan fotoğraflar 90 derece döndürülür. Bu durumda, kamera yazılımı Exif verilerini fotoğrafın görüntülenmesi gereken yönüyle doldurmalıdır .

Aşağıdaki çözümün, Exif verilerini dolduran kamera yazılımına / cihaz üreticisine bağlı olduğunu unutmayın, bu nedenle çoğu durumda çalışacaktır, ancak% 100 güvenilir bir çözüm değildir.

ExifInterface ei = new ExifInterface(photoPath);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                                     ExifInterface.ORIENTATION_UNDEFINED);

Bitmap rotatedBitmap = null;
switch(orientation) {

    case ExifInterface.ORIENTATION_ROTATE_90:
        rotatedBitmap = rotateImage(bitmap, 90);
        break;

    case ExifInterface.ORIENTATION_ROTATE_180:
        rotatedBitmap = rotateImage(bitmap, 180);
        break;

    case ExifInterface.ORIENTATION_ROTATE_270:
        rotatedBitmap = rotateImage(bitmap, 270);
        break;

    case ExifInterface.ORIENTATION_NORMAL:
    default:
        rotatedBitmap = bitmap;
}

İşte rotateImageyöntem:

public static Bitmap rotateImage(Bitmap source, float angle) {
    Matrix matrix = new Matrix();
    matrix.postRotate(angle);
    return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(),
                               matrix, true);
}

1
@JonRobinson kodundan gerçek yönlendirmeyi nasıl alacağımı öğreniyorum ve bu kodla birleştirerek yönlendirmeyi başarıyla yönetiyorum.
Raditya Kurnianto

İkinci seçenek exif.getAttributeIntkullanılarak ExifInterface.ORIENTATION_UNDEFINEDikinci parametre varsayılan değer durumunda olduğu gibi fonksiyon değerini sağlamakta başarısız, hemen hemen aynıdır.
Darpan

5
Bu kod zaten diske yazılmış bir görüntü içindir, değil mi? Diske yazılacak bitmap için bu yöntemi kullanarak hiçbir sonuç elde edemiyorum.
Trakya

4
Her zaman bana 0 değeri döndürür. Lütfen gerçek yönlendirmeyi nasıl alacağınızı söyleyin.
Anurag Srivastava

3
Her zaman 0 almak, neden herhangi bir fikir?
Navya Ramesan

186

Birleştirerek Jason Robinson 'ın cevabı ile Felix s' cevap ve eksik parçalar doldurarak, burada bu sorun için nihai komple bir çözümdür Android üzerinde test edildikten sonra aşağıdakileri yapacak Android 4.1 ( Jelly Bean ), Android 4.4 ( KitKat ) ve Android 5.0 ( Lolipop ).

adımlar

  1. 1024x1024 boyutundan büyükse görüntüyü küçültün.

  2. Görüntüyü yalnızca 90, 180 veya 270 derece döndürdüyse sağa doğru döndürün.

  3. Döndürülen görüntüyü bellek amacıyla geri dönüştürün.

Kod kısmı:

Düzeltmek istediğiniz akım Contextve görüntü ile aşağıdaki yöntemi çağırınURI

/**
 * This method is responsible for solving the rotation issue if exist. Also scale the images to
 * 1024x1024 resolution
 *
 * @param context       The current context
 * @param selectedImage The Image URI
 * @return Bitmap image results
 * @throws IOException
 */
public static Bitmap handleSamplingAndRotationBitmap(Context context, Uri selectedImage)
        throws IOException {
    int MAX_HEIGHT = 1024;
    int MAX_WIDTH = 1024;

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    InputStream imageStream = context.getContentResolver().openInputStream(selectedImage);
    BitmapFactory.decodeStream(imageStream, null, options);
    imageStream.close();

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, MAX_WIDTH, MAX_HEIGHT);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    imageStream = context.getContentResolver().openInputStream(selectedImage);
    Bitmap img = BitmapFactory.decodeStream(imageStream, null, options);

    img = rotateImageIfRequired(context, img, selectedImage);
    return img;
}

İşte CalculateInSampleSizeönceden belirtilen, yöntem kaynağı :

/**
  * Calculate an inSampleSize for use in a {@link BitmapFactory.Options} object when decoding
  * bitmaps using the decode* methods from {@link BitmapFactory}. This implementation calculates
  * the closest inSampleSize that will result in the final decoded bitmap having a width and
  * height equal to or larger than the requested width and height. This implementation does not
  * ensure a power of 2 is returned for inSampleSize which can be faster when decoding but
  * results in a larger bitmap which isn't as useful for caching purposes.
  *
  * @param options   An options object with out* params already populated (run through a decode*
  *                  method with inJustDecodeBounds==true
  * @param reqWidth  The requested width of the resulting bitmap
  * @param reqHeight The requested height of the resulting bitmap
  * @return The value to be used for inSampleSize
  */
private static int calculateInSampleSize(BitmapFactory.Options options,
                                         int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will guarantee a final image
        // with both dimensions larger than or equal to the requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;

        // This offers some additional logic in case the image has a strange
        // aspect ratio. For example, a panorama may have a much larger
        // width than height. In these cases the total pixels might still
        // end up being too large to fit comfortably in memory, so we should
        // be more aggressive with sample down the image (=larger inSampleSize).

        final float totalPixels = width * height;

        // Anything more than 2x the requested pixels we'll sample down further
        final float totalReqPixelsCap = reqWidth * reqHeight * 2;

        while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
            inSampleSize++;
        }
    }
    return inSampleSize;
}

Ardından, dönme açısına karar vermek için mevcut görüntü yönünü kontrol edecek yöntem geliyor

 /**
 * Rotate an image if required.
 *
 * @param img           The image bitmap
 * @param selectedImage Image URI
 * @return The resulted Bitmap after manipulation
 */
private static Bitmap rotateImageIfRequired(Context context, Bitmap img, Uri selectedImage) throws IOException {

InputStream input = context.getContentResolver().openInputStream(selectedImage);
ExifInterface ei;
if (Build.VERSION.SDK_INT > 23)
    ei = new ExifInterface(input);
else
    ei = new ExifInterface(selectedImage.getPath());

    int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

    switch (orientation) {
        case ExifInterface.ORIENTATION_ROTATE_90:
            return rotateImage(img, 90);
        case ExifInterface.ORIENTATION_ROTATE_180:
            return rotateImage(img, 180);
        case ExifInterface.ORIENTATION_ROTATE_270:
            return rotateImage(img, 270);
        default:
            return img;
    }
}

Son olarak döndürme yönteminin kendisi

private static Bitmap rotateImage(Bitmap img, int degree) {
    Matrix matrix = new Matrix();
    matrix.postRotate(degree);
    Bitmap rotatedImg = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true);
    img.recycle();
    return rotatedImg;
}

- Çabalarının cevapları ve bu yararlı soruyu soran Shirish Herwade için oy vermeyi unutmayın .


2
Onun için Woking Perfectly.Teşekkür ederiz
Shohel Rana

1
yöntem rotateImageIfRequired () çok iyi çalışıyor .. teşekkürler !!
mapo

5
Benim için çalışmıyor. Bazen telefonum portre, bazen manzara fotoğrafları veriyor, ancak algılanan yön her zaman 0 derecedir.
Makalele

@Makalele Bu sorun, fotoğraf çekerken ve WhatsApp aracılığıyla eklerken de ortaya çıkıyor mu?
Manoj Perumarath

WhatsApp kullanmıyorum, bu yüzden söyleyemem, ama muhtemelen evet. Bunun nedeni stok fotoğraf uygulamasında (Google Stock Camera) bile gerçekleşmesidir.
Makalele

45

Görüntü yönlendirmesini algılamak ve bitmap'i aşağıdakileri kullanarak değiştirmek kolaydır:

 /**
 * Rotate an image if required.
 * @param img
 * @param selectedImage
 * @return
 */
private static Bitmap rotateImageIfRequired(Context context,Bitmap img, Uri selectedImage) {

    // Detect rotation
    int rotation = getRotation(context, selectedImage);
    if (rotation != 0) {
        Matrix matrix = new Matrix();
        matrix.postRotate(rotation);
        Bitmap rotatedImg = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true);
        img.recycle();
        return rotatedImg;
    }
    else{
        return img;
    }
}

/**
 * Get the rotation of the last image added.
 * @param context
 * @param selectedImage
 * @return
 */
private static int getRotation(Context context,Uri selectedImage) {

    int rotation = 0;
    ContentResolver content = context.getContentResolver();

    Cursor mediaCursor = content.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                                       new String[] { "orientation", "date_added" },
                                       null, null, "date_added desc");

    if (mediaCursor != null && mediaCursor.getCount() != 0) {
        while(mediaCursor.moveToNext()){
            rotation = mediaCursor.getInt(0);
            break;
        }
    }
    mediaCursor.close();
    return rotation;
}

Büyük resimli anıların yetersiz kalmasını önlemek için, resmi kullanarak yeniden ölçeklendirmenizi öneririz:

private static final int MAX_HEIGHT = 1024;
private static final int MAX_WIDTH = 1024;
public static Bitmap decodeSampledBitmap(Context context, Uri selectedImage)
    throws IOException {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    InputStream imageStream = context.getContentResolver().openInputStream(selectedImage);
    BitmapFactory.decodeStream(imageStream, null, options);
    imageStream.close();

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, MAX_WIDTH, MAX_HEIGHT);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    imageStream = context.getContentResolver().openInputStream(selectedImage);
    Bitmap img = BitmapFactory.decodeStream(imageStream, null, options);

    img = rotateImageIfRequired(img, selectedImage);
    return img;
}

Android işletim sistemi sorunu nedeniyle oryantasyonu almak için ExifInterface kullanmak mümkün değildir: https://code.google.com/p/android/issues/detail?id=19268

Ve işte burada calculateInSampleSize

/**
 * Calculate an inSampleSize for use in a {@link BitmapFactory.Options} object when decoding
 * bitmaps using the decode* methods from {@link BitmapFactory}. This implementation calculates
 * the closest inSampleSize that will result in the final decoded bitmap having a width and
 * height equal to or larger than the requested width and height. This implementation does not
 * ensure a power of 2 is returned for inSampleSize which can be faster when decoding but
 * results in a larger bitmap which isn't as useful for caching purposes.
 *
 * @param options   An options object with out* params already populated (run through a decode*
 *                  method with inJustDecodeBounds==true
 * @param reqWidth  The requested width of the resulting bitmap
 * @param reqHeight The requested height of the resulting bitmap
 * @return The value to be used for inSampleSize
 */
public static int calculateInSampleSize(BitmapFactory.Options options,
                                        int reqWidth, int reqHeight) {

    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will guarantee a final image
        // with both dimensions larger than or equal to the requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;

        // This offers some additional logic in case the image has a strange
        // aspect ratio. For example, a panorama may have a much larger
        // width than height. In these cases the total pixels might still
        // end up being too large to fit comfortably in memory, so we should
        // be more aggressive with sample down the image (=larger inSampleSize).

        final float totalPixels = width * height;

        // Anything more than 2x the requested pixels we'll sample down further
        final float totalReqPixelsCap = reqWidth * reqHeight * 2;

        while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
            inSampleSize++;
        }
    }
    return inSampleSize;
}

1

1
@madhukotagiri burada calculateInSampleSize için uygulama örneğine sahipsiniz
Felix

Teşekkürler dostum, kesinlikle tek kişisin! İşlem sadece ara sıra yapılırsa, yeniden boyutlandırmanın ne kadar yararlı olacağını merak ediyorum.
Marino

4
Uri selectedImage parametresi getRotation (...) yönteminde kullanılmaz. Nasıl kullanmamız gerekiyor? Teşekkür ederim.
valerybodak

1
'SelectedImage' parametresi hiçbir yerde kullanılmıyor gibi görünüyor. Orada olmak için bir sebep var mı?
Alex

20

Tek hat çözümü:

Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);

Veya

Picasso.with(context).load("file:" + photoPath).into(imageView);

Bu, dönüşü otomatik olarak algılar ve görüntüyü doğru yönde yerleştirir

Picasso, uygulamanızdaki görüntüleri işlemek için çok güçlü bir kütüphanedir: Minimum bellek kullanımı ile karmaşık görüntü dönüşümleri.


1
İlginç bir çözüm
Bhavik Mehta

8
Görüntüyü bir görünüme yükler, size bir bitmap veya manipüle edebileceğiniz veya bir sunucuya yükleyebileceğiniz bir dosya vermez.
flawyte

4
Görüntülenen görüntü olduğu gibi tıklandı. Gerektiği gibi dönmüyor.
seema

1
@Flawyte, kırpılmış / yeniden boyutlandırılmış bitmap'i döndüren geri arama ile dosya yerine hedefe yükleyerek bunu yapabilirsiniz: Picasso.with (this) .load (cropUriToLoad.resize (1080, 810) .centerInside (). İçine (target); where target = new Target () {BitmapLoaded'deki (Bitmap bitmap, Picasso.LoadedFrom from) genel boşluğunu geçersiz kılın) {
voytez

hala karşılaştığım sorun, görüntüyü görüntülemek için birkaç saniye sürüyor
Anu

12

Bunun için çözüm aramak için çok zaman harcadım. Ve sonunda bunu başardı. @Jason Robinson'ın cevabını oylamayı unutma çünkü benim temele dayanıyor.

İlk olarak, Android 7.0'dan beri kullanmamız FileProviderve bir şey çağırmamız gerektiğini biliyorsunuz ContentUri, aksi takdirde sizi çağırmaya çalışırken can sıkıcı bir hata alacaksınız Intent. Bu örnek kod:

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, getUriFromPath(context, "[Your path to save image]"));
startActivityForResult(intent, CAPTURE_IMAGE_RESULT);

getUriFromPath(Context, String)Android kullanıcı sürümüne dayalı yöntem temeli FileUri (file://...)veya ContentUri (content://...)orada:

public Uri getUriFromPath(Context context, String destination) {
    File file =  new File(destination);

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
        return FileProvider.getUriForFile(context, context.getPackageName() + ".provider", file);
    } else {
        return Uri.fromFile(file);
    }
}

Görüntünün kamera tarafından kaydedildiği yeri onActivityResultyakalayabilmenizden sonra uri, şimdi kamera dönüşünü algılamanız gerekiyor, burada moddified @ Jason Robinson cevabını kullanacağız:

Önce oluşturmak gerekir ExifInterfacedayalıUri

@Nullable
public ExifInterface getExifInterface(Context context, Uri uri) {
    try {
        String path = uri.toString();
        if (path.startsWith("file://")) {
            return new ExifInterface(path);
        }
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            if (path.startsWith("content://")) {
                InputStream inputStream = context.getContentResolver().openInputStream(uri);
                return new ExifInterface(inputStream);
            }
        }
    }
    catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

Yukarıdaki kod basitleştirilebilir, ama her şeyi göstermek istiyorum. Dolayısıyla, dayanarak FileUrioluşturabiliriz , ancak yapamayız, Android bunu desteklemez.ExifInterfaceString pathContentUri

Bu durumda, başka bir kurucu kullanmamız gerekir InputStream. Bu kurucunun varsayılan olarak kullanılamadığını, ek kitaplık eklemeniz gerektiğini unutmayın:

compile "com.android.support:exifinterface:XX.X.X"

Şimdi açımızı getExifInterfacealmak için yöntemi kullanabiliriz :

public float getExifAngle(Context context, Uri uri) {
    try {
        ExifInterface exifInterface = getExifInterface(context, uri);
        if(exifInterface == null) {
            return -1f;
        }

        int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                ExifInterface.ORIENTATION_UNDEFINED);

        switch (orientation) {
            case ExifInterface.ORIENTATION_ROTATE_90:
                return 90f;
            case ExifInterface.ORIENTATION_ROTATE_180:
                return 180f;
            case ExifInterface.ORIENTATION_ROTATE_270:
                return 270f;
            case ExifInterface.ORIENTATION_NORMAL:
                return 0f;
            case ExifInterface.ORIENTATION_UNDEFINED:
                return -1f;
            default:
                return -1f;
        }
    }
    catch (Exception e) {
        e.printStackTrace();
        return -1f;
    }
}

Şimdi size doğru görüntü döndürmek için Açı var :).


2
uygulama 'androidx.exifinterface: exifinterface: XXX' Bu androidx kullananlar içindir.
gönderi

11
// Try this way,hope this will help you to solve your problem...

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:gravity="center">
        <ImageView
            android:id="@+id/imgFromCameraOrGallery"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:adjustViewBounds="true"
            android:src="@drawable/ic_launcher"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <Button
            android:id="@+id/btnCamera"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="Camera"/>
        <Button
            android:id="@+id/btnGallery"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_marginLeft="5dp"
            android:layout_height="wrap_content"
            android:text="Gallery"/>

    </LinearLayout>
</LinearLayout>

MainActivity.java

    public class MainActivity extends Activity {

    private ImageView imgFromCameraOrGallery;
    private Button btnCamera;
    private Button btnGallery;

    private String imgPath;
    final private int PICK_IMAGE = 1;
    final private int CAPTURE_IMAGE = 2;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imgFromCameraOrGallery = (ImageView) findViewById(R.id.imgFromCameraOrGallery);
        btnCamera = (Button) findViewById(R.id.btnCamera);
        btnGallery = (Button) findViewById(R.id.btnGallery);

        btnCamera.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, setImageUri());
                startActivityForResult(intent, CAPTURE_IMAGE);
            }
        });

        btnGallery.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setType("image/*");
                intent.setAction(Intent.ACTION_GET_CONTENT);
                startActivityForResult(Intent.createChooser(intent, ""), PICK_IMAGE);
            }
        });

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK) {
            if (requestCode == CAPTURE_IMAGE) {
                setCapturedImage(getImagePath());
            } else if (requestCode == PICK_IMAGE) {
                imgFromCameraOrGallery.setImageBitmap(BitmapFactory.decodeFile(getAbsolutePath(data.getData())));
            }
        }

    }

    private String getRightAngleImage(String photoPath) {

        try {
            ExifInterface ei = new ExifInterface(photoPath);
            int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            int degree = 0;

            switch (orientation) {
                case ExifInterface.ORIENTATION_NORMAL:
                    degree = 0;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
                case ExifInterface.ORIENTATION_UNDEFINED:
                    degree = 0;
                    break;
                default:
                    degree = 90;
            }

            return rotateImage(degree,photoPath);

        } catch (Exception e) {
            e.printStackTrace();
        }

        return photoPath;
    }

    private String rotateImage(int degree, String imagePath){

        if(degree<=0){
            return imagePath;
        }
        try{
            Bitmap b= BitmapFactory.decodeFile(imagePath);

            Matrix matrix = new Matrix();
            if(b.getWidth()>b.getHeight()){
                matrix.setRotate(degree);
                b = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(),
                        matrix, true);
            }

            FileOutputStream fOut = new FileOutputStream(imagePath);
            String imageName = imagePath.substring(imagePath.lastIndexOf("/") + 1);
            String imageType = imageName.substring(imageName.lastIndexOf(".") + 1);

            FileOutputStream out = new FileOutputStream(imagePath);
            if (imageType.equalsIgnoreCase("png")) {
                b.compress(Bitmap.CompressFormat.PNG, 100, out);
            }else if (imageType.equalsIgnoreCase("jpeg")|| imageType.equalsIgnoreCase("jpg")) {
                b.compress(Bitmap.CompressFormat.JPEG, 100, out);
            }
            fOut.flush();
            fOut.close();

            b.recycle();
        }catch (Exception e){
            e.printStackTrace();
        }
        return imagePath;
    }

    private void setCapturedImage(final String imagePath){
        new AsyncTask<Void,Void,String>(){
            @Override
            protected String doInBackground(Void... params) {
                try {
                    return getRightAngleImage(imagePath);
                }catch (Throwable e){
                    e.printStackTrace();
                }
                return imagePath;
            }

            @Override
            protected void onPostExecute(String imagePath) {
                super.onPostExecute(imagePath);
                imgFromCameraOrGallery.setImageBitmap(decodeFile(imagePath));
            }
        }.execute();
    }

    public Bitmap decodeFile(String path) {
        try {
            // Decode deal_image size
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(path, o);
            // The new size we want to scale to
            final int REQUIRED_SIZE = 1024;

            // Find the correct scale value. It should be the power of 2.
            int scale = 1;
            while (o.outWidth / scale / 2 >= REQUIRED_SIZE && o.outHeight / scale / 2 >= REQUIRED_SIZE)
                scale *= 2;
            // Decode with inSampleSize
            BitmapFactory.Options o2 = new BitmapFactory.Options();
            o2.inSampleSize = scale;
            return BitmapFactory.decodeFile(path, o2);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }

    public String getAbsolutePath(Uri uri) {
        if(Build.VERSION.SDK_INT >= 19){
            String id = "";
            if(uri.getLastPathSegment().split(":").length > 1)
                id = uri.getLastPathSegment().split(":")[1];
            else if(uri.getLastPathSegment().split(":").length > 0)
                id = uri.getLastPathSegment().split(":")[0];
            if(id.length() > 0){
                final String[] imageColumns = {MediaStore.Images.Media.DATA };
                final String imageOrderBy = null;
                Uri tempUri = getUri();
                Cursor imageCursor = getContentResolver().query(tempUri, imageColumns, MediaStore.Images.Media._ID + "=" + id, null, imageOrderBy);
                if (imageCursor.moveToFirst()) {
                    return imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
                }else{
                    return null;
                }
            }else{
                return null;
            }
        }else{
            String[] projection = { MediaStore.MediaColumns.DATA };
            Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
            if (cursor != null) {
                int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
                cursor.moveToFirst();
                return cursor.getString(column_index);
            } else
                return null;
        }

    }

    private Uri getUri() {
        String state = Environment.getExternalStorageState();
        if(!state.equalsIgnoreCase(Environment.MEDIA_MOUNTED))
            return MediaStore.Images.Media.INTERNAL_CONTENT_URI;

        return MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
    }

    public Uri setImageUri() {
        Uri imgUri;
        String state = Environment.getExternalStorageState();
        if (Environment.MEDIA_MOUNTED.equals(state)) {
            File file = new File(Environment.getExternalStorageDirectory() + "/DCIM/",getString(R.string.app_name) + Calendar.getInstance().getTimeInMillis() + ".png");
            imgUri = Uri.fromFile(file);
            imgPath = file.getAbsolutePath();
        }else {
            File file = new File(getFilesDir() ,getString(R.string.app_name) + Calendar.getInstance().getTimeInMillis()+ ".png");
            imgUri = Uri.fromFile(file);
            this.imgPath = file.getAbsolutePath();
        }
        return imgUri;
    }

    public String getImagePath() {
        return imgPath;
    }
}

Mükemmel Çözüm Haresh Bhai
Sagar Pithiya

9

Kamera sensörünün yönünü Google tarafından belirtildiği gibi dokümanlarda okuyabilirsiniz: https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html

SENSOR_ORIENTATION

Added in API level 21
Key<Integer> SENSOR_ORIENTATION
Clockwise angle through which the output image needs to be rotated to be upright on the device screen in its native orientation.

Also defines the direction of rolling shutter readout, which is from top to bottom in the sensor's coordinate system.

Units: Degrees of clockwise rotation; always a multiple of 90

Range of valid values:
0, 90, 180, 270

This key is available on all devices.

Basit kod:

CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
int orientation = 0;
try {
    String cameraId = manager.getCameraIdList()[0];
    CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
    orientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
}
catch (Exception e)
{
}


4

Normalde @ Jason Robinson'un önerdiği gibi ExifInterface ile sorunu çözmeniz önerilir. Bu yaklaşım işe yaramazsa, çekilen son görüntünün Oryantasyonunu aramayı deneyebilirsiniz ...

private int getImageOrientation(){
    final String[] imageColumns = { MediaStore.Images.Media._ID, MediaStore.Images.ImageColumns.ORIENTATION };
    final String imageOrderBy = MediaStore.Images.Media._ID+" DESC";
    Cursor cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            imageColumns, null, null, imageOrderBy);

    if(cursor.moveToFirst()){
        int orientation = cursor.getInt(cursor.getColumnIndex(MediaStore.Images.ImageColumns.ORIENTATION));
        cursor.close();
        return orientation;
    } else {
        return 0;
    }
}

1
Bence bu kod sadece hangi derecede dönme meydana geldiğini algılar. Şimdi bunu yapabilirim, ancak bir sonraki görevde görüntüyü döndürmek mümkün değil.
Shirish Herwade

Haklısın, ama bu Konudaki rotasyonu istemedin, bu yüzden temiz tutalım;) Bu yüzden dönen problemine cevabımı diğer Konuya koydum ... Umarım yardımcı olur, işe yarıyor ben: stackoverflow.com/questions/14123809/…
Chris Conway

4

Ne yazık ki, yukarıdaki jason-robinson yanıtı benim için işe yaramadı.

Döndürme işlevi mükemmel bir şekilde çalışmasına rağmen:

public static Bitmap rotateImage(Bitmap source, float angle) {
    Matrix matrix = new Matrix();
    matrix.postRotate(angle);
    return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix,
            true);
}

Exif yönü her zaman 0 olduğu için yönlendirmeyi almak için aşağıdakileri yapmak zorunda kaldım

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode,resultCode,data);
    if (requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && data != null) {
            Uri selectedImage = data.getData();
            String[] orientationColumn = {MediaStore.Images.Media.ORIENTATION};
            Cursor cur = managedQuery(imageUri, orientationColumn, null, null, null);
            int orientation = -1;
            if (cur != null && cur.moveToFirst()) {
                    orientation = cur.getInt(cur.getColumnIndex(orientationColumn[0]));
            }
            InputStream imageStream = getContentResolver().openInputStream(selectedImage);
            Bitmap bitmap = BitmapFactory.decodeStream(imageStream);
            switch(orientation) {
                    case 90:
                            bitmap = rotateImage(chosen_image_bitmap, 90);
                            break;
                    case 180:
                            bitmap = rotateImage(chosen_image_bitmap, 180);
                            break;
                    case 270:
                            bitmap = rotateImage(chosen_image_bitmap, 270);
                            break;
                    default:
                            break;
            }
            imageView.setImageBitmap(bitmap );

1

2

Resmi belirli bir yönde çekmeye çalışın.

android:screenOrientation="landscape"
android:configChanges="orientation|keyboardHidden"

En iyi sonuçlar için kamera görüntüsü etkinliğinde yatay yönlendirme yapın.


üzgünüm, çalışmıyor. Aslında sekmesinde, onActivityResult'un yürütülmesini bitirdikten sonra her seferinde garip bir şekilde onCreate çağrılır.
Shirish Herwade

1
üzgünüm, sorun olduğu gibi
Shirish Herwade



1

Seçilen cevap, bu ve benzeri sorulara en sık cevaplanan yöntemi kullanır. Bununla birlikte, Samsung'daki hem ön hem de arka kameralarla çalışmaz. Samsung ve diğer büyük üreticiler için hem ön hem de arka kameralarda çalışan bir çözüm arayanlar için nvhausid'in bu yanıtı harika:

https://stackoverflow.com/a/18915443/6080472

Tıklamak istemeyenler için, ilgili sihir EXIF'e güvenmek yerine CameraInfo'yu kullanmaktır.

Bitmap realImage = BitmapFactory.decodeByteArray(data, 0, data.length);
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(mCurrentCameraId, info);
Bitmap bitmap = rotate(realImage, info.orientation);

Bağlantıda tam kod.


hayır, farklı açılardan yanlış dönüş (smasung s7). Tabii galeri galeri
djdance

1

Bu belki söylemeye gerek yok ama her zaman sunucunuzda bu görüntü işleme sorunlarının bazılarını ele alabileceğinizi unutmayın. Görüntünün hemen görüntülenmesini sağlamak için bu iş parçacığındaki yanıtlar gibi yanıtlar kullandım. Ancak uygulamam görüntülerin sunucuda depolanmasını gerektiriyor (kullanıcılar telefon değiştirdikçe görüntünün devam etmesini istiyorsanız, bu muhtemelen yaygın bir gereksinimdir).

Bu konuyla ilgili iş parçacıklarının çoğunda bulunan çözümler, Bitmap'in görüntü sıkıştırmasından kurtulamayan EXIF ​​verilerinin kalıcılığını tartışmaz, yani sunucunuz her yüklediğinde görüntüyü döndürmeniz gerekir. Alternatif olarak, EXIF ​​yönlendirme verilerini sunucunuza gönderebilir ve ardından gerekirse görüntüyü orada döndürebilirsiniz.

Bir sunucuda kalıcı bir çözüm oluşturmak benim için daha kolaydı çünkü Android'in gizli dosya yolları hakkında endişelenmem gerekmiyordu.


Görüntü yakalama zamanında bir kez döndürebilir ve bu şekilde kaydedebilir, böylece bir daha döndürülemez mi?
jk7

Evet yapabilirsin ve sonunda sonunda uyguladığım süreç bu. Bunu yapmamı sağlayacak olan Android telefondaki görüntüden dosya yolunu almakta sorun yaşıyordum.
Yardımcı

1

Bu sorunun en basit çözümü:

captureBuilder.set(CaptureRequest.JPEG_ORIENTATION,
                   characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION));

Resmi jpg formatında kaydediyorum.


0

İşte Xamarin.Androidsürüm:

@Jason Robinson'ın cevabından :

Bitmap rotate(Bitmap bitmap, int angle)
{
    var matrix = new Matrix();
    matrix.PostRotate(angle);

    return Bitmap.CreateBitmap(bitmap, 0, 0, bitmap.Width, bitmap.Height, matrix, true);
}

Bitmap rotateIfRequired(Bitmap bitmap, string imagePath)
{
    var ei = new ExifInterface(imagePath);
    var orientation = ei.GetAttributeInt(ExifInterface.TagOrientation, (int)Android.Media.Orientation.Undefined);

    switch (orientation)
    {
        case (int)Android.Media.Orientation.Rotate90: return rotate(bitmap, 90);
        case (int)Android.Media.Orientation.Rotate180: return rotate(bitmap, 180);
        case (int)Android.Media.Orientation.Rotate270: return rotate(bitmap, 270);
        default: return bitmap;
    }
}

Sonra calculateInSampleSizeyöntem:

int calculateInSampleSize(BitmapFactory.Options options, int reqW, int reqH)
{
    float h = options.OutHeight;
    float w = options.OutWidth;
    var inSampleSize = 1;

    if (h > reqH || w > reqW)
    {
        if (reqH == 0) inSampleSize = (int)Math.Floor(w / reqW);
        else if (reqW == 0) inSampleSize = (int)Math.Floor(h / reqH);
        else
        {
            var hRatio = (int)Math.Floor(h / reqH);
            var wRatio = (int)Math.Floor(w / reqW);
            inSampleSize = false ? Math.Max(hRatio, wRatio) : Math.Min(hRatio, wRatio);
        }
    }

    return inSampleSize;
}

@Sami Eltamawy'nin cevabından :

Bitmap handleSamplingAndRotationBitmap(string imagePath)
{
    var maxHeight = 1024;
    var maxWidth = 1024;

    var options = new BitmapFactory.Options();
    options.InJustDecodeBounds = true;
    BitmapFactory.DecodeFile(imagePath, options);

    options.InSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);

    options.InJustDecodeBounds = false;

    var bitmap = BitmapFactory.DecodeFile(imagePath, options);

    bitmap = rotateIfRequired(bitmap, imagePath);

    return bitmap;
}

0

Fresco kullanıyorsanız, bunu kullanabilirsiniz -

final ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(uri)
.setRotationOptions(RotationOptions.autoRotate())
.build();

mSimpleDraweeView.setController(
Fresco.newDraweeControllerBuilder()
    .setImageRequest(imageRequest)
    .build());

Bu, görüntüleri Exif verilerine göre otomatik olarak döndürür.

Kaynak: https://frescolib.org/docs/rotation.html


0

Aşağıdaki kod benimle çalıştı, fileUri'den bitmap aldı ve gerekirse döndürme düzeltmesini yapın:

    private fun getCapturedImage(selectedPhotoUri: Uri): Bitmap {
        val bitmap = when {
            Build.VERSION.SDK_INT < 28 -> MediaStore.Images.Media.getBitmap(
                this.contentResolver,
                selectedPhotoUri
            )
            else -> {
                val source = ImageDecoder.createSource(this.contentResolver, selectedPhotoUri)
                ImageDecoder.decodeBitmap(source)
            }
        }

        // If the image is rotated, fix it
        return when (ExifInterface(contentResolver.run { openInputStream(selectedPhotoUri) }).getAttributeInt(
            ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED)) {
            ExifInterface.ORIENTATION_ROTATE_90 ->
                Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, Matrix().apply {
                    postRotate(90F) }, true)
            ExifInterface.ORIENTATION_ROTATE_180 ->
                Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, Matrix().apply {
                    postRotate(180F) }, true)
            ExifInterface.ORIENTATION_ROTATE_270 ->
                Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, Matrix().apply {
                    postRotate(270F) }, true)
            else -> bitmap
        } 
    }

0

ExifInterface kullanmadan bu soruna bir cevap var . Kameranın rotasyonunu ön kamera veya arka kameradan hangisini kullanırsanız kullanın, ardından Bitmap oluştururken Matma.postRotate (derece) kullanarak bitmap'i döndürebiliriz

public int getRotationDegree() {
    int degree = 0;

    for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(i, info);
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
            degree = info.orientation;

            return degree;
        }
    }

    return degree;
}

Rotasyonu hesapladıktan sonra, aşağıdaki gibi bitmap'i döndürebilirsiniz:

 Matrix matrix = new Matrix();

 matrix.postRotate(getRotationDegree());

 Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);

Herare bm sizin bitmapiniz olmalı.

Ön kameranızın dönüşünü bilmek istiyorsanız yukarıdaki Camera.CameraInfo.CAMERA_FACING_BACK öğesini yukarıdaki Camera.CameraInfo.CAMERA_FACING_FRONT olarak değiştirin .

Umarım bu yardımcı olur.


1
Korkunç cevap ama yanlışlıkla iptal ettim. Bu kod Galeriden her görüntü ile yapılır varsayar senin kamera. Durum böyle değil
Zun

-1

@Jason Robinson'un cevabına dayanarak Kotlin geliştiricilerinin çalışmasını kolaylaştıran bir Kotlin genişletme işlevi oluşturdum. Umut ediyorum bu yardım eder.

fun Bitmap.fixRotation(uri: Uri): Bitmap? {

    val ei = ExifInterface(uri.path)

    val orientation: Int = ei.getAttributeInt(
        ExifInterface.TAG_ORIENTATION,
        ExifInterface.ORIENTATION_UNDEFINED
    )

    return when (orientation) {
        ExifInterface.ORIENTATION_ROTATE_90 -> rotateImage( 90f)
        ExifInterface.ORIENTATION_ROTATE_180 -> rotateImage( 180f)
        ExifInterface.ORIENTATION_ROTATE_270 -> rotateImage( 270f)
        ExifInterface.ORIENTATION_NORMAL -> this
        else -> this
    }
}

fun Bitmap.rotateImage(angle: Float): Bitmap? {
    val matrix = Matrix()
    matrix.postRotate(angle)
    return Bitmap.createBitmap(
        this, 0, 0, width, height,
        matrix, true
    )
}

1
harika ama uzantı veya işlev olarak tüm çözümlerle aynı sorundan muzdarip - Android 10'da çalışmıyor
Lior Iluz

-2

Bu hatayı düzeltmek için daha basit bir komut var.

Sadece ImageView.setBitmap (bitmap) sonra ekleyin; bu yourImageView.setRotation (90);

Bu benimkini düzeltti. Umarım yardımcı olur !


6
OP'nin belirttiği gibi, bazı cihazlar görüntüyü döndürmez, bazıları 90 derece döndürür, bazıları 180, vb. Bu yüzden her zaman 90 döndürmek bazı durumlarda yanlış olur.
jk7

-8

bu benim için çalıştı

ImageView display_image = findViewById(R.id.image);
this.display_image.setRotation(90);

lol bu ne ucube. Fotoğraf makinesi tarafından çekilen fotoğrafın nasıl olduğunu -90 / 90/0 / ... biliyorsunuz ... Kullanıcı manzara olarak fotoğraf çekiyor olabilir ve ne döndürürseniz döndürün ... lmao
Alex

Bu durumda benim için çalıştı çünkü benim durumumda kullanıcı telefonla dikey olarak her zaman resim çekecek.
Christian Eduardo Galdamez
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.