Android:旋转图像而不将其加载到内存中

end*_*yha 23 android

我想知道是否可以旋转存储在SD卡上的图像而不将其加载到内存中.

原因是我正在寻找着名的OutOfMemoryError.我知道我可以通过下采样大图像来避免它,但事实上我不想减小该图像的大小,我想要原始图像但旋转90度.

任何有关这方面的建议都热烈赞赏:)

riw*_*nyk 26

在此输入图像描述

对于90度旋转,我真的采用RenderScript,它专门用于处理位图,并且出乎意料地甚至比默认值更快Bitmap.createBitmap().进程内位图不存储在Java堆上,因此不会将您推入OutOfMemoryError.

在项目中使用几行设置RenderScript支持后,以下是要使用的RenderScript算法:

1)app\src\main\rs\rotator.rs使用以下内容创建RenderScript文件.

#pragma version(1)
#pragma rs java_package_name(ua.kulku.rs)

rs_allocation inImage;
int inWidth;
int inHeight;

uchar4 __attribute__ ((kernel)) rotate_90_clockwise (uchar4 in, uint32_t x, uint32_t y) {
    uint32_t inX  = inWidth - 1 - y;
    uint32_t inY = x;
    const uchar4 *out = rsGetElementAt(inImage, inX, inY);
    return *out;
}

uchar4 __attribute__ ((kernel)) rotate_270_clockwise (uchar4 in, uint32_t x, uint32_t y) {
    uint32_t inX = y;
    uint32_t inY = inHeight - 1 - x;

    const uchar4 *out = rsGetElementAt(inImage, inX, inY);
    return *out;
}
Run Code Online (Sandbox Code Playgroud)

注意ua.kulku.rs,这是您为自动生成RS Java接口选择的一些包名称.

2)在Java代码中引用它:

import ua.kulku.rs.ScriptC_rotator;

    public Bitmap rotate(Bitmap bitmap) {
        RenderScript rs = RenderScript.create(mContext);
        ScriptC_rotator script = new ScriptC_rotator(rs);
        script.set_inWidth(bitmap.getWidth());
        script.set_inHeight(bitmap.getHeight());
        Allocation sourceAllocation = Allocation.createFromBitmap(rs, bitmap,
                Allocation.MipmapControl.MIPMAP_NONE,
                Allocation.USAGE_SCRIPT);
        bitmap.recycle();
        script.set_inImage(sourceAllocation);

        int targetHeight = bitmap.getWidth();
        int targetWidth = bitmap.getHeight();
        Bitmap.Config config = bitmap.getConfig();
        Bitmap target = Bitmap.createBitmap(targetWidth, targetHeight, config);
        final Allocation targetAllocation = Allocation.createFromBitmap(rs, target,
                Allocation.MipmapControl.MIPMAP_NONE,
                Allocation.USAGE_SCRIPT);
        script.forEach_rotate_90_clockwise(targetAllocation, targetAllocation);
        targetAllocation.copyTo(target);
        rs.destroy();
        return target;
    }
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

对于180度旋转,NDK解决方案优于RenderScript,因为我使用顺序数组项访问,因为180度旋转实际上是图像像素阵列的反转.我在这些比较中使用的NDK算法来自 https://github.com/AndroidDeveloperLB/AndroidJniBitmapOperations.进程中的位图也不会存储在Java堆上,从而阻止了OutOfMemoryError.

统计条表示我在三星S4(Android 5.0)上拍摄的13 MP照片的毫秒数.


Col*_*ire 5

你应该使用解码解码图像Bitmap.你应该按照谷歌提供的加载大图像的方式来做这件事..它帮助了我很多,你会注意到RAM使用量的巨大差异..

更新如果您想要的只是旋转图像,您可以使用此代码

Matrix matrix = new Matrix();
matrix.setRotate(90);
result = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),bitmap.getHeight(), matrix, false);
Run Code Online (Sandbox Code Playgroud)

如果您只需要设置图像方向(例如拍摄时的照片方向),您可以使用

ExifInterface exif = new ExifInterface(filePath);
Run Code Online (Sandbox Code Playgroud)

ExifInterface.TAG_ORIENTATION 我希望这个属性可以帮到你

  • 这个答案是不正确的.如你所说旋转,你需要将两个巨大的位图加载到内存中.OP希望避免这种情况,我不知道为什么他将此标记为答案. (10认同)
  • @AA将矩阵应用于内存中的位图并不会有帮助,因为整个问题是位图可能太大而无法合理地加载到内存中. (7认同)
  • 是的,我知道这个技术,但如果我在内存中加载调整大小的位图,旋转,然后将其保存在磁盘上,将有这个下采样的图像,但我想有原始大小的图像,但旋转(没有质量或大小的损失) (5认同)