【问题标题】:Core Image ciContext.writeHEIFRepresentation() generates images with diagonal lines when using CICrop filter. How can I prevent this?Core Image ciContext.writeHEIFRepresentation() 在使用 CICrop 过滤器时生成带有对角线的图像。我怎样才能防止这种情况?
【发布时间】:2021-09-08 11:08:12
【问题描述】:

我正在尝试生成 HEIF 输出文件,但这样做时会得到奇怪的对角线。其他输出格式都没有出现这些奇怪的线条。见下图。问题似乎正在裁剪,但错误仅显示在 HEIF 输出文件中。

我可以使用以下操场代码复制此代码,您可以从这里下载 https://duncangroenewald.com/files/SampleApps/CoreImageHEIFExporterBug-2.zip

我有一份 Apple 的错误报告,他们提到了“亚像素错误”——我不知道那是什么,或者为什么这些只会在 heif 输出格式中体现出来,或者如何防止它们——任何想法或这样做只是看起来像是 Apple 代码中的错误?

编辑。需要明确的是,这不是操场问题,因为问题发生在 macOS 应用程序中。

我怀疑在生成 HEIF 输出时这一定是 CIContext 错误,因为它仅在 heif 输出文件中出现。但是,我对亚像素错误或 Apple 认为它们应该与此问题相关的原因一无所知。也许有更多Core Image知识的人可以提出一些可能的解决方案。

import Cocoa

let files = ["/Users/duncangroenewald/Development/Playgrounds/CoreImageHEIFExporterBug/DSC02022.ARW",
     "/Users/duncangroenewald/Development/Playgrounds/CoreImageHEIFExporterBug/DSC02018.ARW"
]

let destFilePath = "/Users/duncangroenewald/Development/Playgrounds/CoreImageHEIFExporterBug"

let destUrl = URL(fileURLWithPath: destFilePath)

let exporter = Exporter()

var crops = [CGRect(x: 0, y: 0, width: 5310, height: 3212),
             CGRect(x: 0, y: 0, width: 5311, height: 3212),
             CGRect(x: 0, y: 0, width: 5312, height: 3212),
             CGRect(x: 0, y: 0, width: 5313, height: 3212)]


for file in files {
    exporter.processRAWFile(file, destPath: destFilePath, crops: crops)
}

print("Done!")

import AppKit
import CoreImage
import CoreImage.CIFilterBuiltins
import OSLog

public class Exporter {
    
    var formats: [String] = ["heif", "png"]
    
    // Get the CIContext
    let ciContext = CIContext()
    
    var imageOrientation: Int = 0
    var imageNativeSize: CGSize = .zero

    var crops: [CGRect] = [.zero]

    public init() {
        
    }
    
    public func processRAWFile(_ path: String, destPath: String, crops: [CGRect]) {
        
        print("processRAWFile XXX")
        self.crops = crops
        
        let url = URL(fileURLWithPath: path)
        
        let filename = url.deletingPathExtension().lastPathComponent
        
        let destDirUrl = URL(fileURLWithPath: destPath)
        print("destDirUrl: \(destDirUrl)")
        
        for crop in crops {
        
            let cropName = "\(filename)_\(crop.width)x\(crop.height)_\(useDefaultRAW ? "default" : "")"
        
            for format in formats {
            let destUrl = destDirUrl.appendingPathComponent(cropName).appendingPathExtension(format)
            print("destFile: \(destUrl)")
        
                self.exportFile(url: url, destUrl: destUrl, crop: crop, format: format)
                
            }
          
        }
    }
    
