我正在使用以下代码通过Accelerate / vImage调整图像大小。它适用于大多数图像。但是,当调整大小的操作发生在以灰度格式编码的相当小的(441字节,80px x 48px)JPEG图像上时,vImageScale_ARGB8888
方法将抛出EXC_BAD_ACCESS
。
它必须处理为目标数据分配多少空间。为了计算目标缓冲区所需的容量,我们需要采取以下措施:
destination_image_height * destination_image_width * bytes_per_pixel
用于:
UnsafeMutablePointer<UInt8>.allocate(capacity: destHeight * destBytesPerRow)
其中destBytesPerRow
是destWidth * bytesPerPixel
我尝试处理一个以灰度格式编码的JPEG文件,并将其大小调整为40px x 24px。灰度图像具有每个像素恰好一个字节。因此,我们在公式中有24 x 40 * 1
来计算所需的容量。 EXC_BAD_ACCESS
失败了。
但是,当我增加所需的容量并将4
设置为bytesPerPixel
时(与常规RGB(A)图像一样),代码运行得很好(24 * 40 * 4
)>
我正试图了解这种奇怪行为的原因。为什么高估所需容量可以解决问题?
如果有帮助,malloc_error_break
报告以下内容:
libsystem_malloc.dylib`malloc_error_break:
-> 0x7fff694070de <+0>: pushq %rbp
0x7fff694070df <+1>: movq %rsp, %rbp
0x7fff694070e2 <+4>: nop
0x7fff694070e3 <+5>: nopl (%rax)
0x7fff694070e7 <+9>: popq %rbp
0x7fff694070e8 <+10>: retq
这是我的完整代码:
// Define format
var format = vImage_CGImageFormat(
bitsPerComponent: 8,
bitsPerPixel: 32,
colorSpace: nil,
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.first.rawValue),
version: 0,
decode: nil,
renderingIntent: CGColorRenderingIntent.defaultIntent
)
// Create empty input vImage buffer
var srcBuffer = vImage_Buffer()
// Fill the input buffer with inputImage pixel data
var error = vImageBuffer_InitWithCGImage(&srcBuffer, &format, nil, inputImage, vImage_Flags(kvImageNoFlags))
guard error == kvImageNoError else {
free(srcBuffer.data)
return nil
}
let destWidth = Int(width)
let destHeight = Int(height)
// ----
let bytesPerPixel = inputImage.bitsPerPixel / 8 //this does not work
//let bytesPerPixel = 4 //this works just fine
// ----
let destBytesPerRow = destWidth * bytesPerPixel
// Fill the input buffer with inputImage pixel data
let destData = UnsafeMutablePointer<UInt8>.allocate(capacity: destHeight * destBytesPerRow)
defer {
destData.deinitialize(count: destHeight * destBytesPerRow)
destData.deallocate()
}
var destBuffer = vImage_Buffer(
data: destData,
height: vImagePixelCount(destHeight),
width: vImagePixelCount(destWidth),
rowBytes: destBytesPerRow
)
// Perform the actual resize
error = vImageScale_ARGB8888(&srcBuffer, &destBuffer, nil, vImage_Flags(kvImageHighQualityResampling))
guard error == kvImageNoError else {
return nil
}
// Convert vImage output buffer back into CGImage
let result = vImageCreateCGImageFromBuffer(
&destBuffer,
&format,
nil,
nil,
vImage_Flags(kvImageNoFlags),
&error
)?.takeRetainedValue()
guard error == kvImageNoError else {
return nil
}
return result