使用缓冲区时,vImage会抛出EXC_BAD_ACCESS

时间:2019-03-30 11:10:09

标签: swift accelerate-framework vimage

我正在使用以下代码通过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)

其中destBytesPerRowdestWidth * 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

0 个答案:

没有答案