Android Open Source - volley Bitmap Decoder






From Project

Back to project page volley.

License

The source code is released under:

Apache License

If you think the Android project volley listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.android.volley.toolbox;
/*from w  w w .  jav  a 2  s  . c  om*/
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;

import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.MediaStore;

import com.android.volley.VolleyLog;
import com.android.volley.toolbox.ImageLoader.ImageCache;

public class BitmapDecoder {
    public static final String SCHEME_RES = "android_res://";
    public static final String SCHEME_ASSET = "android_asset://";
    public static final String SCHEME_CONTENT = "android_content://";
    
    protected static final String CONTENT_CONTACTS_URI_PREFIX = "content://com.android.contacts/";
    protected static final int BUFFER_SIZE = 32 * 1024; // 32 Kb
    
    /**
     * decode bitmap from resource
     * 
     * @param resId
     * @return
     */
    public static Bitmap getBitmapFromRes(Context context, ImageCache cache, int resId, int maxWidth, int maxHeight) {
        Bitmap bitmap = null;
        if (cache != null) {
            bitmap = cache.getBitmap(SCHEME_RES + resId);
        }
        if (bitmap == null) {
            bitmap = inputStream2Bitmap(context, SCHEME_RES + resId, getInputStream(context, SCHEME_RES + resId), Config.RGB_565, maxWidth, maxHeight);
            if (cache != null && bitmap != null) {
                cache.putBitmap(SCHEME_RES + resId, bitmap);
            }
        }
        return bitmap;
    }

    /**
     * decode bitmap from asset
     * bitmap getBitmapFromAsset
     * 
     * @param filePath
     * @return
     * @since 3.6
     */
    public static Bitmap getBitmapFromAsset(Context context, ImageCache cache, String filePath, int maxWidth, int maxHeight) {
        Bitmap bitmap = null;
        if (cache != null) {
            bitmap = cache.getBitmap(SCHEME_ASSET + filePath);
        }
        if (bitmap == null) {
            bitmap = inputStream2Bitmap(context, SCHEME_ASSET + filePath, getInputStream(context, SCHEME_ASSET + filePath), Config.RGB_565, maxWidth, maxHeight);
            if (cache != null && bitmap != null) {
                cache.putBitmap(SCHEME_ASSET + filePath, bitmap);
            }
        }
        return bitmap;
    }

    /**
     * decode bitmap from content
     * getStreamFromContent
     * 
     * @param imageUri
     * @return
     * @since 3.6
     */
    public static Bitmap getBitmapFromContent(Context context, ImageCache cache, String imageUri, int maxWidth, int maxHeight) {
        Bitmap bitmap = null;
        if (cache != null) {
            bitmap = cache.getBitmap(SCHEME_CONTENT + imageUri);
        }
        if (bitmap == null) {
            bitmap = inputStream2Bitmap(context, SCHEME_CONTENT + imageUri, getInputStream(context, SCHEME_CONTENT + imageUri), Config.RGB_565, maxWidth, maxHeight);
            if (cache != null && bitmap != null) {
                cache.putBitmap(SCHEME_CONTENT + imageUri, bitmap);
            }
        }
        return bitmap;
    }
    
    /**
     * decode bitmap from sdcard
     * getBitmapFromFile
     * @param cache
     * @param path
     * @param maxWidth
     * @param maxHeight
     * @return
     * @since 3.5
     */
    public static Bitmap getBitmapFromFile(ImageCache cache, String path, int maxWidth, int maxHeight) {
        Bitmap bitmap = null;
        if (cache != null) {
            bitmap = cache.getBitmap(path);
        }
        if (bitmap == null) {
            bitmap = inputStream2Bitmap(null, path, getInputStream(null, path), Config.RGB_565, maxWidth, maxHeight);
            if (cache != null && bitmap != null) {
                cache.putBitmap(path, bitmap);
            }
        }
        return bitmap;
    }
    
    private static boolean isVideoUri(Context context, Uri uri) {
        String mimeType = context.getContentResolver().getType(uri);
        if (mimeType == null) {
            return false;
        }
        return mimeType.startsWith("video/");
    }
    
    // get the best size to decode bitmap
    static int findBestSampleSize(
            int actualWidth, int actualHeight, int desiredWidth, int desiredHeight) {
        double wr = (double) actualWidth / desiredWidth;
        double hr = (double) actualHeight / desiredHeight;
        double ratio = Math.min(wr, hr);
        float n = 1.0f;
        while ((n * 2) <= ratio) {
            n *= 2;
        }
        return (int) n;
    }
    
