nostra13 / Android-Universal-Image-Loader

Powerful and flexible library for loading, caching and displaying images on Android.
Apache License 2.0
16.79k stars 6.11k forks source link

EXIF Orientation bug #559

Open ziem opened 10 years ago

ziem commented 10 years ago

Hello, I'm using UIL 1.9.1 in my recent project. I saw that UIL is now supporting EXIF orientation https://github.com/nostra13/Android-Universal-Image-Loader/issues/172 but I encountered issue when loading photos from SD card. In my application image is rotated by 90 degrees, but in Android gallery everything is ok.

Screens:

Code: ImageLoader.getInstance().displayImage("file:///" + currentPhotoAbsolutePath, imageView, ImageLoaderOptions.GALLERY);

public static DisplayImageOptions GALLERY = new DisplayImageOptions.Builder() .cacheInMemory(true) .build();

According to https://github.com/nostra13/Android-Universal-Image-Loader/issues/172#issuecomment-17120841 it should work because I'm loading local files.

The problem occurs on:

grine4ka commented 10 years ago

Hi, @Ziem I consider this is not an issue. Have you tried to set considerExifParams(true) and cacheOnDisc(true) to your DisplayImageOption which you use in ImageLoader.displayImage() method?

ziem commented 10 years ago

You are right. I overlooked it. considerExifParams(true) solved my problem, thanks.

swatigoel commented 10 years ago

It really helped me to solve this problem.

Thanks a lot. This is really awesome library.

carl1990 commented 9 years ago

hi :I used the 1.9.2 jar and set considerExifParams(true) and cacheOnDisc(true) but this problem is also exist

ihenk commented 9 years ago

@carl1990 I have the same problem

nostra13 commented 9 years ago

Can you provide image URL which is displayed wrong?

carl1990 commented 9 years ago

sorry! I am in debug environment use company intranet,so the url u can not access.

ihenk commented 9 years ago

@nostra13 http://www.bipt.edu.cn/pub/news/images/content/2014-11/20141113143629640236.jpg

ihenk commented 9 years ago

before is wrong

    public static DisplayImageOptions getDefaultDisplayImageOptions(
            Context context) {
        return new DisplayImageOptions.Builder()
                .showImageOnLoading(R.drawable.ic_default)
                .showImageForEmptyUri(R.drawable.ic_default)
                .showImageOnFail(R.drawable.ic_default)
                .cacheInMemory(true)
                .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2)
                .cacheOnDisk(true)
                .considerExifParams(true)
                .displayer(
                        new RoundedBitmapDisplayer(context.getResources()
                                .getDimensionPixelSize(R.dimen.icon_rounded)))
                .build();
    }

after is right

    public static DisplayImageOptions getDefaultDisplayImageOptions(
            Context context) {
        return new DisplayImageOptions.Builder()
                .showImageOnLoading(R.drawable.ic_default)
                .showImageForEmptyUri(R.drawable.ic_default)
                .showImageOnFail(R.drawable.ic_default)
                .cacheInMemory(true)
                .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2)
                .cacheOnDisk(true)
                .considerExifParams(false)
                .displayer(
                        new RoundedBitmapDisplayer(context.getResources()
                                .getDimensionPixelSize(R.dimen.icon_rounded)))
                .build();
    }
ihenk commented 9 years ago

When I set "considerExifParams (true)",the picture displayed on the phone in the wrong direction.But when I open the SD card cache files and found the picture in the right direction,this is really incredible.

After several attempts, I set "considerExifParams (false)",the picture displayed on the phone in the right direction. notes: (1) My program set the phone to force portrait. (2) Only a few pictures displayed incorrectly direction. (3) I use the jar version 1.9.3.

nostra13 commented 9 years ago

@ihenk I tested your link and realized this weird behavior. It seems this image is rotated during decoding into Bitmap. I'll investigate this case.

trungp commented 9 years ago

I faced this issue now. I also try considerExifParams on both true and false but the image still rotate 90 degree. I use version 1.9.3. Here is my display image configure:

 mDisplayImageOptions = new DisplayImageOptions.Builder()
                .cacheInMemory(true)
                .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2)
                .bitmapConfig(Bitmap.Config.ARGB_4444)
                .considerExifParams(false)
                .build();

