Get/pick an image from Android's built-in Gallery app programmatically

前端 未结 19 1647
终归单人心
终归单人心 2020-11-22 00:49

I am trying to open an image / picture in the Gallery built-in app from inside my application.

I have a URI of the picture (the picture is located on the SD card).

19条回答
  •  深忆病人
    2020-11-22 01:08

    this is my revisit to this topic, gathering all the information here, plus from other relevant stack overflow questions. It returns images from some provider, while handling out-of-memory conditions and image rotation. It supports gallery, picasa and file managers, like drop box. Usage is simple: as input, the constructor receives the content resolver and the uri. The output is the final bitmap.

    /**
     * Creates resized images without exploding memory. Uses the method described in android
     * documentation concerning bitmap allocation, which is to subsample the image to a smaller size,
     * close to some expected size. This is required because the android standard library is unable to
     * create a reduced size image from an image file using memory comparable to the final size (and
     * loading a full sized multi-megapixel picture for processing may exceed application memory budget).
     */
    
    public class UserPicture {
        static int MAX_WIDTH = 600;
        static int MAX_HEIGHT = 800;
        Uri uri;
        ContentResolver resolver;
        String path;
        Matrix orientation;
        int storedHeight;
        int storedWidth;
    
        public UserPicture(Uri uri, ContentResolver resolver) {
            this.uri = uri;
            this.resolver = resolver;
        }
    
        private boolean getInformation() throws IOException {
            if (getInformationFromMediaDatabase())
                return true;
    
            if (getInformationFromFileSystem())
                return true;
    
            return false;
        }
    
        /* Support for gallery apps and remote ("picasa") images */
        private boolean getInformationFromMediaDatabase() {
            String[] fields = { Media.DATA, ImageColumns.ORIENTATION };
            Cursor cursor = resolver.query(uri, fields, null, null, null);
    
            if (cursor == null)
                return false;
    
            cursor.moveToFirst();
            path = cursor.getString(cursor.getColumnIndex(Media.DATA));
            int orientation = cursor.getInt(cursor.getColumnIndex(ImageColumns.ORIENTATION));
            this.orientation = new Matrix();
            this.orientation.setRotate(orientation);
            cursor.close();
    
            return true;
        }
    
        /* Support for file managers and dropbox */
        private boolean getInformationFromFileSystem() throws IOException {
            path = uri.getPath();
    
            if (path == null)
                return false;
    
            ExifInterface exif = new ExifInterface(path);
            int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                                                   ExifInterface.ORIENTATION_NORMAL);
    
            this.orientation = new Matrix();
            switch(orientation) {
                case ExifInterface.ORIENTATION_NORMAL:
                    /* Identity matrix */
                    break;
                case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
                    this.orientation.setScale(-1, 1);
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    this.orientation.setRotate(180);
                    break;
                case ExifInterface.ORIENTATION_FLIP_VERTICAL:
                    this.orientation.setScale(1, -1);
                    break;
                case ExifInterface.ORIENTATION_TRANSPOSE:
                    this.orientation.setRotate(90);
                    this.orientation.postScale(-1, 1);
                    break;
                case ExifInterface.ORIENTATION_ROTATE_90:
                    this.orientation.setRotate(90);
                    break;
                case ExifInterface.ORIENTATION_TRANSVERSE:
                    this.orientation.setRotate(-90);
                    this.orientation.postScale(-1, 1);
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    this.orientation.setRotate(-90);
                    break;
            }
    
            return true;
        }
    
        private boolean getStoredDimensions() throws IOException {
            InputStream input = resolver.openInputStream(uri);
            Options options = new Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(resolver.openInputStream(uri), null, options);
    
            /* The input stream could be reset instead of closed and reopened if it were possible
               to reliably wrap the input stream on a buffered stream, but it's not possible because
               decodeStream() places an upper read limit of 1024 bytes for a reset to be made (it calls
               mark(1024) on the stream). */
            input.close();
    
            if (options.outHeight <= 0 || options.outWidth <= 0)
                return false;
    
            storedHeight = options.outHeight;
            storedWidth = options.outWidth;
    
            return true;
        }
    
        public Bitmap getBitmap() throws IOException {
            if (!getInformation())
                throw new FileNotFoundException();
    
            if (!getStoredDimensions())
                throw new InvalidObjectException(null);
    
            RectF rect = new RectF(0, 0, storedWidth, storedHeight);
            orientation.mapRect(rect);
            int width = (int)rect.width();
            int height = (int)rect.height();
            int subSample = 1;
    
            while (width > MAX_WIDTH || height > MAX_HEIGHT) {
                width /= 2;
                height /= 2;
                subSample *= 2;
            }
    
            if (width == 0 || height == 0)
                throw new InvalidObjectException(null);
    
            Options options = new Options();
            options.inSampleSize = subSample;
            Bitmap subSampled = BitmapFactory.decodeStream(resolver.openInputStream(uri), null, options);
    
            Bitmap picture;
            if (!orientation.isIdentity()) {
                picture = Bitmap.createBitmap(subSampled, 0, 0, options.outWidth, options.outHeight,
                                              orientation, false);
                subSampled.recycle();
            } else
                picture = subSampled;
    
            return picture;
        }
    }
    

    References:

    • http://developer.android.com/training/displaying-bitmaps/index.html
    • Get/pick an image from Android's built-in Gallery app programmatically
    • Strange out of memory issue while loading an image to a Bitmap object
    • Set image orientation using ExifInterface
    • https://gist.github.com/9re/1990019
    • how to get bitmap information and then decode bitmap from internet-inputStream?

提交回复
热议问题