iOS 14 ARKit CapturedImage JPEG 转换 HEIC 警告

iOS 14 ARKit CapturedImage JPEG Conversion HEIC Warning

TL;DR:iOS14 中的 ARKit capturedImage 发生了一些变化,我们无法使其适应我们的流程。

Built with Xcode 12 GM, tested on iPhone 6S 14.0.

我们实施了一个流程,将 ARFrame 转换为 Data,这非常适合尚未升级到 iOS14 的设备。

我们得到了 ciImage 这样的:

extension ARFrame {
    var ciImage: CIImage { CIImage(cvPixelBuffer: capturedImage) }
}

我们输入 ImageConverter:

public class ImageConverter {
    lazy var imageContext = CIContext(mtlDevice: MTLCreateSystemDefaultDevice()!)
    lazy var colorSpace = CGColorSpace(name: CGColorSpace.sRGB)

    public func jpgData(for image: CIImage) -> Data {
        guard let colorSpace = colorSpace else { return Data() }

        if let jpegRepresentation = imageContext.jpegRepresentation(of: image,
                                                                    colorSpace: image.colorSpace ?? colorSpace) {
            return jpegRepresentation
        } else {
            return Data()
        }
    }
}

所以,问题是,当我们调用.jpegRepresentation时,它给出了一个警告:

findWriterForType:128: unsupported file format 'public.heic'

虽然 jpegRepresentation 不是零,但它不适用于我们的服务器,它需要一个 jpeg 数据(它仍然适用于 iOS13.7 或以下设备)。

到目前为止我们尝试了什么:

if let heifRepresentation = imageContext.heifRepresentation(of: image,
                                                            format: .RGBA8,
                                                            colorSpace: image.colorSpace ?? colorSpace) {
    return heifRepresentation
}

returns nil,并抛出与 .jpegRepresentation 相同的错误。也试过其他格式,无果。

问题出在用.jpegRepresentation创建的JPEG数据格式。

这是 iPhone XS - iOS13 与 iPhone 6S - iOS14 之间的区别:

终端输出:

➜ file testiOS13.jpeg

testiOS13.jpeg: JPEG image data, JFIF standard 1.01, aspect ratio, density 72x72, segment length 16, Exif Standard: [TIFF image data, big-endian, direntries=1], baseline, precision 8, 600x800, components 3

➜ file testiOS14.jpeg

testiOS14.jpeg: JPEG image data, Exif standard: [TIFF image data, big-endian, direntries=5, xresolution=74, yresolution=82, resolutionunit=2], baseline, precision 8, 412x733, components 3

iOS 14 张 ARKit 图片缺少 JFIF 标准 1.01。

CGImageData 之间有一个环(以及可用性检查以防 iOS 13.7 或更低版本出现问题):

public func jpgData(for image: CIImage, with size: CGSize) -> Data {
    guard #available(iOS 14.0, *) else { return jpgData(for: image) }

    guard let cgImage = imageContext.createCGImage(image, from: CGRect(origin: .zero, size: size)) else { return jpgData(for: image) }

    let data = NSMutableData()

    guard let imageDestination = CGImageDestinationCreateWithData(data, AVFileType.jpg as CFString, 1, nil) else { return jpgData(for: image) }
    CGImageDestinationAddImage(imageDestination, cgImage, nil)

    guard CGImageDestinationFinalize(imageDestination) else { return jpgData(for: image) }

    return data as Data
}

private func jpgData(for image: CIImage) -> Data {
    guard let colorSpace = colorSpace else { return Data() }

    return imageContext.jpegRepresentation(of: image, colorSpace: colorSpace) ?? Data()
}

最新变化:

终端输出:

➜ file testiOS14_New.jpeg

testiOS14_New.jpeg: JPEG image data, JFIF standard 1.01, aspect ratio, density 72x72, segment length 16, Exif Standard: [TIFF image data, big-endian, direntries=1], baseline, precision 8, 413x734, components 3

我也注意到了一些奇怪的地方,执行几乎相同的流程,但将 ARFrame 保存为 heic 文件: 在 iOS 14 上,它在某些内部方法中完全崩溃,并使 heifRepresentation 变得无用。

下面是处理转换的代码片段:

        guard let ciImage = CIImage(image: self),
        let colorSpace = ciImage.colorSpace else {
        throw HEICError.heicNotSupported
    }
    
    let ciContext = CIContext()

    do {
        try ciContext.writeHEIFRepresentation(of: ciImage, to: urlFilePath, format: ciContext.workingFormat, colorSpace: colorSpace, options: [kCGImageDestinationLossyCompressionQuality as CIImageRepresentationOption: 1.0])
    } catch {
        print("Error is \(error.localizedDescription)")
        throw HEICError.saveFail
    }

提醒一下,这在 iOS14 之前是完美的。我已经尝试了很多编写 heic 文件的方法,但我遇到了致命的崩溃:

vExtractChannel_ARGB8888 BAD_EXEC

这里肯定有猫腻。

有什么事情会更新