如何在 Android 中编辑和保存大位图?目前将其写成瓷砖,但将它们重新组合在一起很慢

Aar*_*545 2 android bitmap renderscript

我在 Android 上使用 renderscript 来编辑照片,目前由于 Android 上的纹理大小限制和内存限制,如果我尝试任何太大的东西,例如使用设备相机拍摄的照片,应用程序将崩溃。

我解决这个问题的第一个想法是使用 BitmapRegionDecoder 并将大照片平铺成可管理的部分,通过渲染脚本编辑它们并一次保存一个,然后使用 PNGJ 将它们拼接在一起 - 一个允许编写 PNG 的 PNG 解码和编码库图像分部分存入磁盘,因此我的内存中没有完整图像。

这工作正常,但将其拼接在一起需要相当长的时间 - 大约 1 分钟。

还有其他我应该考虑的解决方案吗?如果那里有解决方案,我可以更改为 JPEG,但我还没有找到。基本上我正在寻找 BitmapRegionDecoder 的另一面,一个 BitmapRegionEncoder。

为了清楚起见,我不想调整图像大小。

Mil*_*myk 6

  1. 使用 加载水平条纹图像BitmapRegionDecoder。下面的代码假设它是 PNG 并使用 PNGJ 将元数据复制到新图像,但添加对 JPEG 的支持应该不会太困难。
  2. 使用 Renderscript 处理每个条纹。
  3. 使用 PNGJ 保存它。不要使用高压缩率,否则它会减慢速度。

此图像的PNG 版本(4850x3635px) 在 Nexus 5 上需要 12 秒,并使用简单的 RS 过滤器(去饱和)。

void processPng(String forig,String fdest) {
    try {
        Allocation inAllocation = null;
        Allocation outAllocation = null;
        final int block_height = 64;

        FileInputStream orig = new FileInputStream(forig);
        FileInputStream orig2 = new FileInputStream(forig);
        FileOutputStream dest = new FileOutputStream(fdest);

        BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(orig, false);
        Rect blockRect = new Rect();

        PngReader pngr = new PngReader(orig2);
        PngWriter pngw = new PngWriter(dest, pngr.imgInfo);
        pngw.copyChunksFrom(pngr.getChunksList());

        // keep compression quick
        pngw.getPixelsWriter().setDeflaterCompLevel(1);

        int channels = 3; // needles to say, this should not be hardcoded
        int width = pngr.imgInfo.samplesPerRow / channels;
        int height = pngr.imgInfo.rows;

        pngr.close(); // don't need it anymore

        blockRect.left = 0;
        blockRect.right = width;

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
        Bitmap blockBitmap;
        byte []bytes = new byte[width * block_height * 4];
        byte []byteline = new byte[width * channels];

        for (int row = 0; row <= height / block_height; row++) {
            int h;

            // are we nearing the end?
            if((row + 1) *  block_height <= height)
                h = block_height;
            else {
                h = height - row * block_height;

                // so that new, smaller Allocations are created
                inAllocation = outAllocation = null;
            }

            blockRect.top = row * block_height;
            blockRect.bottom = row * block_height + h;

            blockBitmap = decoder.decodeRegion(blockRect, options);

            if(inAllocation == null)
                inAllocation = Allocation.createFromBitmap(mRS, blockBitmap);

            if(outAllocation == null)
            {
                Type.Builder TypeDir = new Type.Builder(mRS, Element.U8_4(mRS));
                TypeDir.setX(width).setY(h);

                outAllocation = Allocation.createTyped(mRS, TypeDir.create());
            }

            inAllocation.copyFrom(blockBitmap);
            mScript.forEach_saturation(inAllocation, outAllocation);
            outAllocation.copyTo(bytes);

            int idx = 0;

            for(int raster = 0; raster < h; raster++) {
                for(int m = 0; m < width; m++)
                {
                    byteline[m * channels] = bytes[idx++];
                    byteline[m * channels + 1] = bytes[idx++];
                    byteline[m * channels + 2] = bytes[idx++];
                    idx++;
                }

                ImageLineByte line = new ImageLineByte(pngr.imgInfo, byteline);
                pngw.writeRow(line);
            }
        }
        pngw.end();
    } catch (IOException e)
    {
        Log.d("BIG", "File io problem");
    }
}
Run Code Online (Sandbox Code Playgroud)