Skip to content

Instantly share code, notes, and snippets.

@davemorrissey
Created November 9, 2017 10:40
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save davemorrissey/1f247d415e21ed10fddfd7fee49b4ff3 to your computer and use it in GitHub Desktop.
Save davemorrissey/1f247d415e21ed10fddfd7fee49b4ff3 to your computer and use it in GitHub Desktop.
Subsampling Scale Image View Input Stream Decoder
package com.davemorrissey.labs.subscaleview.decoder.inputstream;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.BitmapRegionDecoder;
import android.net.Uri;
import com.davemorrissey.labs.subscaleview.decoder.DecoderFactory;
import com.davemorrissey.labs.subscaleview.decoder.ImageDecoder;
import com.davemorrissey.labs.subscaleview.decoder.ImageRegionDecoder;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
public class InputStreamImageDecoder implements ImageDecoder {
public static class Factory implements DecoderFactory<InputStreamImageDecoder> {
private final InputStream inputStream;
private final Config bitmapConfig;
public Factory(InputStream inputStream) {
this(inputStream, null);
}
public Factory(InputStream inputStream, Config bitmapConfig) {
this.inputStream = inputStream;
this.bitmapConfig = bitmapConfig;
}
@Override
public InputStreamImageDecoder make() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
return new InputStreamImageDecoder(inputStream, bitmapConfig);
}
}
private final InputStream inputStream;
private final Config bitmapConfig;
private InputStreamImageDecoder(InputStream inputStream, Config bitmapConfig) {
this.inputStream = inputStream;
if (bitmapConfig == null) {
this.bitmapConfig = Config.RGB_565;
} else {
this.bitmapConfig = bitmapConfig;
}
}
@Override
public Bitmap decode(Context context, Uri uri) throws Exception {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = bitmapConfig;
return BitmapFactory.decodeStream(inputStream, null, options);
}
}
package com.davemorrissey.labs.subscaleview.decoder.inputstream;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.BitmapRegionDecoder;
import android.graphics.Point;
import android.graphics.Rect;
import android.net.Uri;
import com.davemorrissey.labs.subscaleview.decoder.DecoderFactory;
import com.davemorrissey.labs.subscaleview.decoder.ImageRegionDecoder;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
/**
* Default implementation of {@link ImageRegionDecoder}
* using Android's {@link BitmapRegionDecoder}, based on the Skia library. This
* works well in most circumstances and has reasonable performance due to the cached decoder instance,
* however it has some problems with grayscale, indexed and CMYK images.
*/
public class InputStreamImageRegionDecoder implements ImageRegionDecoder {
public static class Factory implements DecoderFactory<InputStreamImageRegionDecoder> {
private final InputStream inputStream;
private final Config bitmapConfig;
public Factory(InputStream inputStream) {
this(inputStream, null);
}
public Factory(InputStream inputStream, Config bitmapConfig) {
this.inputStream = inputStream;
this.bitmapConfig = bitmapConfig;
}
@Override
public InputStreamImageRegionDecoder make() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
return new InputStreamImageRegionDecoder(inputStream, bitmapConfig);
}
}
private BitmapRegionDecoder decoder;
private final Object decoderLock = new Object();
private final InputStream inputStream;
private final Config bitmapConfig;
private InputStreamImageRegionDecoder(InputStream inputStream, Config bitmapConfig) {
this.inputStream = inputStream;
if (bitmapConfig == null) {
this.bitmapConfig = Config.RGB_565;
} else {
this.bitmapConfig = bitmapConfig;
}
}
@Override
public Point init(Context context, Uri uri) throws Exception {
decoder = BitmapRegionDecoder.newInstance(inputStream, false);
return new Point(decoder.getWidth(), decoder.getHeight());
}
@Override
public Bitmap decodeRegion(Rect sRect, int sampleSize) {
synchronized (decoderLock) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = sampleSize;
options.inPreferredConfig = bitmapConfig;
Bitmap bitmap = decoder.decodeRegion(sRect, options);
if (bitmap == null) {
throw new RuntimeException("Skia image decoder returned null bitmap - image format may not be supported");
}
return bitmap;
}
}
@Override
public boolean isReady() {
return decoder != null && !decoder.isRecycled();
}
@Override
public void recycle() {
decoder.recycle();
}
}
public class MyActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
try {
InputStream is = getAssets().open("card.png", AssetManager.ACCESS_RANDOM);
SubsamplingScaleImageView view = findViewById(id.imageView);
view.setBitmapDecoderFactory(new InputStreamImageDecoder.Factory(is));
view.setRegionDecoderFactory(new InputStreamImageRegionDecoder.Factory(is));
view.setImage(ImageSource.asset("dummy"));
} catch (Exception e) {
// ...
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment