Giả sử dự án đã có hình ảnh mà người dùng đã chọn, bước tiếp theo là cho phép người dùng áp dụng các bộ lọc Hình ảnh cốt lõi khác nhau cho nó. Để bắt đầu, tôi sẽ chỉ làm việc với một bộ lọc duy nhất, nhưng tôi sẽ sớm mở rộng bộ lọc đó bằng hộp thoại xác nhận.
Nếu muốn sử dụng Core Image trong ứng dụng của mình, trước tiên cần thêm hai lần nhập vào đầu ContentView.swift:
import CoreImage
import CoreImage.CIFilterBuiltins
Tiếp theo chúng ta cần cả bối cảnh và bộ lọc. Bối cảnh Hình ảnh cốt lõi là một đối tượng chịu trách nhiệm hiển thị CIImage thành CGImage hoặc theo thuật ngữ thực tế hơn là một đối tượng để chuyển đổi công thức cho hình ảnh thành một chuỗi pixel thực tế mà chúng ta có thể làm việc.
Việc tạo bối cảnh rất phức tạp, vì vậy nếu bạn có ý định hiển thị nhiều hình ảnh thì bạn nên tạo bối cảnh một lần và duy trì nó. Đối với bộ lọc, chúng tôi sẽ sử dụng CIFilter.sepiaTone() làm mặc định nhưng vì sau này chúng tôi sẽ làm cho nó linh hoạt nên chúng tôi sẽ sử dụng bộ lọc @State để có thể thay đổi nó.
Vì vậy, hãy thêm hai thuộc tính này vào ContentView:
@State private var currentFilter = CIFilter.sepiaTone()
let context = CIContext()
Với hai thứ đó, giờ đây chúng ta có thể viết một phương thức sẽ xử lý bất kỳ hình ảnh nào được nhập - điều đó có nghĩa là nó sẽ đặt cường độ của bộ lọc màu nâu đỏ dựa trên giá trị trong , đọc lại hình ảnh đầu ra filterIntensity từ bộ lọc, yêu cầu chúng ta CIContext kết xuất nó, sau đó đặt kết quả vào image thuộc tính của chúng tôi để nó hiển thị trên màn hình.
func applyProcessing() {
currentFilter.intensity = Float(filterIntensity)
guard let outputImage = currentFilter.outputImage else { return }
if let cgimg = context.createCGImage(outputImage, from: outputImage.extent) {
let uiImage = UIImage(cgImage: cgimg)
image = Image(uiImage: uiImage)
}
}
Mẹo: Đáng buồn thay, Hình ảnh cốt lõi đằng sau bộ lọc tông màu nâu đỏ lại muốn Floatthay Double vì giá trị của nó. Tôi biết điều này khiến Core Image thậm chí còn cũ hơn nhưng đừng lo lắng – chúng tôi sẽ sớm loại bỏ nó!
Công việc tiếp theo là thay đổi cách loadImage() làm việc. Ngay bây giờ điều đó được gán cho image giá trị, nhưng chúng tôi không muốn điều đó nữa. Thay vào đó, nó sẽ gửi bất kỳ hình ảnh nào đã được chọn vào bộ lọc tông màu nâu đỏ, sau đó gọi applyProcessing() để biến điều kỳ diệu thành hiện thực.
Bộ lọc Hình ảnh cốt lõi có một inputImage thuộc tính chuyên dụng cho phép chúng tôi gửi một CIImage thuộc tính để bộ lọc hoạt động, nhưng điều này thường bị hỏng hoàn toàn và sẽ khiến ứng dụng của bạn gặp sự cố, vì vậy sẽ an toàn hơn nhiều khi sử dụng phương thức của bộ lọc setValue() với khóa kCIInputImageKey.
Vì vậy, hãy thay thế loadImage() phương pháp hiện tại của bạn bằng phương pháp này:
func loadImage() {
guard let inputImage = inputImage else { return }
let beginImage = CIImage(image: inputImage)
currentFilter.setValue(beginImage, forKey: kCIInputImageKey)
applyProcessing()
}
Nếu chạy mã ngay bây giờ, bạn sẽ thấy luồng ứng dụng cơ bản của chúng tôi hoạt động rất tốt: chúng tôi có thể chọn một hình ảnh, sau đó xem nó với hiệu ứng màu nâu đỏ được áp dụng. Nhưng thanh trượt cường độ mà chúng tôi đã thêm không làm được gì cả, mặc dù nó bị ràng buộc với cùng một filterIntensity giá trị mà bộ lọc của chúng tôi đang đọc.
Điều đang xảy ra ở đây không có gì đáng ngạc nhiên: mặc dù thanh trượt đang thay đổi giá trị của filterIntensity, việc thay đổi thuộc tính đó sẽ không tự động kích hoạt applyProcessing() lại phương thức của chúng ta. Thay vào đó, chúng ta cần thực hiện điều đó bằng tay bằng cách yêu cầu SwiftUI xem filterIntensity bằng onChange().
Một lần nữa, những công cụ sửa đổi này onChange() có thể đi đến bất kỳ đâu trong hệ thống phân cấp chế độ xem SwiftUI của chúng ta, nhưng trong tình huống này, tôi làm điều gì đó khác: khi một chế độ xem cụ thể chịu trách nhiệm thay đổi một giá trị, tôi thường thêm trực tiếp onChange() vào chế độ xem đó để sau này tôi hiểu rõ việc điều chỉnh chế độ xem đó gây ra tác dụng phụ. Nếu nhiều chế độ xem điều chỉnh cùng một giá trị hoặc nếu nó không quá cụ thể về điều gì đang thay đổi giá trị thì tôi sẽ thêm công cụ sửa đổi ở cuối chế độ xem.
Dù sao, ở đây filterIntensity đang được thay đổi bởi thanh trượt, vì vậy hãy thêm onChange() vào đó:
Slider(value: $filterIntensity)
.onChange(of: filterIntensity) { _ in
applyProcessing()
}
Bạn có thể tiếp tục và chạy ứng dụng ngay bây giờ nhưng hãy lưu ý: mặc dù Core Image cực kỳ nhanh trên tất cả iPhone nhưng nó thường cực kỳ chậm trong trình mô phỏng.
Nguồn: https://www.hackingwithswift.com/books/ios-swiftui/basic-image-filtering-using-core-image
Bình luận