Can someone help me to point out the issue here?

vivaladiem commented 9 years ago

I also meet the problem. I'm making gallery feature, so I need to load images from MediaStore. Original image files works well when I set considerExifParams to true.(otherwise it rotated wrongly)

But when I use MediaStore.Image.Thumbnail.Data, the Image rotated wrongly even though I set considerExifParams to true.

I also set cacheOnDisk, but it doesn't solve the problem.

swatigoel commented 9 years ago

To make gallery for images, I am using below code to query Media Store: final String[] columns = { MediaStore.Images.Media.DATA, MediaStore.Images.Media._ID, MediaStore.Images.Media.MIME_TYPE, MediaStore.Images.Media.DISPLAY_NAME, MediaStore.Images.Media.SIZE}; final String orderBy = MediaStore.Images.Media._ID; Cursor imageCursor = managedQuery( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, null, null, orderBy); if (imageCursor != null && imageCursor.getCount() > 0) {

                while (imageCursor.moveToNext()) {
                    CustomGalleryItem item = new CustomGalleryItem();

                    int dataColumnIndex = imageCursor
                            .getColumnIndex(MediaStore.Images.Media.DATA);

                    item.sdcardPath = imageCursor.getString(dataColumnIndex);

                    int mimeTypeColumnIndex = imageCursor.getColumnIndex(MediaStore.Images.Media.MIME_TYPE);
                    item.mimeType = imageCursor.getString(mimeTypeColumnIndex);

                    int idColumnIndex = imageCursor.getColumnIndex(MediaStore.Images.Media._ID);
                    item.id = imageCursor.getString(idColumnIndex);

                    int nameColumnIndex = imageCursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME);
                    item.fileName = imageCursor.getString(nameColumnIndex);

                    int sizeColumnIndex = imageCursor.getColumnIndex(MediaStore.Images.Media.SIZE);
                    item.fileSize = imageCursor.getString(sizeColumnIndex);

                    if(selectedList != null && selectedList.size() > 0) {
                        for(CustomGalleryItem selectedItem : selectedList) {
                            if(selectedItem.id.equals(item.id)) {
                                item.isSeleted = true;
                                break;
                            }
                        }
                    }
                    galleryList.add(item);
                }
            }

To initialize Image Loader, I have used below code:

DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder() .imageScaleType(ImageScaleType.EXACTLY_STRETCHED) .bitmapConfig(Bitmap.Config.RGB_565) .considerExifParams(true).build(); ImageDecoder smartUriDecoder = new SmartUriDecoder(this, getContentResolver(), new BaseImageDecoder(false));

    ImageLoaderConfiguration.Builder builder = new ImageLoaderConfiguration.Builder(
            this).defaultDisplayImageOptions(defaultOptions).memoryCache(
                    new WeakMemoryCache())
                    .imageDecoder(smartUriDecoder);

    ImageLoaderConfiguration config = builder.build();
    ImageLoader imageLoader = ImageLoader.getInstance();
    imageLoader.init(config);

I have written custom ImageDecoder because Universal Image loader works properly to show image thumbnail. But I wanted to show thumbnail for videos, audios as well.

I am using "universal-image-loader-1.9.2-SNAPSHOT-with-sources"

antonderevyanko commented 9 years ago

The same issue for me. Both .considerExifParams(false) and .considerExifParams(true)

leads to the same result - not properly rotated photo for portrait made images. Landscape photo is shown properly.

universal-image-loader:1.9.4

RubydulAhsan commented 9 years ago

Hello i faced the problem in U.I.L. V-1.9.4.Please share the findings and fix the bug.I think it is one of the major bug of this library as they offered that feature with a heavy note.

Cedriga commented 9 years ago

Until the problem is fixed, I used Picasso. It automatically solves this.

carl1990 commented 9 years ago

@Cedriga The Picasso has the same problem in SAMSUNG NOTE III with android 4.4

burakicel commented 8 years ago

Actually .considerExifParams(true) works for me. However make sure that you setup options and pass them to ImageLoader on any activity where you display images, Gallery, ImageDetail etc... Here is my code:

