iOS - 创建核心图像过滤器循环时保留原始图像
iOS -Keep original image when creating a loop of Core Image Filters
我遵循了这 2 个教程 tutsplus and appcoda
我在 vc1 中有一个图像传递给 vc2。 vc2 有两个 imageView:originalImageView
显示来自 vc1 的原始图像,filteredImageView
显示应用了核心图像过滤器的新图像。 filteredImageView
锚定在 originalImageView
之上
我还有一个 scrollView,我用它创建了 coreImage 过滤器作为按钮,一旦你按下一个按钮,新的过滤器就会被应用,过滤后的图像现在显示在隐藏 [=12] 的 filteredImageView
中=] 因为它在它下面。
一旦用户按下任何包含滤镜的按钮,他们将无法返回到原始图像。
如何创建一个按钮来显示 scrollView 中的原始图像以及所有过滤后的图像?理想情况下,它应该是第一个图像,这样一旦用户按下它,就会显示原始图像
let originalImageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill
return imageView
}()
let filteredImageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill
return imageView
}()
let scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.backgroundColor = .black
return scrollView
}()
var originalImage: UIImage? // set from vc1
let ciFilterNames = [
"CISharpenLuminance",
"CIPhotoEffectChrome",
"CIPhotoEffectFade",
"CIPhotoEffectInstant",
"CIPhotoEffectNoir",
"CIPhotoEffectProcess",
"CIPhotoEffectTonal",
"CIPhotoEffectTransfer",
"CISepiaTone"
]
override func viewDidLoad() {
super.viewDidLoad()
createAnchors()
guard let originalImage = originalImage else { return }
originaImage.image = originalImage
var xCoord: CGFloat = 5
let yCoord: CGFloat = 5
let buttonWidth:CGFloat = 70
let buttonHeight: CGFloat = 70
let gapBetweenButtons: CGFloat = 5
var itemCount = 0
for i in 0..<ciFilterNames.count {
itemCount = i
let filterButton = UIButton(type: .custom)
button.frame = CGRect(x: xCoord, y: yCoord, width: buttonWidth, height: buttonHeight)
filterButton.tag = itemCount
filterButton.addTarget(self, action: #selector(filterButtonPressed(_:)), for: .touchUpInside)
filterButton.layer.cornerRadius = 7
filterButton.clipsToBounds = true
guard let openGLContext = EAGLContext(api: .openGLES3) else { return }
let context = CIContext(eaglContext: openGLContext)
// Create filters for each button
let coreImage = CIImage(image: originalImage)
let filter = CIFilter(name: "\(ciFilterNames[i])" )
filter?.setDefaults()
filter?.setValue(coreImage, forKey: kCIInputImageKey)
if ciFilterNames[i] == "CISharpenLuminance" {
filter?.setValue(0.8, forKey: kCIInputSharpnessKey)
} else {
filter?.setValue(1, forKey: kCIInputIntensityKey)
}
guard let output = filter?.value(forKey: kCIOutputImageKey) as? CIImage else { return }
guard let cgimgresult = context.createCGImage(output, from: output.extent) else { return }
let imageForButton = UIImage(cgImage: cgimgresult)
filterButton.setBackgroundImage(imageForButton, for: .normal)
// Add Buttons in the Scroll View
xCoord += buttonWidth + gapBetweenButtons
scrollView.addSubview(filterButton)
}
}
@objc fileprivate func filterButtonPressed(_ sender: UIButton) {
let button = sender as UIButton
filteredImageView.image = button.backgroundImage( for: .normal)
}
func createAnchors() {
view.addSubview(originalImageView)
view.addSubview(filteredImageView)
view.addSubview(scrollView)
originalImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
originalImageView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
originalImageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
originalImageView.widthAnchor.constraint(equalToConstant: view.frame.width).isActive = true
originalImageView.heightAnchor.constraint(equalToConstant: view.frame.width).isActive = true
filteredImageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
filteredImageView.leadingAnchor.constraint(equalTo: originalImageView.leadingAnchor).isActive = true
filteredImageView.widthAnchor.constraint(equalTo: originalImageView.widthAnchor).isActive = true
filteredImageView.heightAnchor.constraint(equalTo: originalImageView.heightAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: originalImageView.bottomAnchor, constant: 8).isActive = true
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
scrollView.heightAnchor.constraint(equalToConstant: 80).isActive = true
}
我使用水平 collectionView 和 viewDidLoad 代替 scrollView 第一次我将 vc1 中的图像添加到 [UIImages]
的数组然后第二次我遍历所有 ciFilterNames 并将它们添加到相同的数组中我将它们添加到滚动视图的方式。这样做让我将原始图像作为第一张图像以及所有过滤后的图像一起放在 collectionVIew 中。我也只需要一个imageView。
我在viewDidLoad里面的评论中添加了这两个步骤
var collectionView: UICollectionView!
let originalImageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill
return imageView
}()
var originalImage: UIImage? // set from vc1 or just use your own UIImage(named: "whatever") for this example
var tableData = [UIImage]()
let filterCell = "filterCell"
let ciFilterNames = [
"CISharpenLuminance",
"CIPhotoEffectChrome",
"CIPhotoEffectFade",
"CIPhotoEffectInstant",
"CIPhotoEffectNoir",
"CIPhotoEffectProcess",
"CIPhotoEffectTonal",
"CIPhotoEffectTransfer",
"CISepiaTone"
]
override func viewDidLoad() {
super.viewDidLoad()
configureCollectionView()
createAnchors()
guard let originalImage = originalImage else { return }
originaImage.image = originalImage
// 1. this appends the originalImage as the very first cell
tableData.append(originaImage)
guard let openGLContext = EAGLContext(api: .openGLES3) else { return }
let context = CIContext(eaglContext: openGLContext)
for i in 0..<ciFilterNames.count {
let coreImage = CIImage(image: tableData[0])
let filter = CIFilter(name: "\(ciFilterNames[i])" )
filter?.setDefaults()
filter?.setValue(coreImage, forKey: kCIInputImageKey)
if ciFilterNames[i] == "CISharpenLuminance" {
filter?.setValue(0.8, forKey: kCIInputSharpnessKey)
} else if ciFilterNames[i] == "CISepiaTone" {
filter?.setValue(1, forKey: kCIInputIntensityKey)
} else {
filter?.value(forKey: kCIOutputImageKey) as! CIImage
}
guard let output = filter?.value(forKey: kCIOutputImageKey) as? CIImage else { return }
guard let cgimgresult = context.createCGImage(output, from: output.extent) else { return }
let newImageWithFilterApplied = UIImage(cgImage: cgimgresult)
// 2. after each loop append the newImageWithFilterApplied to the rest of the cells
tableData.append(newImageWithFilterApplied)
collectionView.reloadData()
}
}
func configureCollectionView() {
let layout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0)
layout.scrollDirection = .horizontal
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.delegate = self
collectionView.dataSource = self
collectionView.alwaysBounceHorizontal = true
collectionView.backgroundColor = .black
collectionView.showsHorizontalScrollIndicator = false
collectionView.register(FilterCell.self, forCellWithReuseIdentifier: filterCell)
}
func createAnchors() {
view.addSubview(originalImageView)
view.addSubview(collectionView)
originalImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
originalImageView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
originalImageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
originalImageView.heightAnchor.constraint(equalToConstant: view.frame.width).isActive = true
collectionView.topAnchor.constraint(equalTo: originalImageView.bottomAnchor, constant: 10).isActive = true
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
collectionView.heightAnchor.constraint(equalToConstant: 80).isActive = true
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return tableData.count
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 80, height: 80)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: filterCell, for: indexPath) as! FilterCell
cell.imageView.image = tableData[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let cell = collectionView.cellForItem(at: indexPath) as? FilterCell else { return }
guard let indexPath = collectionView.indexPath(for: cell) else { return }
originalImageView.image = tableData[indexPath.item]
}
我遵循了这 2 个教程 tutsplus and appcoda
我在 vc1 中有一个图像传递给 vc2。 vc2 有两个 imageView:originalImageView
显示来自 vc1 的原始图像,filteredImageView
显示应用了核心图像过滤器的新图像。 filteredImageView
锚定在 originalImageView
我还有一个 scrollView,我用它创建了 coreImage 过滤器作为按钮,一旦你按下一个按钮,新的过滤器就会被应用,过滤后的图像现在显示在隐藏 [=12] 的 filteredImageView
中=] 因为它在它下面。
一旦用户按下任何包含滤镜的按钮,他们将无法返回到原始图像。
如何创建一个按钮来显示 scrollView 中的原始图像以及所有过滤后的图像?理想情况下,它应该是第一个图像,这样一旦用户按下它,就会显示原始图像
let originalImageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill
return imageView
}()
let filteredImageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill
return imageView
}()
let scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.backgroundColor = .black
return scrollView
}()
var originalImage: UIImage? // set from vc1
let ciFilterNames = [
"CISharpenLuminance",
"CIPhotoEffectChrome",
"CIPhotoEffectFade",
"CIPhotoEffectInstant",
"CIPhotoEffectNoir",
"CIPhotoEffectProcess",
"CIPhotoEffectTonal",
"CIPhotoEffectTransfer",
"CISepiaTone"
]
override func viewDidLoad() {
super.viewDidLoad()
createAnchors()
guard let originalImage = originalImage else { return }
originaImage.image = originalImage
var xCoord: CGFloat = 5
let yCoord: CGFloat = 5
let buttonWidth:CGFloat = 70
let buttonHeight: CGFloat = 70
let gapBetweenButtons: CGFloat = 5
var itemCount = 0
for i in 0..<ciFilterNames.count {
itemCount = i
let filterButton = UIButton(type: .custom)
button.frame = CGRect(x: xCoord, y: yCoord, width: buttonWidth, height: buttonHeight)
filterButton.tag = itemCount
filterButton.addTarget(self, action: #selector(filterButtonPressed(_:)), for: .touchUpInside)
filterButton.layer.cornerRadius = 7
filterButton.clipsToBounds = true
guard let openGLContext = EAGLContext(api: .openGLES3) else { return }
let context = CIContext(eaglContext: openGLContext)
// Create filters for each button
let coreImage = CIImage(image: originalImage)
let filter = CIFilter(name: "\(ciFilterNames[i])" )
filter?.setDefaults()
filter?.setValue(coreImage, forKey: kCIInputImageKey)
if ciFilterNames[i] == "CISharpenLuminance" {
filter?.setValue(0.8, forKey: kCIInputSharpnessKey)
} else {
filter?.setValue(1, forKey: kCIInputIntensityKey)
}
guard let output = filter?.value(forKey: kCIOutputImageKey) as? CIImage else { return }
guard let cgimgresult = context.createCGImage(output, from: output.extent) else { return }
let imageForButton = UIImage(cgImage: cgimgresult)
filterButton.setBackgroundImage(imageForButton, for: .normal)
// Add Buttons in the Scroll View
xCoord += buttonWidth + gapBetweenButtons
scrollView.addSubview(filterButton)
}
}
@objc fileprivate func filterButtonPressed(_ sender: UIButton) {
let button = sender as UIButton
filteredImageView.image = button.backgroundImage( for: .normal)
}
func createAnchors() {
view.addSubview(originalImageView)
view.addSubview(filteredImageView)
view.addSubview(scrollView)
originalImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
originalImageView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
originalImageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
originalImageView.widthAnchor.constraint(equalToConstant: view.frame.width).isActive = true
originalImageView.heightAnchor.constraint(equalToConstant: view.frame.width).isActive = true
filteredImageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
filteredImageView.leadingAnchor.constraint(equalTo: originalImageView.leadingAnchor).isActive = true
filteredImageView.widthAnchor.constraint(equalTo: originalImageView.widthAnchor).isActive = true
filteredImageView.heightAnchor.constraint(equalTo: originalImageView.heightAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: originalImageView.bottomAnchor, constant: 8).isActive = true
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
scrollView.heightAnchor.constraint(equalToConstant: 80).isActive = true
}
我使用水平 collectionView 和 viewDidLoad 代替 scrollView 第一次我将 vc1 中的图像添加到 [UIImages]
的数组然后第二次我遍历所有 ciFilterNames 并将它们添加到相同的数组中我将它们添加到滚动视图的方式。这样做让我将原始图像作为第一张图像以及所有过滤后的图像一起放在 collectionVIew 中。我也只需要一个imageView。
我在viewDidLoad里面的评论中添加了这两个步骤
var collectionView: UICollectionView!
let originalImageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill
return imageView
}()
var originalImage: UIImage? // set from vc1 or just use your own UIImage(named: "whatever") for this example
var tableData = [UIImage]()
let filterCell = "filterCell"
let ciFilterNames = [
"CISharpenLuminance",
"CIPhotoEffectChrome",
"CIPhotoEffectFade",
"CIPhotoEffectInstant",
"CIPhotoEffectNoir",
"CIPhotoEffectProcess",
"CIPhotoEffectTonal",
"CIPhotoEffectTransfer",
"CISepiaTone"
]
override func viewDidLoad() {
super.viewDidLoad()
configureCollectionView()
createAnchors()
guard let originalImage = originalImage else { return }
originaImage.image = originalImage
// 1. this appends the originalImage as the very first cell
tableData.append(originaImage)
guard let openGLContext = EAGLContext(api: .openGLES3) else { return }
let context = CIContext(eaglContext: openGLContext)
for i in 0..<ciFilterNames.count {
let coreImage = CIImage(image: tableData[0])
let filter = CIFilter(name: "\(ciFilterNames[i])" )
filter?.setDefaults()
filter?.setValue(coreImage, forKey: kCIInputImageKey)
if ciFilterNames[i] == "CISharpenLuminance" {
filter?.setValue(0.8, forKey: kCIInputSharpnessKey)
} else if ciFilterNames[i] == "CISepiaTone" {
filter?.setValue(1, forKey: kCIInputIntensityKey)
} else {
filter?.value(forKey: kCIOutputImageKey) as! CIImage
}
guard let output = filter?.value(forKey: kCIOutputImageKey) as? CIImage else { return }
guard let cgimgresult = context.createCGImage(output, from: output.extent) else { return }
let newImageWithFilterApplied = UIImage(cgImage: cgimgresult)
// 2. after each loop append the newImageWithFilterApplied to the rest of the cells
tableData.append(newImageWithFilterApplied)
collectionView.reloadData()
}
}
func configureCollectionView() {
let layout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0)
layout.scrollDirection = .horizontal
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.delegate = self
collectionView.dataSource = self
collectionView.alwaysBounceHorizontal = true
collectionView.backgroundColor = .black
collectionView.showsHorizontalScrollIndicator = false
collectionView.register(FilterCell.self, forCellWithReuseIdentifier: filterCell)
}
func createAnchors() {
view.addSubview(originalImageView)
view.addSubview(collectionView)
originalImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
originalImageView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
originalImageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
originalImageView.heightAnchor.constraint(equalToConstant: view.frame.width).isActive = true
collectionView.topAnchor.constraint(equalTo: originalImageView.bottomAnchor, constant: 10).isActive = true
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
collectionView.heightAnchor.constraint(equalToConstant: 80).isActive = true
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return tableData.count
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 80, height: 80)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: filterCell, for: indexPath) as! FilterCell
cell.imageView.image = tableData[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let cell = collectionView.cellForItem(at: indexPath) as? FilterCell else { return }
guard let indexPath = collectionView.indexPath(for: cell) else { return }
originalImageView.image = tableData[indexPath.item]
}