Android:将大型位图文件调整为缩放输出文件

我在一个文件中有一个很大的位图(比如3888x2592)。 现在,我想将该位图调整为800x533并将其保存到另一个文件。 我通常会调用Bitmap.createBitmap方法来缩放位图,但它需要一个源位图作为第一个参数,这是我无法提供的,因为将原始图像加载到Bitmap对象当然会超出内存(例如,请参阅此处)。

我也无法读取位图,例如BitmapFactory.decodeFile(file, options) ,提供一个BitmapFactory.Options.inSampleSize ,因为我想调整它的大小和宽度。 使用inSampleSize会将位图的大小调整为972x648(如果我使用inSampleSize=4 )或778x518(如果我使用inSampleSize=5 ,甚至不是2的幂)。

我还想避免在第一步中使用inSampleSize(例如972x648)读取图像,然后在第二步中将其大小改为800x533,因为与直接调整原始图像大小相比,质量会差一些。

总结我的问题:是否有一种方法可以读取大于10MP的大图像文件并将其保存到新的图像文件中,并调整为特定的新宽度和高度,而不会出现OutOfMemory异常?

我也尝试了BitmapFactory.decodeFile(file, options) ,并将Options.outHeight和Options.outWidth值手动设置为800和533,但这种方式并不奏效。


不,我喜欢有人纠正我,但我接受了您尝试的加载/调整方法作为妥协。

以下是任何人浏览的步骤:

  • 计算仍然会产生大于目标图像的inSampleSize的最大可能inSampleSize
  • 使用BitmapFactory.decodeFile(file, options)加载图像,并传入inSampleSize作为选项。
  • 使用Bitmap.createScaledBitmap()调整到所需的尺寸。

  • 贾斯汀回答翻译成代码(完美的作品):

    private Bitmap getBitmap(String path) {
    
    Uri uri = getImageUri(path);
    InputStream in = null;
    try {
        final int IMAGE_MAX_SIZE = 1200000; // 1.2MP
        in = mContentResolver.openInputStream(uri);
    
        // Decode image size
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(in, null, options);
        in.close();
    
    
    
        int scale = 1;
        while ((options.outWidth * options.outHeight) * (1 / Math.pow(scale, 2)) > 
              IMAGE_MAX_SIZE) {
           scale++;
        }
        Log.d(TAG, "scale = " + scale + ", orig-width: " + options.outWidth + ", 
           orig-height: " + options.outHeight);
    
        Bitmap resultBitmap = null;
        in = mContentResolver.openInputStream(uri);
        if (scale > 1) {
            scale--;
            // scale to max possible inSampleSize that still yields an image
            // larger than target
            options = new BitmapFactory.Options();
            options.inSampleSize = scale;
            resultBitmap = BitmapFactory.decodeStream(in, null, options);
    
            // resize to desired dimensions
            int height = resultBitmap.getHeight();
            int width = resultBitmap.getWidth();
            Log.d(TAG, "1th scale operation dimenions - width: " + width + ",
               height: " + height);
    
            double y = Math.sqrt(IMAGE_MAX_SIZE
                    / (((double) width) / height));
            double x = (y / height) * width;
    
            Bitmap scaledBitmap = Bitmap.createScaledBitmap(resultBitmap, (int) x, 
               (int) y, true);
            resultBitmap.recycle();
            resultBitmap = scaledBitmap;
    
            System.gc();
        } else {
            resultBitmap = BitmapFactory.decodeStream(in);
        }
        in.close();
    
        Log.d(TAG, "bitmap size - width: " +resultBitmap.getWidth() + ", height: " + 
           resultBitmap.getHeight());
        return resultBitmap;
    } catch (IOException e) {
        Log.e(TAG, e.getMessage(),e);
        return null;
    }
    

    这是'Mojo Risin'和'Ofir的解决方案'相结合“。 这会给你一个比例调整大小的图像,其边界为最大宽度和最大高度。

  • 它只读取元数据以获取原始大小(options.inJustDecodeBounds)
  • 它使用一个可调整大小来节省内存(itmap.createScaledBitmap)
  • 它使用基于前面创建的粗糙Bitamp的精确调整大小的图像。
  • 对我而言,它在下面的5百万像素图像上表现良好。

    try
    {
        int inWidth = 0;
        int inHeight = 0;
    
        InputStream in = new FileInputStream(pathOfInputImage);
    
        // decode image size (decode metadata only, not the whole image)
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(in, null, options);
        in.close();
        in = null;
    
        // save width and height
        inWidth = options.outWidth;
        inHeight = options.outHeight;
    
        // decode full image pre-resized
        in = new FileInputStream(pathOfInputImage);
        options = new BitmapFactory.Options();
        // calc rought re-size (this is no exact resize)
        options.inSampleSize = Math.max(inWidth/dstWidth, inHeight/dstHeight);
        // decode full image
        Bitmap roughBitmap = BitmapFactory.decodeStream(in, null, options);
    
        // calc exact destination size
        Matrix m = new Matrix();
        RectF inRect = new RectF(0, 0, roughBitmap.getWidth(), roughBitmap.getHeight());
        RectF outRect = new RectF(0, 0, dstWidth, dstHeight);
        m.setRectToRect(inRect, outRect, Matrix.ScaleToFit.CENTER);
        float[] values = new float[9];
        m.getValues(values);
    
        // resize bitmap
        Bitmap resizedBitmap = Bitmap.createScaledBitmap(roughBitmap, (int) (roughBitmap.getWidth() * values[0]), (int) (roughBitmap.getHeight() * values[4]), true);
    
        // save image
        try
        {
            FileOutputStream out = new FileOutputStream(pathOfOutputImage);
            resizedBitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
        }
        catch (Exception e)
        {
            Log.e("Image", e.getMessage(), e);
        }
    }
    catch (IOException e)
    {
        Log.e("Image", e.getMessage(), e);
    }
    
    链接地址: http://www.djcxy.com/p/93071.html

    上一篇: Android: Resize a large bitmap file to scaled output file

    下一篇: Monkey test fails due to createBitmap reports OOM