如何在Android中编辑和保存大型位图?目前正在将其写为平铺,但将它们重新连接在一起的速度很慢

如何在Android中编辑和保存大型位图?目前正在将其写为平铺,但将它们重新连接在一起的速度很慢,android,bitmap,renderscript,Android,Bitmap,Renderscript,我正在使用Android上的renderscript编辑照片,目前由于Android上的纹理大小限制和内存限制,如果我尝试任何太大的东西,例如使用设备相机拍摄的照片,应用程序将崩溃 我的第一个想法是使用BitMapRegionCoder并将大照片平铺成可管理的部分,通过renderscript编辑它们并一次保存一个,然后使用PNGJ将它们缝合在一起—一个PNG解码和编码库,允许将PNG图像部分写入磁盘,这样我的内存中就不会有完整的图像 这很好,但缝合起来需要相当长的时间-大约1分钟左右的猜测 我

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

我的第一个想法是使用BitMapRegionCoder并将大照片平铺成可管理的部分,通过renderscript编辑它们并一次保存一个,然后使用PNGJ将它们缝合在一起—一个PNG解码和编码库,允许将PNG图像部分写入磁盘,这样我的内存中就不会有完整的图像

这很好,但缝合起来需要相当长的时间-大约1分钟左右的猜测

我还有什么其他的解决办法吗?如果有解决方案,我可以改成JPEG,但我还没有找到。基本上我在寻找BitMapRegionCoder的另一面,BitMapRegionCoder

