OutOfMemoryError while decoding and encoding Base64 String into Bitmap

前端 未结 7 2007
你的背包
你的背包 2020-12-14 14:49

I\'m trying to decode and encode a Bitmap image. On some devices it runs perfectly while on others it\'s not. I\'m uploading Bas

7条回答
  •  死守一世寂寞
    2020-12-14 15:30

    As greenapps suggested, it would be better to avoid using Bitmap and BitmapFactory in order to TRANSMIT the file:

    FileInputStream fis = new FileInputStream(imageFile);
    byte[] byteArray = inputStreamToByteArray(fis);
    String base64ImageSend = Base64.encodeToString(byteArray, Base64.NO_WRAP);
    

    where:

    /**
     * Convert an InputStream object into a byte array
     * @param inputStream The InputStream to convert
     * @return The byte[] representing the converted InputStream or null if the inputStream is null
     */
    public static byte[] inputStreamToByteArray(InputStream inputStream) throws IOException {
        if(inputStream==null) {
            return null;
        }
        ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
        int bufferSize = 1024;
        byte[] buffer = new byte[bufferSize];
    
        int len = 0;
        while ((len = inputStream.read(buffer)) != -1) {
            byteBuffer.write(buffer, 0, len);
        }
        return byteBuffer.toByteArray();
    }
    

    Actually the outOfMemory problem, as stated by Kai, is due to the fact that you are decoding a full resolution and high quality image. The better way to avoid this is to downsampling your image:

    /**
     * Decode a file, representing an image, into a bitmap, trying to scale the original image if required
     * @param context The application context
     * @param file The image file
     * @param requestedWidth The requested width
     * @param requestedHeight The requested height
     * @return The decoded bitmap or null if it is not possible to decode the file parameter
     */
    public static Bitmap decodeImageFileIntoMutableBitmap(Context context, File file, int requestedWidth, int requestedHeight) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true; // just compute size, don't create bitmap
        BitmapFactory.decodeFile(file.getAbsolutePath(), options);
        float sampleSize = computeImageScaleCoefficient(options, requestedWidth, requestedHeight);
        if (sampleSize == -1) {
            return null;
        }
        else if (sampleSize <= 1) {
            options.inSampleSize = 1;
        }
        else {
            options.inSampleSize = (int) sampleSize;
        }
        options.inJustDecodeBounds = false; // compute size and create bitmap
        /*it is possible to reduce the memory when decoding through skipping ARGB_8888 and using RGB_565 instead and inDither to true to preserve image quality.*/
        //options.inPreferredConfig = Bitmap.Config.RGB_565;
        //options.inDither = true;
        Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), options);
        if (bitmap == null) {
            return null;
        }
        return bitmap;
    }
    
    /**
     * Find the sample coefficient sk=2k, with k &isin ℕ, such that
     * mink(requestedWidth-options.outWidth×sk)>0
     * &&
     * mink(requestedHeight-options.outHeight×sk)>0
     * @param options The BitmapFactory.Options instance of the original image user wants to scale
     * @param requestedWidth The requested width
     * @param requestedHeight The requested height
     * @return -1 if if there is an error trying to decode the image
     * or the sample coefficient sk,
     * >1 if the image needs to be down-sampled,
     * <1 if the image needs to be up-sampled
     */
    public static float computeImageScaleCoefficient(BitmapFactory.Options options, int requestedWidth, int requestedHeight) {
        float sampleCoefficient = 1;
        int imageWidth = options.outWidth;
        int imageHeight = options.outHeight;
        if (imageWidth == -1 || imageHeight == -1) {
            return -1;
        }
        double outWidth = imageWidth;
        double outHeight = imageHeight;
        if ((outWidth > requestedWidth) || (outHeight > requestedHeight)) {
            while ((outWidth > requestedWidth) || (outHeight > requestedHeight)) {
                outWidth = Math.floor(outWidth/2.0);
                outHeight = Math.floor(outHeight/2.0);
                sampleCoefficient *= 2.0;
            }
        }
        else {
            while ((outWidth < requestedWidth) && (outHeight < requestedHeight)) {
                outWidth *= 2;
                outHeight *= 2;
                if ((outWidth <= requestedWidth) && (outHeight <= requestedHeight)) {
                    sampleCoefficient /= 2.0;
                }
            }
        }
        return sampleCoefficient;
    }
    

提交回复
热议问题