DisplayImageOptions options = new DisplayImageOptions.Builder()
                .showImageOnLoading(R.drawable.blank)
                .showImageForEmptyUri(R.drawable.blank)
                .showImageOnFail(R.drawable.blank)
                .cacheInMemory(true)
                .cacheOnDisk(true)
                .considerExifParams(true)
                .bitmapConfig(Bitmap.Config.RGB_565)
                .build();

imageLoader.displayImage(GalleryActivity.mThumbIds[position] ,imageView, options);
Dineshcg commented 8 years ago

My activity view is in landscape mode.

I am using all but still image is set rotate on image view.

options = new DisplayImageOptions.Builder() .showImageOnLoading(android.R.color.white) .showImageForEmptyUri(android.R.color.white) .showImageOnFail(android.R.color.white) .imageScaleType(ImageScaleType.EXACTLY) .cacheInMemory(true) .cacheOnDisk(true) .considerExifParams(true) .bitmapConfig(Bitmap.Config.RGB_565) .build();

The same issue for me. Both .considerExifParams(false) and .considerExifParams(true)

surajdubey commented 8 years ago

It's more of a compatibility issue in KitKat, Lollipop I think. Here is another thread https://github.com/square/picasso/issues/579 I'm using Picasso and having this issue. I'll use and see if UIL gives solution.

rx123rx commented 8 years ago

you need override the BaseImageDecoder.class and override the canDefineExifParams method,add image/png mimetype,then everything is ok

FireZenk commented 8 years ago

Is this solved?

dikevin0512 commented 8 years ago

sorry ,no...

------------------ 原始邮件 ------------------ 发件人: "Jorge Garrido";notifications@github.com; 发送时间: 2016年4月1日(星期五) 下午3:22 收件人: "nostra13/Android-Universal-Image-Loader"Android-Universal-Image-Loader@noreply.github.com;

