Skip to content

Commit

Permalink
Allow transparent images
Browse files Browse the repository at this point in the history
Load PNGs as ARGB_8888 and JPEGs as RGB_565 preferentially.
Also save ARGB_8888 images to disk cache as PNGs and RGB_565
as jpegs. Fixes some quality issues with transparent images
  • Loading branch information
Sam Judd committed Sep 10, 2013
1 parent 9deda93 commit 525d503
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 26 deletions.
3 changes: 1 addition & 2 deletions library/src/com/bumptech/glide/presenter/ImagePresenter.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,9 @@ public static class Builder<T> {
private ExceptionHandler<T> exceptionHandler = new ExceptionHandler<T>() {
@Override
public void onException(Exception e, T model, boolean isCurrent) {
Log.e("IP: onImageLoadException model= " + model);
if (e != null) {
e.printStackTrace();
} else {
Log.e("IP: onImageLoadException model= " + model);
}
}
};
Expand Down
2 changes: 1 addition & 1 deletion library/src/com/bumptech/glide/resize/ImageManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ private void putInDiskCache(String key, final Bitmap bitmap) {
diskCache.put(key, new DiskCache.Writer() {
@Override
public void write(OutputStream os) {
bitmap.compress(bitmapCompressFormat, bitmapCompressQuality, os);
bitmap.compress(bitmap.getConfig() == Bitmap.Config.ARGB_8888 ? Bitmap.CompressFormat.PNG : Bitmap.CompressFormat.JPEG, bitmapCompressQuality, os);
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@

public interface BitmapPool {
public boolean put(Bitmap bitmap);
public Bitmap get(int width, int height);
public Bitmap get(int width, int height, Bitmap.Config config);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
import android.graphics.Bitmap;

public class BitmapPoolAdapter implements BitmapPool {

@Override
public boolean put(Bitmap bitmap) {
return false;
}

@Override
public Bitmap get(int width, int height) {
public Bitmap get(int width, int height, Bitmap.Config config) {
return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,6 @@ public LruBitmapPool(int maxSize) {

@Override
public synchronized boolean put(Bitmap bitmap) {
//BitmapFactory.decodeStream can sometimes return bitmaps with null configs, which can't generally be
//reused
if (bitmap.getConfig() == null) {
return false;
}

final int size = getSize(bitmap);

pool.put(bitmap);
Expand All @@ -45,10 +39,10 @@ private void evict() {
}

@Override
public synchronized Bitmap get(int width, int height) {
final Bitmap result = pool.get(width, height);
public synchronized Bitmap get(int width, int height, Bitmap.Config config) {
final Bitmap result = pool.get(width, height, config);
if (result == null) {
Log.d("LBP: missing bitmap for width=" + width + " height=" + height);
Log.d("LBP: missing bitmap for width=" + width + " height=" + height + " config=" + config);
} else {
currentSize -= getSize(result);
}
Expand Down Expand Up @@ -77,14 +71,14 @@ private static class GroupedBitmapLinkedMap {
private static class KeyPool {
private static final int MAX_SIZE = 20;

private Queue<Key> keyPool = new LinkedList<Key>();
private final Queue<Key> keyPool = new LinkedList<Key>();

public Key get(int width, int height) {
public Key get(int width, int height, Bitmap.Config config) {
Key result = keyPool.poll();
if (result == null) {
result = new Key();
}
result.init(width, height);
result.init(width, height, config);
return result;
}

Expand All @@ -98,10 +92,12 @@ public void offer(Key key) {
private static class Key {
private int width;
private int height;
private Bitmap.Config config; //this can be null :(

public void init(int width, int height) {
public void init(int width, int height, Bitmap.Config config) {
this.width = width;
this.height = height;
this.config = config;
}

@Override
Expand All @@ -113,6 +109,7 @@ public boolean equals(Object o) {

if (height != key.height) return false;
if (width != key.width) return false;
if (config != key.config) return false;

return true;
}
Expand All @@ -121,12 +118,13 @@ public boolean equals(Object o) {
public int hashCode() {
int result = width;
result = 31 * result + height;
result = 31 * result + (config != null ? config.hashCode() : 0);
return result;
}
}

public void put(Bitmap bitmap) {
final Key key = keyPool.get(bitmap.getWidth(), bitmap.getHeight());
final Key key = keyPool.get(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());

LinkedEntry entry = keyToEntry.get(key);
if (entry == null) {
Expand All @@ -140,8 +138,8 @@ public void put(Bitmap bitmap) {
entry.add(bitmap);
}

public Bitmap get(int width, int height) {
final Key key = keyPool.get(width, height);
public Bitmap get(int width, int height, Bitmap.Config config) {
final Key key = keyPool.get(width, height, config);

LinkedEntry entry = keyToEntry.get(key);
if (entry == null) {
Expand Down
27 changes: 24 additions & 3 deletions library/src/com/bumptech/glide/resize/load/Downsampler.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import android.os.Build;
import com.bumptech.glide.resize.RecyclableBufferedInputStream;
import com.bumptech.glide.resize.bitmap_recycle.BitmapPool;
import com.bumptech.glide.util.Log;

import java.io.IOException;

Expand Down Expand Up @@ -39,7 +40,6 @@ protected int getSampleSize(int inWidth, int inHeight, int outWidth, int outHeig
}
};


/**
* Load the image at its original size
*
Expand Down Expand Up @@ -71,7 +71,7 @@ public Bitmap downsample(RecyclableBufferedInputStream bis, BitmapFactory.Option
bis.mark(MARK_POSITION);
int orientation = 0;
try {
orientation = new ExifOrientationParser(bis).getOrientation();//ImageResizer.getOrientation(bis);
orientation = new ExifOrientationParser(bis).getOrientation();
} catch (IOException e) {
e.printStackTrace();
}
Expand Down Expand Up @@ -109,11 +109,28 @@ protected Bitmap downsampleWithSize(RecyclableBufferedInputStream bis, BitmapFac
if (sampleSize > 1) {
options.inSampleSize = sampleSize;
} else {
setInBitmap(options, pool.get(inWidth, inHeight));
setInBitmap(options, pool.get(inWidth, inHeight, getConfig(bis)));
}
return decodeStream(bis, options);
}

private Bitmap.Config getConfig(RecyclableBufferedInputStream bis) {
Bitmap.Config result = Bitmap.Config.RGB_565;
bis.mark(1024); //we probably only need 25, but this is safer (particularly since the buffer size is > 1024)
try {
result = new ExifOrientationParser(bis).hasAlpha() ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bis.reset();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}

/**
* Get some id that uniquely identifies the downsample for use as part of a cache key
* @return A unique String
Expand Down Expand Up @@ -163,6 +180,9 @@ private Bitmap decodeStream(RecyclableBufferedInputStream bis, BitmapFactory.Opt
}

final Bitmap result = BitmapFactory.decodeStream(bis, null, options);
if (result == null && !options.inJustDecodeBounds) {
throw new IllegalArgumentException("IP: null result, sampleSize=" + options.inSampleSize);
}

try {
if (options.inJustDecodeBounds) {
Expand All @@ -172,6 +192,7 @@ private Bitmap decodeStream(RecyclableBufferedInputStream bis, BitmapFactory.Opt
bis.close();
}
} catch (IOException e) {
Log.d("Downsampler: exception loading inDecodeBounds=" + options.inJustDecodeBounds + " sample=" + options.inSampleSize);
e.printStackTrace();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
* A class for parsing the exif orientation from an InputStream for an image. Handles jpegs and tiffs.
*/
public class ExifOrientationParser {
private static final int GIF_HEADER = 0x474946;
private static final int PNG_HEADER = 0x89504E47;
private static final int EXIF_MAGIC_NUMBER = 0xFFD8;
private static final int MOTOROLA_TIFF_MAGIC_NUMBER = 0x4D4D; // "MM"
private static final int INTEL_TIFF_MAGIC_NUMBER = 0x4949; // "II"
Expand All @@ -32,6 +34,32 @@ public ExifOrientationParser(InputStream is) {
streamReader = new StreamReader(is);
}


// 0xD0A3C68 -> <htm
// 0xCAFEBABE -> <!DOCTYPE...
public boolean hasAlpha() throws IOException {
int firstByte = streamReader.getUInt8();

if (firstByte == EXIF_MAGIC_NUMBER >> 8) { //JPEG
return false;
}

final int firstTwoBytes = firstByte << 8 & 0xFF00 | streamReader.getUInt8() & 0xFF;
final int firstFourBytes = firstTwoBytes << 16 & 0xFFFF0000 | streamReader.getUInt16() & 0xFFFF;
if (firstFourBytes == PNG_HEADER) { //PNG
//see: http://stackoverflow.com/questions/2057923/how-to-check-a-png-for-grayscale-alpha-color-type
streamReader.skip(25 - 4);
int alpha = streamReader.getByte();
return alpha > 3;
}

if (firstFourBytes >> 8 == GIF_HEADER) { //GIF from first 3 bytes
return true;
}

return false;
}

/**
* Parse the orientation from the image header. If it doesn't handle this image type (or this is not an image)
* it will return a default value rather than throwing an exception.
Expand Down Expand Up @@ -225,6 +253,10 @@ public long skip(long total) throws IOException {
public int read(byte[] buffer) throws IOException {
return is.read(buffer);
}

public int getByte() throws IOException {
return is.read();
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ public static Bitmap rotateImageExif(Bitmap toOrient, BitmapPool pool, int exifO
final int newWidth = Math.round(newRect.width());
final int newHeight = Math.round(newRect.height());

Bitmap result = pool.get(newWidth, newHeight);
Bitmap result = pool.get(newWidth, newHeight, toOrient.getConfig());
if (result == null) {
result = Bitmap.createBitmap(newWidth, newHeight, toOrient.getConfig());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public Bitmap transform(Bitmap bitmap, BitmapPool pool, int outWidth, int outHei
throw new IllegalArgumentException("Cannot center crop image to width=" + outWidth + " and height="
+ outHeight);
}
return ImageResizer.centerCrop(pool.get(outWidth, outHeight), bitmap, outWidth, outHeight);
return ImageResizer.centerCrop(pool.get(outWidth, outHeight, bitmap.getConfig()), bitmap, outWidth, outHeight);
}
};

Expand Down

0 comments on commit 525d503

Please sign in to comment.