如何在Android中编辑和保存大型位图?目前正在将其写为平铺,但将它们重新连接在一起的速度很慢
我正在使用Android上的renderscript编辑照片,目前由于Android上的纹理大小限制和内存限制,如果我尝试任何太大的东西,例如使用设备相机拍摄的照片,应用程序将崩溃 我的第一个想法是使用BitMapRegionCoder并将大照片平铺成可管理的部分,通过renderscript编辑它们并一次保存一个,然后使用PNGJ将它们缝合在一起—一个PNG解码和编码库,允许将PNG图像部分写入磁盘,这样我的内存中就不会有完整的图像 这很好,但缝合起来需要相当长的时间-大约1分钟左右的猜测 我还有什么其他的解决办法吗?如果有解决方案,我可以改成JPEG,但我还没有找到。基本上我在寻找BitMapRegionCoder的另一面,BitMapRegionCoder 只是为了清楚,我不想调整图像的大小如何在Android中编辑和保存大型位图?目前正在将其写为平铺,但将它们重新连接在一起的速度很慢,android,bitmap,renderscript,Android,Bitmap,Renderscript,我正在使用Android上的renderscript编辑照片,目前由于Android上的纹理大小限制和内存限制,如果我尝试任何太大的东西,例如使用设备相机拍摄的照片,应用程序将崩溃 我的第一个想法是使用BitMapRegionCoder并将大照片平铺成可管理的部分,通过renderscript编辑它们并一次保存一个,然后使用PNGJ将它们缝合在一起—一个PNG解码和编码库,允许将PNG图像部分写入磁盘,这样我的内存中就不会有完整的图像 这很好,但缝合起来需要相当长的时间-大约1分钟左右的猜测 我
BitMapRegionCoder
以水平条纹加载图像。下面的代码假设它是PNG,并使用PNGJ将元数据复制到新图像,但添加对JPEG的支持应该不会太困难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")
}
}