    func exportFile(url: URL, destUrl: URL, crop: CGRect, format: String){
        print("exportFile \(url)")
        print("destFile: \(destUrl)")
        
        guard let rawFilter = CIFilter(imageURL: url, options: nil), let outputImage = rawFilter.outputImage else {
            print("Failed to load \(url.lastPathComponent) for exporting")
            return
        }
        
        let processImage = self.crop(outputImage, rect: crop)
        
        
        let options = [kCGImageDestinationLossyCompressionQuality as CIImageRepresentationOption: 1.0 as CGFloat]
        let colorSpace = CGColorSpace(name: CGColorSpace.sRGB)!
        let imgFormat = CIFormat.RGBA16
        
        do {
            
            switch format {
            case "tiff":
                try ciContext.writeTIFFRepresentation(of: processImage, to: destUrl, format: imgFormat, colorSpace: colorSpace, options: options)
            case "jpeg":
                try ciContext.writeJPEGRepresentation(of: processImage, to: destUrl, colorSpace: colorSpace, options: options)
            case "png":
                try ciContext.writePNGRepresentation(of: processImage, to: destUrl, format: imgFormat, colorSpace: colorSpace, options: options)
            case "heif":
                try ciContext.writeHEIFRepresentation(of: processImage, to: destUrl, format: imgFormat, colorSpace: colorSpace, options: options)
            default:
                try ciContext.writePNGRepresentation(of: processImage, to: destUrl, format: imgFormat, colorSpace: colorSpace, options: options)
            }
            
        } catch {
            print("Error exporting \(format): \(error.localizedDescription)")
        }
        
    }
    var useDefaultRAW: Bool = true

    func crop(_ ciImage: CIImage, rect: CGRect)->CIImage {
        if let cropped = self.cropFilter(ciImage, rect: rect) {
            return cropped
        } else {
            print("Error cropping image !")
            return ciImage
        }
    }
  
    
    func cropFilter(_ input: CIImage, rect: CGRect) -> CIImage? {
        
        
        // Getting a dashed border !!
        guard let cropFilter = CIFilter(name: "CICrop") else {
            print("Error no CICrop filter found !")
            return input
        }
        let ciVect = CIVector(cgRect: rect)
        cropFilter.setValue(input, forKey: kCIInputImageKey)

        cropFilter.setValue(ciVect, forKey: "inputRectangle")

        return cropFilter.value(forKey: kCIOutputImageKey) as? CIImage
        
    }
}

【问题讨论】:

  • 你的话题太宽泛了。我们不知道您报告的是 Playground 问题、Core Image 问题还是 HEIF 问题。
  • 这不是操场问题,因为这发生在 macOS 应用程序中。 Playground 只是用来重现问题。不太确定这怎么可能是 HEIF 问题,因为这是格式规范。要么我使用的 API 不正确,要么是 Core Image 中的一个错误——我不清楚代码是否有问题,因为它适用于除 HEIF 输出格式之外的所有格式,但也许有一些我不知道的裁剪注意事项以确保避免亚像素错误。
  • 我对对角线有同样的问题,但仅在某些 ciFilters 输出的某些图像中。可能的内部平铺问题?将努力缩小显示线条的情况。
  • @WillLoew-Blosser - 看起来这是一个错误 - 尝试使用 Xcode 13 的 macOS12 测试版 - 似乎它仍然没有在 11.5 测试版中修复。

标签: swift macos cocoa core-image heif


【解决方案1】:

我能找到解决它的唯一方法是 先通过上下文渲染CGImage,然后从CGImage重新创建CIImage。

编辑

let context = CIContext()
let fileURL = <URL to save location>
let ciImage = <Here is the image you got as output of filter>
let options = [kCGImageDestinationLossyCompressionQuality as CIImageRepresentationOption: 1.0 as CGFloat]
let colorSpace = CGColorSpace(name: CGColorSpace.sRGB)!
let imgFormat = CIFormat.RGBA16

// First we create a CGImage
let cgImage = context.createCGImage(ciImage, 
                                    from: ciImage.extent,
                                    format: imgFormat,
                                    colorSpace: colorSpace)

// Then we use this CGImage to re-create CIImage and save it
try context.writeHEIFRepresentation(
                of: CIImage(cgImage: cgImage),
                to: fileURL,
                format: imgFormat,
                colorSpace: colorSpace,
                options: options
            )

【讨论】:

  • 能否与我们分享一些代码或示例?这将使您的答案更加完整和有用,谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
  • 2021-06-17
  • 2017-09-17
相关资源
最近更新 更多