主题: Re: [nostra13/Android-Universal-Image-Loader] EXIF Orientation bug(#559)

Is this solved?

— You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub

rx123rx commented 8 years ago

i got the reason,that is because of mimeType in method canDefineExifParams(String imageUri, String mimeType) of the class BaseImageDecoder you should add "image/png" in this method. I did it like this,and it works.

在 2016-04-01 15:25:18,"dylan" notifications@github.com 写道: sorry ,no...

------------------ 原始邮件 ------------------ 发件人: "Jorge Garrido";notifications@github.com; 发送时间: 2016年4月1日(星期五) 下午3:22 收件人: "nostra13/Android-Universal-Image-Loader"Android-Universal-Image-Loader@noreply.github.com;

主题: Re: [nostra13/Android-Universal-Image-Loader] EXIF Orientation bug(#559)

Is this solved?

— You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub

— You are receiving this because you commented. Reply to this email directly or view it on GitHub

FireZenk commented 8 years ago

Some sample code @rx123rx ?

dikevin0512 commented 8 years ago

thanks ,i try it later...

------------------ 原始邮件 ------------------ 发件人: "Monkey.D.Ren";notifications@github.com; 发送时间: 2016年4月1日(星期五) 下午3:42 收件人: "nostra13/Android-Universal-Image-Loader"Android-Universal-Image-Loader@noreply.github.com; 抄送: "kevin"274355280@qq.com; 主题: Re: [nostra13/Android-Universal-Image-Loader] EXIF Orientation bug(#559)

i got the reason,that is because of mimeType in method canDefineExifParams(String imageUri, String mimeType) of the class BaseImageDecoder you should add "image/png" in this method. I did it like this,and it works.

在 2016-04-01 15:25:18,"dylan" notifications@github.com 写道: sorry ,no...

------------------ 原始邮件 ------------------ 发件人: "Jorge Garrido";notifications@github.com; 发送时间: 2016年4月1日(星期五) 下午3:22 收件人: "nostra13/Android-Universal-Image-Loader"Android-Universal-Image-Loader@noreply.github.com;

主题: Re: [nostra13/Android-Universal-Image-Loader] EXIF Orientation bug(#559)

Is this solved?

— You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub

— You are receiving this because you commented. Reply to this email directly or view it on GitHub — You are receiving this because you commented. Reply to this email directly or view it on GitHub

rx123rx commented 8 years ago

private boolean canDefineExifParams(String imageUri, String mimeType) { if (mimeType == null) { return false; } return ("image/jpeg".equalsIgnoreCase(mimeType) || "image/png".equalsIgnoreCase(mimeType)) && (Scheme.ofUri(imageUri) == Scheme.FILE); }

because of the suffix of the pictures in the cache is .png,i just override this method like this.

在 2016-04-01 15:44:36,"Jorge Garrido" notifications@github.com 写道:

Some sample code @rx123rx ?

— You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub

dikevin0512 commented 8 years ago

ha ha ,thanks,may i take your contact information?

------------------ 原始邮件 ------------------ 发件人: "Monkey.D.Ren";notifications@github.com; 发送时间: 2016年4月1日(星期五) 下午3:52 收件人: "nostra13/Android-Universal-Image-Loader"Android-Universal-Image-Loader@noreply.github.com; 抄送: "kevin"274355280@qq.com; 主题: Re: [nostra13/Android-Universal-Image-Loader] EXIF Orientation bug(#559)

private boolean canDefineExifParams(String imageUri, String mimeType) { if (mimeType == null) { return false; } return ("image/jpeg".equalsIgnoreCase(mimeType) || "image/png".equalsIgnoreCase(mimeType)) && (Scheme.ofUri(imageUri) == Scheme.FILE); }

because of the suffix of the pictures in the cache is .png,i just override this method like this.

在 2016-04-01 15:44:36,"Jorge Garrido" notifications@github.com 写道:

Some sample code @rx123rx ?

— You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub — You are receiving this because you commented. Reply to this email directly or view it on GitHub

rx123rx commented 8 years ago

does it work?

在 2016-04-01 15:45:42,"dylan" notifications@github.com 写道: thanks ,i try it later...

------------------ 原始邮件 ------------------ 发件人: "Monkey.D.Ren";notifications@github.com; 发送时间: 2016年4月1日(星期五) 下午3:42 收件人: "nostra13/Android-Universal-Image-Loader"Android-Universal-Image-Loader@noreply.github.com; 抄送: "kevin"274355280@qq.com; 主题: Re: [nostra13/Android-Universal-Image-Loader] EXIF Orientation bug(#559)

i got the reason,that is because of mimeType in method canDefineExifParams(String imageUri, String mimeType) of the class BaseImageDecoder you should add "image/png" in this method. I did it like this,and it works.

在 2016-04-01 15:25:18,"dylan" notifications@github.com 写道: sorry ,no...

------------------ 原始邮件 ------------------ 发件人: "Jorge Garrido";notifications@github.com; 发送时间: 2016年4月1日(星期五) 下午3:22 收件人: "nostra13/Android-Universal-Image-Loader"Android-Universal-Image-Loader@noreply.github.com;

主题: Re: [nostra13/Android-Universal-Image-Loader] EXIF Orientation bug(#559)

Is this solved?

— You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub

— You are receiving this because you commented. Reply to this email directly or view it on GitHub — You are receiving this because you commented. Reply to this email directly or view it on GitHub

— You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub

FireZenk commented 8 years ago

@rx123rx Seems to work on Samsung devices... but Sony fails

rx123rx commented 8 years ago

i think u can watch the logcat ,have a look what kind of suffix of the pictures in the cache then add this kind of mimeType in that method. Maybe it works.good luck!

在 2016-04-01 17:51:02,"Jorge Garrido" notifications@github.com 写道:

@rx123rx Seems to work on Samsung devices... but Sony fails

— You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub

rx123rx commented 8 years ago

And it works on my HTC M8 .

在 2016-04-01 17:51:02,"Jorge Garrido" notifications@github.com 写道:

@rx123rx Seems to work on Samsung devices... but Sony fails

— You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub

tusharpandey-kiwi commented 7 years ago

@nostra13 : I have tried this section of logic and it works in mine case.

http://stackoverflow.com/a/39226824/2382964

im4eversmrt commented 7 years ago

I just faced the same problem on samsung devices but considerExifParams(true) just solved it.

yogeshmishrikotkar commented 7 years ago

Hello ,

I am using this universal image loader lib for caching images. But when I received the image i am adding the encryption on file and decryption while the decode is called. I am facing issue of Samsung devices , As my image is get rotated. exif param is not applying at this time. please help if anyone has fixed this issue .

my code is : For Encryption is `@Override public boolean save(String imageUri, InputStream imageDataStream, IoUtils.CopyListener listener) throws IOException {

    InputStream imageStream = EncryptionHandler.getSecureInputStream(imageDataStream, EncryptionHandler.MODE_ENCRYPT, ImageDbEncryptionAlgo.getInstance());
    File imageFile = getFile(imageUri);
    File tmpFile = new File(imageFile.getAbsolutePath() + TEMP_IMAGE_POSTFIX);
     boolean loaded = false;
    try {
        OutputStream os = new BufferedOutputStream(new FileOutputStream(tmpFile), bufferSize);
        try {
            loaded = IoUtils.copyStream(imageStream, os, listener, bufferSize);
          } finally {
            IoUtils.closeSilently(os);
        }
    } finally {
        if (loaded && !tmpFile.renameTo(imageFile)) {
            loaded = false;
        }
           if (!loaded) {
            tmpFile.delete();
        }
        if(imageStream !=null){
            IoUtils.closeSilently(imageStream);
        }
        if(imageDataStream !=null){
            IoUtils.closeSilently(imageDataStream);
        }
        imageStream =null;
        imageDataStream =null;
    }
    return loaded;
}
   @Override
    public boolean save(String imageUri, Bitmap bitmap) throws IOException {
        File imageFile = getFile(imageUri);
        File tmpFile = new File(imageFile.getAbsolutePath() + TEMP_IMAGE_POSTFIX);
        OutputStream os = new BufferedOutputStream(new FileOutputStream(tmpFile), bufferSize);
        boolean savedSuccessfully = false;
        try {
            savedSuccessfully = EncryptionHandler.encryptBitmap(bitmap, tmpFile.getAbsolutePath(),ImageDbEncryptionAlgo.getInstance());
         } finally {
            IoUtils.closeSilently(os);
            if (savedSuccessfully && !tmpFile.renameTo(imageFile)) {
                savedSuccessfully = false;
            }
             if (!savedSuccessfully) {
                tmpFile.delete();
            }
        }
        bitmap.recycle();
        return savedSuccessfully;
    }
`

For decryption code is :

public Bitmap decode(ImageDecodingInfo decodingInfo) throws IOException {
        Bitmap decodedBitmap;
        ImageFileInfo imageInfo;
        InputStream decryptedStream =null;
          InputStream imageStream = getImageStream(decodingInfo);
        if (imageStream == null) {
            L.e("Error no image stream", decodingInfo.getImageKey());
            return null;
        }
        try {
            String imageKey = decodingInfo.getImageUri();

            boolean isLocalImage= isLocalCachedFile(imageKey);
            if (isLocalImage) {
                decryptedStream = EncryptionHandler.getSecureInputStream(imageStream, EncryptionHandler.MODE_DECRYPT, ImageDbEncryptionAlgo.getInstance());
            } else {
                decryptedStream = imageStream;
            }

            imageInfo = defineImageSizeAndRotation(decryptedStream, decodingInfo);

            decryptedStream = resetStream(decryptedStream, decodingInfo);

            BitmapFactory.Options decodingOptions = prepareDecodingOptions(imageInfo.imageSize, decodingInfo);
            decodedBitmap = BitmapFactory.decodeStream(decryptedStream, null, decodingOptions);
        } finally {
            IoUtils.closeSilently(decryptedStream);
            IoUtils.closeSilently(imageStream);
        }

        if (decodedBitmap == null) {
            L.e(ERROR_CANT_DECODE_IMAGE, decodingInfo.getImageKey());
        } else {
            decodedBitmap = considerExactScaleAndOrientatiton(decodedBitmap, decodingInfo, imageInfo.exif.rotation,
                    imageInfo.exif.flipHorizontal);
        }
                return decodedBitmap;
    }
shubham-raitka commented 7 years ago

I used this;- DisplayImageOptions options = new DisplayImageOptions.Builder() .cacheInMemory(true) .cacheOnDisk(true) .displayer(new SimpleBitmapDisplayer()) .resetViewBeforeLoading(true) .considerExifParams(true) .build();

considerExifParams(true) worked for me.