    static int getResizedDimension(int maxPrimary, int maxSecondary, int actualPrimary,
            int actualSecondary) {
        // If no dominant value at all, just return the actual.
        if (maxPrimary == 0 && maxSecondary == 0) {
            return actualPrimary;
        }

        // If primary is unspecified, scale primary to match secondary's scaling ratio.
        if (maxPrimary == 0) {
            double ratio = (double) maxSecondary / (double) actualSecondary;
            return (int) (actualPrimary * ratio);
        }

        if (maxSecondary == 0) {
            return maxPrimary;
        }

        double ratio = (double) actualSecondary / (double) actualPrimary;
        int resized = maxPrimary;
        if (resized * ratio > maxSecondary) {
            resized = (int) (maxSecondary / ratio);
        }
        return resized;
    }
    
    @SuppressLint("DefaultLocale")
    public static InputStream getInputStream(Context context, String key) {
        if (key.startsWith(SCHEME_RES)) {
            int index = key.indexOf(SCHEME_RES);
            int id = Integer.parseInt(key.substring(index + SCHEME_RES.length()));
            return context.getResources().openRawResource(id);

        } else if (key.startsWith(SCHEME_ASSET)) {
            int index = key.indexOf(SCHEME_ASSET);
            String filePath = key.substring(index + SCHEME_ASSET.length());
            try {
                return context.getAssets().open(filePath);
            } catch (IOException e) {
                e.printStackTrace();
            }

        } else if (key.startsWith(SCHEME_CONTENT)) {
            ContentResolver res = context.getContentResolver();
            int index = key.indexOf(SCHEME_CONTENT);
            String imageUri = key.substring(index + SCHEME_CONTENT.length());
            Uri uri = Uri.parse(imageUri);
            if (isVideoUri(context, uri)) { // video thumbnail
                Long origId = Long.valueOf(uri.getLastPathSegment());
                Bitmap bitmap = MediaStore.Video.Thumbnails.getThumbnail(res, origId,
                        MediaStore.Images.Thumbnails.MINI_KIND, null);
                if (bitmap != null) {
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    bitmap.compress(CompressFormat.PNG, 0, bos);
                    return new ByteArrayInputStream(bos.toByteArray());
                }
            } else if (imageUri.startsWith(CONTENT_CONTACTS_URI_PREFIX)) { // contacts
                return ContactsContract.Contacts.openContactPhotoInputStream(res, uri);
            } else {
                try {
                    return res.openInputStream(uri);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }

        } else if (key.trim().toLowerCase().startsWith("file")) {
            try {
                String filePath = new URI(key).getPath();
                return new ContentLengthInputStream(new BufferedInputStream(new FileInputStream(filePath), BUFFER_SIZE),
                        (int) new File(filePath).length());
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (URISyntaxException e) {
                e.printStackTrace();
            }

        } else if (key.trim().toLowerCase().startsWith("/")) {
            try {
                return new ContentLengthInputStream(new BufferedInputStream(new FileInputStream(key), BUFFER_SIZE),
                        (int) new File(key).length());
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    
    /**
     * ???????bitmap
     * inputStream2Bitmap
     * @param context ??????
     * @param key ???????????key
     * @param is ??
     * @param config
     * @param maxWidth
     * @param maxHeight
     * @return
     * @since 3.5
     */
    public static Bitmap inputStream2Bitmap(Context context, String key, InputStream is, Config config, int maxWidth, int maxHeight) {
        if (is == null) return null;
        BitmapFactory.Options decodeOptions = new BitmapFactory.Options();
        Bitmap bitmap = null;
        if (maxWidth == 0 && maxWidth == 0) {
            decodeOptions.inPreferredConfig = config;
            decodeOptions.inPurgeable = true;
            bitmap = BitmapFactory.decodeStream(is, null, decodeOptions);
        } else {
            // If we have to resize this image, first get the natural bounds.
            decodeOptions.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(is, null, decodeOptions);
            int actualWidth = decodeOptions.outWidth;
            int actualHeight = decodeOptions.outHeight;

            // Then compute the dimensions we would ideally like to decode to.
            int desiredWidth = getResizedDimension(maxWidth, maxHeight, actualWidth, actualHeight);
            int desiredHeight = getResizedDimension(maxHeight, maxWidth, actualHeight, actualWidth);

            // Decode to the nearest power of two scaling factor.
            decodeOptions.inJustDecodeBounds = false;
            decodeOptions.inPurgeable = true;
            // TODO(ficus): Do we need this or is it okay since API 8 doesn't
            // support it?
            // decodeOptions.inPreferQualityOverSpeed =
            // PREFER_QUALITY_OVER_SPEED;
            decodeOptions.inSampleSize = findBestSampleSize(actualWidth, actualHeight, desiredWidth, desiredHeight);
            try {
                is.reset();
            } catch (IOException e) {
                try {
                    is.close();
                } catch (IOException e1) {
                }
                is = getInputStream(context, key);
            }
            Bitmap tempBitmap = BitmapFactory.decodeStream(is, null, decodeOptions);

            // If necessary, scale down to the maximal acceptable size.
            if (tempBitmap != null && (tempBitmap.getWidth() > desiredWidth || tempBitmap.getHeight() > desiredHeight)) {
                bitmap = Bitmap.createScaledBitmap(tempBitmap, desiredWidth, desiredHeight, true);
                tempBitmap.recycle();
            } else {
                bitmap = tempBitmap;
            }
            // ????????????exif???????????
            if (canDefineExifParams(key)) {
                bitmap = considerExactScaleAndOrientatiton(bitmap, defineExifOrientation(key));
            }
        }
        return bitmap;
    }
    
    public static Bitmap bytes2Bitmap(byte[] data, int maxWidth, int maxHeight) {
        return bytes2Bitmap(data, Config.RGB_565, maxWidth, maxHeight);
    }
    
    public static Bitmap bytes2Bitmap(byte[] data, Config config, int maxWidth, int maxHeight) {
        if (data == null) return null;
        BitmapFactory.Options decodeOptions = new BitmapFactory.Options();
        Bitmap bitmap = null;
        if (maxWidth == 0 && maxWidth == 0) {
            decodeOptions.inPreferredConfig = config;
            decodeOptions.inPurgeable = true;
            bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);
        } else {
            // If we have to resize this image, first get the natural bounds.
            decodeOptions.inJustDecodeBounds = true;
            BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);
            int actualWidth = decodeOptions.outWidth;
            int actualHeight = decodeOptions.outHeight;

            // Then compute the dimensions we would ideally like to decode to.
            int desiredWidth = getResizedDimension(maxWidth, maxHeight, actualWidth, actualHeight);
            int desiredHeight = getResizedDimension(maxHeight, maxWidth, actualHeight, actualWidth);

            // Decode to the nearest power of two scaling factor.
            decodeOptions.inJustDecodeBounds = false;
            decodeOptions.inPurgeable = true;
            // TODO(ficus): Do we need this or is it okay since API 8 doesn't
            // support it?
            // decodeOptions.inPreferQualityOverSpeed =
            // PREFER_QUALITY_OVER_SPEED;
            decodeOptions.inSampleSize = findBestSampleSize(actualWidth, actualHeight, desiredWidth, desiredHeight);
            Bitmap tempBitmap = null;
            try {
                tempBitmap = BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);
            } catch (OutOfMemoryError e) {
                decodeOptions.inSampleSize++;
                tempBitmap = BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);
            }

            // If necessary, scale down to the maximal acceptable size.
            if (tempBitmap != null && (tempBitmap.getWidth() > desiredWidth || tempBitmap.getHeight() > desiredHeight)) {
                bitmap = Bitmap.createScaledBitmap(tempBitmap, desiredWidth, desiredHeight, true);
                tempBitmap.recycle();
            } else {
                bitmap = tempBitmap;
            }
        }
        return bitmap;
    }
    
    private static boolean canDefineExifParams(String imageUri) {
        String uri = imageUri.toLowerCase();
        return (uri.endsWith("jpg") || uri.endsWith("png") || uri.endsWith("jpeg")) && imageUri.startsWith("/");
    }

    private static ExifInfo defineExifOrientation(String imageUri) {
        int rotation = 0;
        boolean flip = false;
        try {
            ExifInterface exif = new ExifInterface(imageUri);
            int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (exifOrientation) {
                case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
                    flip = true;
                case ExifInterface.ORIENTATION_NORMAL:
                    rotation = 0;
                    break;
                case ExifInterface.ORIENTATION_TRANSVERSE:
                    flip = true;
                case ExifInterface.ORIENTATION_ROTATE_90:
                    rotation = 90;
                    break;
                case ExifInterface.ORIENTATION_FLIP_VERTICAL:
                    flip = true;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    rotation = 180;
                    break;
                case ExifInterface.ORIENTATION_TRANSPOSE:
                    flip = true;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    rotation = 270;
                    break;
            }
        } catch (IOException e) {
            VolleyLog.e("Can't read EXIF tags from file [%s]", imageUri);
        }
        return new ExifInfo(rotation, flip);
    }
    
    protected static Bitmap considerExactScaleAndOrientatiton(Bitmap subsampledBitmap, ExifInfo exifInfo) {
        Matrix m = new Matrix();
        // Flip bitmap if need
        if (exifInfo.flipHorizontal) {
            m.postScale(-1, 1);
        }
        // Rotate bitmap if need
        if (exifInfo.rotation != 0) {
            m.postRotate(exifInfo.rotation);
        }

        Bitmap finalBitmap = Bitmap.createBitmap(subsampledBitmap, 0, 0, subsampledBitmap.getWidth(), subsampledBitmap
                .getHeight(), m, true);
        if (finalBitmap != subsampledBitmap) {
            subsampledBitmap.recycle();
        }
        return finalBitmap;
    }


    protected static class ExifInfo {

        public final int rotation;
        public final boolean flipHorizontal;

        protected ExifInfo() {
            this.rotation = 0;
            this.flipHorizontal = false;
        }

        protected ExifInfo(int rotation, boolean flipHorizontal) {
            this.rotation = rotation;
            this.flipHorizontal = flipHorizontal;
        }
    }
}




Java Source Code List

com.android.volley.AuthFailureError.java
com.android.volley.CacheDispatcher.java
com.android.volley.Cache.java
com.android.volley.DefaultRetryPolicy.java
com.android.volley.ExecutorDelivery.java
com.android.volley.NetworkDispatcher.java
com.android.volley.NetworkError.java
com.android.volley.NetworkResponse.java
com.android.volley.Network.java
com.android.volley.NoConnectionError.java
com.android.volley.ParseError.java
com.android.volley.RequestQueue.java
com.android.volley.Request.java
com.android.volley.ResponseDelivery.java
com.android.volley.Response.java
com.android.volley.RetryPolicy.java
com.android.volley.ServerError.java
com.android.volley.TimeoutError.java
com.android.volley.Utils.java
com.android.volley.VolleyError.java
com.android.volley.VolleyLog.java
com.android.volley.ext.ContentLengthInputStream.java
com.android.volley.ext.HttpCallback.java
com.android.volley.ext.PauseOnScrollListener.java
com.android.volley.ext.RequestInfo.java
com.android.volley.ext.display.IDisplayer.java
com.android.volley.ext.display.SimpleDisplayer.java
com.android.volley.ext.tools.BitmapTools.java
com.android.volley.ext.tools.HttpTools.java
com.android.volley.toolbox.AndroidAuthenticator.java
com.android.volley.toolbox.Authenticator.java
com.android.volley.toolbox.BasicNetwork.java
com.android.volley.toolbox.BitmapCache.java
com.android.volley.toolbox.BitmapDecoder.java
com.android.volley.toolbox.ByteArrayPool.java
com.android.volley.toolbox.ClearCacheRequest.java
com.android.volley.toolbox.ContentLengthInputStream.java
com.android.volley.toolbox.DiskBasedCache.java
com.android.volley.toolbox.DiskLruBasedCache.java
com.android.volley.toolbox.DownloadRequest.java
com.android.volley.toolbox.HttpClientStack.java
com.android.volley.toolbox.HttpHeaderParser.java
com.android.volley.toolbox.HttpStack.java
com.android.volley.toolbox.HurlStack.java
com.android.volley.toolbox.ImageLoader.java
com.android.volley.toolbox.ImageRequest.java
com.android.volley.toolbox.InflatingEntity.java
com.android.volley.toolbox.JsonArrayRequest.java
com.android.volley.toolbox.JsonObjectRequest.java
com.android.volley.toolbox.JsonRequest.java
com.android.volley.toolbox.MultiPartRequest.java
com.android.volley.toolbox.NetworkImageView.java
com.android.volley.toolbox.NoCache.java
com.android.volley.toolbox.PoolingByteArrayOutputStream.java
com.android.volley.toolbox.RequestFuture.java
com.android.volley.toolbox.StringRequest.java
com.android.volley.toolbox.UploadMultipartEntity.java
com.android.volley.toolbox.Volley.java
com.android.volley.toolbox.disklrucache.DiskLruCache.java
com.android.volley.toolbox.disklrucache.StrictLineReader.java
com.android.volley.toolbox.disklrucache.Util.java
com.android.volley.toolbox.multipart.BasePart.java
com.android.volley.toolbox.multipart.Boundary.java
com.android.volley.toolbox.multipart.FilePart.java
com.android.volley.toolbox.multipart.MultipartEntity.java
com.android.volley.toolbox.multipart.Part.java
com.android.volley.toolbox.multipart.StringPart.java
com.android.volley.toolbox.multipart.UrlEncodingHelper.java