只是为了清楚,我不想调整图像的大小

  • 使用
    BitMapRegionCoder
    以水平条纹加载图像。下面的代码假设它是PNG,并使用PNGJ将元数据复制到新图像,但添加对JPEG的支持应该不会太困难
  • 使用Renderscript处理每个条带
  • 使用PNGJ保存它。不要使用高压缩,否则会减慢到爬行速度
  • PNG版本的(4850x3635px)在Nexus5上需要12秒,只需一个简单的RS过滤器(去饱和)

    void processPng(字符串forig,字符串fdest){
    试一试{
    分配位置=空;
    分配超出分配=空;
    最终整块高度=64;
    FileInputStream orig=新的FileInputStream(forig);
    FileInputStream orig2=新的FileInputStream(forig);
    FileOutputStream dest=新的FileOutputStream(fdest);
    BitMapRegionCoder解码器=BitMapRegionCoder.newInstance(orig,false);
    Rect blockRect=new Rect();
    PngReader pngr=新PngReader(orig2);
    PngWriter pngw=新PngWriter(目的地,pngr.imgInfo);
    pngw.copyChunksFrom(pngr.getChunksList());
    //保持快速压缩
    pngw.getPixelsWriter().setDeflaterCompLevel(1);
    int channels=3;//也就是说,不应该硬编码
    int width=pngr.imgInfo.samplesPerRow/channels;
    int height=pngr.imgInfo.rows;
    pngr.close();//不再需要它了
    blockRect.left=0;
    blockRect.right=宽度;
    BitmapFactory.Options=new-BitmapFactory.Options();
    options.inPreferredConfig=Bitmap.Config.ARGB_8888;
    位图块位图;
    字节[]字节=新字节[宽度*块高度*4];
    byte[]byteline=新字节[宽度*通道];
    
    对于基于@MiloslawSmyk answer的(int row=0;row),这是加载大型JPEG并用PNGJ保存的版本:

    fun processPng(forig: String, fdest: String) {
        try {
            val blockHeight = 64
    
            val orig = FileInputStream(forig)
            val dest = FileOutputStream(fdest)
    
            val decoder = BitmapRegionDecoder.newInstance(orig, false)
            val blockRect = Rect()
    
            val channels = 3 // needles to say, this should not be hardcoded
            val sizeOptions = BitmapFactory.Options().apply {
                inJustDecodeBounds = true
            }
            BitmapFactory.decodeFile(forig, sizeOptions)
            val height: Int = sizeOptions.outHeight
            val width: Int = sizeOptions.outWidth
    
            val pngw = PngWriter(dest, ImageInfo(width, height, 8, false))
    
            // keep compression quick
            pngw.pixelsWriter.deflaterCompLevel = 1
    
            blockRect.left = 0
            blockRect.right = width
    
            val options = BitmapFactory.Options().apply {
                inPreferredConfig = Bitmap.Config.ARGB_8888
            }
            var blockBitmap: Bitmap
            val byteLine = ByteArray(width * channels)
    
            for (row in 0..height / blockHeight) {
                // are we nearing the end?
                val h: Int = if ((row + 1) * blockHeight <= height)
                                blockHeight
                            else {
                                height - row * blockHeight
                            }
    
                blockRect.top = row * blockHeight
                blockRect.bottom = row * blockHeight + h
    
                blockBitmap = decoder.decodeRegion(blockRect, options)
    
                // convert bitmap into byte array
                val size = blockBitmap.rowBytes * blockBitmap.height
                val byteBuffer = ByteBuffer.allocate(size)
                blockBitmap.copyPixelsToBuffer(byteBuffer)
                val bytes = byteBuffer.array()
    
                var idx = 0
    
                for (raster in 0 until h) {
                    for (m in 0 until width) {
                        byteLine[m * channels] = bytes[idx++]
                        byteLine[m * channels + 1] = bytes[idx++]
                        byteLine[m * channels + 2] = bytes[idx++]
                        idx++
                    }
    
                    val line = ImageLineByte(pngw.imgInfo, byteLine)
                    pngw.writeRow(line)
                }
            }
            pngw.end()
    
        } catch (e: IOException) {
            Log.d("BIG", "File io problem")
        }
    
    }
    
    fun-processPng(forig:String,fdest:String){
    试一试{
    val blockHeight=64
    val orig=FileInputStream(forig)
    val dest=FileOutputStream(fdest)
    val decoder=BitMapRegionCoder.newInstance(orig,false)
    val blockRect=Rect()
    val channels=3//也就是说,不应硬编码
    val sizeOptions=BitmapFactory.Options().apply{
    inJustDecodeBounds=true
    }
    BitmapFactory.decodeFile(forig,sizeOptions)
    val高度:Int=sizeOptions.outHeight
    val宽度:Int=sizeOptions.outWidth
    val pngw=PngWriter(dest,ImageInfo(宽度,高度,8,假))
    //保持快速压缩
    pngw.pixelsWriter.deflaterCompLevel=1
    blockRect.left=0
    blockRect.right=宽度
    val options=BitmapFactory.options().apply{
    inPreferredConfig=Bitmap.Config.ARGB_8888
    }
    var块位图:位图
    val byteLine=ByteArray(宽度*通道)
    用于(0中的行高度/块高度){
    //我们快结束了吗?
    
    val h:Int=if((行+1)*blockHeight@Ata请阅读此问题,因为您提到的库中没有一个可以帮助我。我了解的是,您需要某种转换器,并将加载/保存留给库。转换器允许您随心所欲地更改图像。试试这个。您看过AOSP Gallery2应用程序了吗?@MorrisonChang谢谢,我会查看它。我正在研究使用JNI。如果您首先保存然后缝合,您正在执行压缩和解压缩两次,再加上不必要的磁盘访问。难道您不能一次处理/保存好几行吗?更改压缩级别和删除PNGJ中的alpha对我当前代码中的写入时间和由此产生的fi有很大的不同le并没有太大。我将使用您的方法对其进行进一步优化,每次64行,并按原样将每个行写入PNG,以防止不必要的磁盘访问和编码。感谢将图像以JPEG格式保存在区域/行中的任何解决方案?
    fun processPng(forig: String, fdest: String) {
        try {
            val blockHeight = 64
    
            val orig = FileInputStream(forig)
            val dest = FileOutputStream(fdest)
    
            val decoder = BitmapRegionDecoder.newInstance(orig, false)
            val blockRect = Rect()
    
            val channels = 3 // needles to say, this should not be hardcoded
            val sizeOptions = BitmapFactory.Options().apply {
                inJustDecodeBounds = true
            }
            BitmapFactory.decodeFile(forig, sizeOptions)
            val height: Int = sizeOptions.outHeight
            val width: Int = sizeOptions.outWidth
    
            val pngw = PngWriter(dest, ImageInfo(width, height, 8, false))
    
            // keep compression quick
            pngw.pixelsWriter.deflaterCompLevel = 1
    
            blockRect.left = 0
            blockRect.right = width
    
            val options = BitmapFactory.Options().apply {
                inPreferredConfig = Bitmap.Config.ARGB_8888
            }
            var blockBitmap: Bitmap
            val byteLine = ByteArray(width * channels)
    
            for (row in 0..height / blockHeight) {
                // are we nearing the end?
                val h: Int = if ((row + 1) * blockHeight <= height)
                                blockHeight
                            else {
                                height - row * blockHeight
                            }
    
                blockRect.top = row * blockHeight
                blockRect.bottom = row * blockHeight + h
    
                blockBitmap = decoder.decodeRegion(blockRect, options)
    
                // convert bitmap into byte array
                val size = blockBitmap.rowBytes * blockBitmap.height
                val byteBuffer = ByteBuffer.allocate(size)
                blockBitmap.copyPixelsToBuffer(byteBuffer)
                val bytes = byteBuffer.array()
    
                var idx = 0
    
                for (raster in 0 until h) {
                    for (m in 0 until width) {
                        byteLine[m * channels] = bytes[idx++]
                        byteLine[m * channels + 1] = bytes[idx++]
                        byteLine[m * channels + 2] = bytes[idx++]
                        idx++
                    }
    
                    val line = ImageLineByte(pngw.imgInfo, byteLine)
                    pngw.writeRow(line)
                }
            }
            pngw.end()
    
        } catch (e: IOException) {
            Log.d("BIG", "File io problem")
        }
    
    }