When Glide (3.7.0) loads image from result file cache I get a pixelated image (poor quality). This only happens when file cache is created with centerCrop option. In previous version of Glide (3.6.1) there was no such issue.
Here's a picture with DiskCacheStrategy.NONE and DiskCacheStrategy.RESULT:

It is most noticeable on flower's center petals. I've tried cleaning cache but it's always the same.
What's your Glide load line and XML?
I'm loading like this:
private void setPhoto(ImageView imageView, Cursor cursor)
{
if(imageView == null)
return;
String path = cursor != null && mPhotoColumn != -1 ? cursor.getString(mPhotoColumn) : null;
File file = path != null ? new File(path) : null;
if(file != null && !file.exists())
file = null;
Glide.with(imageView.getContext())
.load(file)
.signature(new MediaStoreSignature("", file != null ? file.lastModified() : 0L, 0))
.diskCacheStrategy(DiskCacheStrategy.RESULT)
.centerCrop()
.error(R.drawable.ic_image_broken)
.fallback(R.drawable.ic_image)
.into(imageView);
}
My ImageView xml part:
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="@dimen/header_height"
android:contentDescription="@string/description_photo"
android:scaleType="centerInside"
android:transitionName="@string/transition_image"/>
The weird thing is that there was no change between https://github.com/bumptech/glide/compare/v3.6.1...v3.7.0 that would warrant this behavior.
Where did you snatch these images from?
I have a suspicion that what we're seeing are just JPEG artifacts. With NONE the image is decoded from network stream and then transformed, so the pixels are closer to the original. With RESULT there's an extra step where Glide saves the image into cache, and then reads it from there, so the first display will show you the same pixels as the any future display from cache. You can confirm this by adding one of these:
.asBitmap().encoder(new BitmapEncoder(CompressFormat.PNG, 100))
.asBitmap().format(DecodeFormat.PREFER_ARGB_8888)
both force PNG encoding one explicitly and one implicitly (Glide chooses PNG when the image has transparency). The second one is better because you can configure it centrally.
SOURCE cache will also give you better quality, because there's recompression there either, but each load will be slightly slower because the downsampling and transformation will take time.
Now I see where the problem lies. I load images from jpg files on a disk (locally) and by default You create (smaller) cached jpg files with default quality set to 90. Geez... JPGs from JPGs. BitmapEncoder should have DEFAULT_COMPRESSION_QUALITY set as 100 to be comparable with the original.
Thanks for help. As an override I now do the following:
mEncoder = new GifBitmapWrapperResourceEncoder(new BitmapEncoder(Bitmap.CompressFormat.PNG, 100), new GifResourceEncoder(Glide.get(context).getBitmapPool()));
// in setPhoto()
Glide.with(imageView.getContext())
.load(file)
.encoder(mEncoder)
.signature(new MediaStoreSignature("", file != null ? file.lastModified() : 0L, 0))
.diskCacheStrategy(DiskCacheStrategy.RESULT)
.centerCrop()
.error(R.drawable.ic_image_broken)
.fallback(R.drawable.ic_image)
.into(imageView);
You're free to set the encoder as I showed above, you can even cache in WebP if that's your heart's content ;) Most of the time the defaults work fine and saves a lot of space on the device.
By the way, the default decode format is also 565 so there may be some quality loss there too.
Personal opinion follows: even high-end devices struggle with space, for example I have a Galaxy S4 and my free space is constantly below 800MB without any media on the internal storage (I have only Asphalt 8 installed and other utility apps).
I think 90% is a good compromise, take a random image taken with a phone's camera (image attached below is just a thumbnail):

There's barely any degradation even at 75%. Usually the source images are low quality already so I think even re-compressing with 90% is a waste. 100% would be only comparable to the original if that was from a lossless format.
I get the point, but 90% is ok only for big images. Smaller images (more like larger thumbnails) look awfull.
Ah I see, I tried the same image but first resized to w400px, the green column in the middle looks dithered. This may be a good enhancement candidate in the future. Calculate the JPEG quality based on some curve so the smaller images are encoded with higher quality. I guess @sjudd will accept a PR with reasonable values for all use cases keeping speed/space constrains in mind.
Thank you for patience and undestanding.
I think PNG is a little overkill though, JPEG is still half the size for photos even at 100%.
JPG is ok when my source file is not already in lossy format (JPGs from JPGs - ugh! - like zipping a .zip file ;)). If the source file is a JPG already then I need to preseve its quality - not make it look more crappy then it is now.
You should lose extremely little quality with JPEG 100, but still save a lot of space (especially if you have a long list with thumbs). Glide doesn't re-encode every time, just when it's first cached, so you won't end up with a mush after like 10000 displays :)
I see that PNG is lossless, but I do have a similar "ugh!" feeling for PNG, just by encoding in a lossless format you won't get better quality if the source image was already lossy-compressed (that flower doesn't look like it was decoded from a RAW format). To give an analogy: it feels like upscaling an image to double size and then saving that file and saying "_see, now it's better quality_", but in reality it doesn't contain more visual information, just 4 times more pixels and bytes encoding the same amount of information. _Oversimplified example, but I've seen people do this. Note that I see that you're much more intelligent than them!_
I guess we have to agree to disagree here on re-compression...
I've tried JPG 100, but it looks the same as I would not use the encoder at all (image gets pixelated). If I use WebP 100 it looks better, but the image look a bit blurry.
Do you have your format set in a GlideModule?
By the way, the default decode format is also 565 so there may be some quality loss there too.
What you see may not only be JPEG, but mix in some color degradation with 565 VS 8888 bitmap formats.
Yes, I have it set to DecodeFormat.PREFER_ARGB_8888. It's not color degradation (like gradient banding), it's pixelation + artifacts coming from reencoding JPG to JPG.
I think I've just faced a similar issue, it looks like an Android "thing", that's why I didn't see problems when I tried compressing an image on my laptop. That SO question confirms that bitmap.compress loses quality (a lot) like you said, and that JPEG re-compression (in general, not Android) is not that bad.
@malloth also found an explanation and solution to my issue, it could be integrated as a mini-library whereby Glide's encoder is replaceable with that.
@TWiStErRob you have answered "I think PNG is a little overkill though, JPEG is still half the size for photos even at 100%."
Why is JPEG still half the size for photos even at 100%?
@liushaofang Because JPEG is always lossy, even at 100%, but it's really unnoticeable. (Note that "half size" means less bytes on the filesystem, not image dimensions as you're looking for in #1132). Usually you can go as low as 80% without visual artifacts on real photos.
This unnoticeable loss at 100% allows for a better compression of the color data. You can think of it as PNG will save pixel values exactly, e.g. 101, 202, 103, 205, 98, but JPEG will "smooth" it to (1, 2, 1, 2, 1)*100 which is already shorter, just written down as text (14 digits vs 8 digits).
Of course the real JPEG works with much more complex math, the above is an oversimplification. For more read this: http://www.whydomath.org/node/wavlets/basicjpg.html or look for "how JPEG works" there are great resources out there (I've just learned deeper this week).
I'd be happy to accept a pull request that offers a higher quality JPEG encoder as an option for users who need the highest quality compressed images.
I'm going to call this fixed in 4.0. BitmapEncoder has options that allow you to set the compression format and quality per request. JPEG is substantially faster to decode so I think our defaults are reasonable. If callers want to change those defaults, they can use the BitmapEncoder options and RequestManager or GlideBuilder's setDefaultRequestOptions methods to do so globally or for a particular Fragment or ``Activity>
Most helpful comment
Thanks for help. As an override I now do the following: