将位图转换为字节数组占用大量内存。

4
我需要将位图转换为字节数组以便上传到服务器。我成功地通过将位图转换为字节数组,然后按照这里的说明再将其转换为Base 64字符串来实现此操作。它的工作效果很好,但在我的Galaxy S2手机上,如果图像大小为6MB,分辨率为72像素/英寸,它占用了约600MB的RAM,并因OutOfMemoryException而崩溃。我尝试通过压缩位图来上传,它可以正常工作,但根据我的项目要求,我需要上传原始图像,即不进行任何压缩。

请帮助我如何实现这一点,无论是否有可能。

谢谢您提前的帮助。


你是否正在寻找一种编码和流式传输数据的方法,而不是一次性全部转换? - Damon Smith
2个回答

0

上传时转换为JPEG流

BufferedStream bs = //...

然后调用bitmap.compress("JPEG", 0, length, bs)

将bs转换为数组并上传到服务器


0

Android应用程序分配内存堆是有限的,特别是在低内存设备上。

您正在犯两个常见错误:

  • 首先,关于上传问题 - 您正在持有完整大小图像的位图对象(可能是使用相机拍摄的)。这是第一次犯错。如果您必须在用户界面上显示捕获的图像,则应根据所需的显示大小(ImageView 的宽度和高度)从刚刚捕获和创建的捕获图像文件中加载缩放版本位图:

    public static Bitmap getSampleBitmapFromFile(String bitmapFilePath, int reqWidth, int reqHeight) {
    try {
        File f = new File(bitmapFilePath);
        ExifInterface exif = new ExifInterface(f.getPath());
        int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
    
        int angle = 0;
    
        if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
            angle = 90;
        } else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
            angle = 180;
        } else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
            angle = 270;
        }
    
        Matrix mat = new Matrix();
        mat.postRotate(angle);
    
        // 计算图像大小
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(new FileInputStream(f), null, options);
    
        int scale = calculateInSampleSize(options, reqWidth, reqHeight);
    
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
    
        Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
        Bitmap correctBmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), mat, true);
    
        return correctBmp;
    } catch (IOException e) {
        Log.e(TAG, "cant butmaputils.getSampleBitmapFromFile failed with IO exception: ", e);
        if (e != null)
            e.printStackTrace();
    } catch (OutOfMemoryError oom) {
        Log.e(TAG, "cant butmaputils.getSampleBitmapFromFile failed with OOM error: ");
        if (oom != null)
            oom.printStackTrace();
    } catch (Exception e) {
        Log.e(TAG, "cant butmaputils.getSampleBitmapFromFile failed with exception: ", e);
    }
    Log.e(TAG, "butmaputils.getSampleBitmapFromFilereturn null for file: " + bitmapFilePath);
    return null;
     }
    
    
    
    public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // 图像的原始高度和宽度
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;
    
    if (height > reqHeight || width > reqWidth) {
    
        // 计算高度和宽度与请求高度和宽度的比率
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);
    
        // 选择最小比率作为inSampleSize值,这将保证
        // 最终图像的两个尺寸都大于或等于所请求的高度和宽度。
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }
    
    return inSampleSize;
    }
    

仅通过这种方式,您就可以大大减少内存分配堆的压力,因为您可以只分配100x200而不是1080x1920个整数,如果这是您的imageView屏幕尺寸。

  • 第二:上传到服务器:您应该上传来自大型原始文件的直接流,而不是将其作为位图加载到内存中并将其解码为base64或其他格式。最好的方法是使用Multipart Entity

使用这种方法,不会对内存分配堆产生任何影响,即使您想上传100M-1000M的文件也没有关系。

更多阅读材料,请参阅http://developer.android.com/training/displaying-bitmaps/load-bitmap.html


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接