How to crop UIImage to mask in Swift











up vote
0
down vote

favorite
1












I have a UIImage that I mask using another UIImage. The only problem is area outside the masked UIImage is still user interactable. How do I completely crop a UIImage to another image instead of mask.



@IBOutlet weak var imageView: UIImageView!

override func viewDidLoad() {
super.viewDidLoad()
let imageMask = UIImageView()

imageMask.image = //image to mask

imageMask.frame = photoImageView.bounds
imageView.mask = imageMask
}


enter image description hereenter image description here










share|improve this question




















  • 1




    stackoverflow.com/questions/32041420/… I think this question is similar
    – Ruban4Axis
    Nov 20 at 1:50















up vote
0
down vote

favorite
1












I have a UIImage that I mask using another UIImage. The only problem is area outside the masked UIImage is still user interactable. How do I completely crop a UIImage to another image instead of mask.



@IBOutlet weak var imageView: UIImageView!

override func viewDidLoad() {
super.viewDidLoad()
let imageMask = UIImageView()

imageMask.image = //image to mask

imageMask.frame = photoImageView.bounds
imageView.mask = imageMask
}


enter image description hereenter image description here










share|improve this question




















  • 1




    stackoverflow.com/questions/32041420/… I think this question is similar
    – Ruban4Axis
    Nov 20 at 1:50













up vote
0
down vote

favorite
1









up vote
0
down vote

favorite
1






1





I have a UIImage that I mask using another UIImage. The only problem is area outside the masked UIImage is still user interactable. How do I completely crop a UIImage to another image instead of mask.



@IBOutlet weak var imageView: UIImageView!

override func viewDidLoad() {
super.viewDidLoad()
let imageMask = UIImageView()

imageMask.image = //image to mask

imageMask.frame = photoImageView.bounds
imageView.mask = imageMask
}


enter image description hereenter image description here










share|improve this question















I have a UIImage that I mask using another UIImage. The only problem is area outside the masked UIImage is still user interactable. How do I completely crop a UIImage to another image instead of mask.



@IBOutlet weak var imageView: UIImageView!

override func viewDidLoad() {
super.viewDidLoad()
let imageMask = UIImageView()

imageMask.image = //image to mask

imageMask.frame = photoImageView.bounds
imageView.mask = imageMask
}


enter image description hereenter image description here







swift uiimageview crop






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 27 at 13:53

























asked Nov 20 at 0:46









Cristian

68115




68115








  • 1




    stackoverflow.com/questions/32041420/… I think this question is similar
    – Ruban4Axis
    Nov 20 at 1:50














  • 1




    stackoverflow.com/questions/32041420/… I think this question is similar
    – Ruban4Axis
    Nov 20 at 1:50








1




1




stackoverflow.com/questions/32041420/… I think this question is similar
– Ruban4Axis
Nov 20 at 1:50




stackoverflow.com/questions/32041420/… I think this question is similar
– Ruban4Axis
Nov 20 at 1:50












1 Answer
1






active

oldest

votes

















up vote
2
down vote



accepted
+50










Criteria



A simple test case could define a background color for the view of the ViewController and load the image and mask. Then a UITapGestureRecognizer is added to the ViewController view and to the UIImageView.



When applying a background color to the ViewController view, it is easy to see if masking works.



If you then tap on a non-transparent area, the tap should be received by the UIImageView, otherwise the ViewController view should receive the tap.



Image and Mask Image Size



In most cases, the image and mask image size or at least the aspect ratio of the image and mask image is the same.
It makes sense to use the same contentMode for the masking of UIImageView as for the original UIImageView, otherwise there would be a misalignment when changing the content mode in InterfaceBuilder at the latest.



Test Case



Therefore the test case could look like this:



import UIKit

class ViewController: UIViewController {

@IBOutlet weak var imageView: UIImageView!
private let maskView = UIImageView()

override func viewDidLoad() {
super.viewDidLoad()
self.imageView.image = UIImage(named: "testimage")
self.maskView.image = UIImage(named: "mask")
self.imageView.mask = maskView

let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(backgroundTapped))
self.view.addGestureRecognizer(tapGestureRecognizer)

let imageViewGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(iamgeViewTapped))
self.imageView.addGestureRecognizer(imageViewGestureRecognizer)
}

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.maskView.contentMode = self.imageView.contentMode
self.maskView.frame = self.imageView.bounds
}

@objc private func backgroundTapped() {
print ("background tapped!")
}

@objc private func iamgeViewTapped() {
print ("image view tapped!")
}

}


This code is already running. As expected, however, taps on the transparent area of the UIImageView also get here.



CustomImageView



Therefore we need a CustomImageView, which returns when clicking on a transparent pixel that it is not responsible for it.



This can be achieved by overriding this method:



func point(inside point: CGPoint, 
with event: UIEvent?) -> Bool


see documentation here: https://developer.apple.com/documentation/uikit/uiview/1622533-point




Returns a Boolean value indicating whether the receiver contains the specified point.




There is this cool answer already on SO, that is just slightly adapted: https://stackoverflow.com/a/27923457



import UIKit

class CustomImageView: UIImageView {

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return self.alphaFromPoint(point: point) > 32
}

private func alphaFromPoint(point: CGPoint) -> UInt8 {
var pixel: [UInt8] = [0, 0, 0, 0]
let colorSpace = CGColorSpaceCreateDeviceRGB();
let alphaInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
if let context = CGContext(data: &pixel,
width: 1,
height: 1,
bitsPerComponent: 8,
bytesPerRow: 4,
space: colorSpace,
bitmapInfo: alphaInfo.rawValue) {
context.translateBy(x: -point.x, y: -point.y)
self.layer.render(in: context)
}
return pixel[3]
}

}


Don't forget to change the custom class of ImageView to CustomImageView in Xcode in the identity inspector.



If you now tap on transparent areas, the view of the ViewController in the background gets the tap. If you tap on non-transparent areas our image view receives the tap.



Demo



Here is a short demo of the above code using the image and mask from the question:



demo






share|improve this answer























  • Thank you, this answered my question exactly
    – Cristian
    Dec 2 at 20:12











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53384678%2fhow-to-crop-uiimage-to-mask-in-swift%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
2
down vote



accepted
+50










Criteria



A simple test case could define a background color for the view of the ViewController and load the image and mask. Then a UITapGestureRecognizer is added to the ViewController view and to the UIImageView.



When applying a background color to the ViewController view, it is easy to see if masking works.



If you then tap on a non-transparent area, the tap should be received by the UIImageView, otherwise the ViewController view should receive the tap.



Image and Mask Image Size



In most cases, the image and mask image size or at least the aspect ratio of the image and mask image is the same.
It makes sense to use the same contentMode for the masking of UIImageView as for the original UIImageView, otherwise there would be a misalignment when changing the content mode in InterfaceBuilder at the latest.



Test Case



Therefore the test case could look like this:



import UIKit

class ViewController: UIViewController {

@IBOutlet weak var imageView: UIImageView!
private let maskView = UIImageView()

override func viewDidLoad() {
super.viewDidLoad()
self.imageView.image = UIImage(named: "testimage")
self.maskView.image = UIImage(named: "mask")
self.imageView.mask = maskView

let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(backgroundTapped))
self.view.addGestureRecognizer(tapGestureRecognizer)

let imageViewGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(iamgeViewTapped))
self.imageView.addGestureRecognizer(imageViewGestureRecognizer)
}

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.maskView.contentMode = self.imageView.contentMode
self.maskView.frame = self.imageView.bounds
}

@objc private func backgroundTapped() {
print ("background tapped!")
}

@objc private func iamgeViewTapped() {
print ("image view tapped!")
}

}


This code is already running. As expected, however, taps on the transparent area of the UIImageView also get here.



CustomImageView



Therefore we need a CustomImageView, which returns when clicking on a transparent pixel that it is not responsible for it.



This can be achieved by overriding this method:



func point(inside point: CGPoint, 
with event: UIEvent?) -> Bool


see documentation here: https://developer.apple.com/documentation/uikit/uiview/1622533-point




Returns a Boolean value indicating whether the receiver contains the specified point.




There is this cool answer already on SO, that is just slightly adapted: https://stackoverflow.com/a/27923457



import UIKit

class CustomImageView: UIImageView {

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return self.alphaFromPoint(point: point) > 32
}

private func alphaFromPoint(point: CGPoint) -> UInt8 {
var pixel: [UInt8] = [0, 0, 0, 0]
let colorSpace = CGColorSpaceCreateDeviceRGB();
let alphaInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
if let context = CGContext(data: &pixel,
width: 1,
height: 1,
bitsPerComponent: 8,
bytesPerRow: 4,
space: colorSpace,
bitmapInfo: alphaInfo.rawValue) {
context.translateBy(x: -point.x, y: -point.y)
self.layer.render(in: context)
}
return pixel[3]
}

}


Don't forget to change the custom class of ImageView to CustomImageView in Xcode in the identity inspector.



If you now tap on transparent areas, the view of the ViewController in the background gets the tap. If you tap on non-transparent areas our image view receives the tap.



Demo



Here is a short demo of the above code using the image and mask from the question:



demo






share|improve this answer























  • Thank you, this answered my question exactly
    – Cristian
    Dec 2 at 20:12















up vote
2
down vote



accepted
+50










Criteria



A simple test case could define a background color for the view of the ViewController and load the image and mask. Then a UITapGestureRecognizer is added to the ViewController view and to the UIImageView.



When applying a background color to the ViewController view, it is easy to see if masking works.



If you then tap on a non-transparent area, the tap should be received by the UIImageView, otherwise the ViewController view should receive the tap.



Image and Mask Image Size



In most cases, the image and mask image size or at least the aspect ratio of the image and mask image is the same.
It makes sense to use the same contentMode for the masking of UIImageView as for the original UIImageView, otherwise there would be a misalignment when changing the content mode in InterfaceBuilder at the latest.



Test Case



Therefore the test case could look like this:



import UIKit

class ViewController: UIViewController {

@IBOutlet weak var imageView: UIImageView!
private let maskView = UIImageView()

override func viewDidLoad() {
super.viewDidLoad()
self.imageView.image = UIImage(named: "testimage")
self.maskView.image = UIImage(named: "mask")
self.imageView.mask = maskView

let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(backgroundTapped))
self.view.addGestureRecognizer(tapGestureRecognizer)

let imageViewGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(iamgeViewTapped))
self.imageView.addGestureRecognizer(imageViewGestureRecognizer)
}

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.maskView.contentMode = self.imageView.contentMode
self.maskView.frame = self.imageView.bounds
}

@objc private func backgroundTapped() {
print ("background tapped!")
}

@objc private func iamgeViewTapped() {
print ("image view tapped!")
}

}


This code is already running. As expected, however, taps on the transparent area of the UIImageView also get here.



CustomImageView



Therefore we need a CustomImageView, which returns when clicking on a transparent pixel that it is not responsible for it.



This can be achieved by overriding this method:



func point(inside point: CGPoint, 
with event: UIEvent?) -> Bool


see documentation here: https://developer.apple.com/documentation/uikit/uiview/1622533-point




Returns a Boolean value indicating whether the receiver contains the specified point.




There is this cool answer already on SO, that is just slightly adapted: https://stackoverflow.com/a/27923457



import UIKit

class CustomImageView: UIImageView {

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return self.alphaFromPoint(point: point) > 32
}

private func alphaFromPoint(point: CGPoint) -> UInt8 {
var pixel: [UInt8] = [0, 0, 0, 0]
let colorSpace = CGColorSpaceCreateDeviceRGB();
let alphaInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
if let context = CGContext(data: &pixel,
width: 1,
height: 1,
bitsPerComponent: 8,
bytesPerRow: 4,
space: colorSpace,
bitmapInfo: alphaInfo.rawValue) {
context.translateBy(x: -point.x, y: -point.y)
self.layer.render(in: context)
}
return pixel[3]
}

}


Don't forget to change the custom class of ImageView to CustomImageView in Xcode in the identity inspector.



If you now tap on transparent areas, the view of the ViewController in the background gets the tap. If you tap on non-transparent areas our image view receives the tap.



Demo



Here is a short demo of the above code using the image and mask from the question:



demo






share|improve this answer























  • Thank you, this answered my question exactly
    – Cristian
    Dec 2 at 20:12













up vote
2
down vote



accepted
+50







up vote
2
down vote



accepted
+50




+50




Criteria



A simple test case could define a background color for the view of the ViewController and load the image and mask. Then a UITapGestureRecognizer is added to the ViewController view and to the UIImageView.



When applying a background color to the ViewController view, it is easy to see if masking works.



If you then tap on a non-transparent area, the tap should be received by the UIImageView, otherwise the ViewController view should receive the tap.



Image and Mask Image Size



In most cases, the image and mask image size or at least the aspect ratio of the image and mask image is the same.
It makes sense to use the same contentMode for the masking of UIImageView as for the original UIImageView, otherwise there would be a misalignment when changing the content mode in InterfaceBuilder at the latest.



Test Case



Therefore the test case could look like this:



import UIKit

class ViewController: UIViewController {

@IBOutlet weak var imageView: UIImageView!
private let maskView = UIImageView()

override func viewDidLoad() {
super.viewDidLoad()
self.imageView.image = UIImage(named: "testimage")
self.maskView.image = UIImage(named: "mask")
self.imageView.mask = maskView

let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(backgroundTapped))
self.view.addGestureRecognizer(tapGestureRecognizer)

let imageViewGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(iamgeViewTapped))
self.imageView.addGestureRecognizer(imageViewGestureRecognizer)
}

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.maskView.contentMode = self.imageView.contentMode
self.maskView.frame = self.imageView.bounds
}

@objc private func backgroundTapped() {
print ("background tapped!")
}

@objc private func iamgeViewTapped() {
print ("image view tapped!")
}

}


This code is already running. As expected, however, taps on the transparent area of the UIImageView also get here.



CustomImageView



Therefore we need a CustomImageView, which returns when clicking on a transparent pixel that it is not responsible for it.



This can be achieved by overriding this method:



func point(inside point: CGPoint, 
with event: UIEvent?) -> Bool


see documentation here: https://developer.apple.com/documentation/uikit/uiview/1622533-point




Returns a Boolean value indicating whether the receiver contains the specified point.




There is this cool answer already on SO, that is just slightly adapted: https://stackoverflow.com/a/27923457



import UIKit

class CustomImageView: UIImageView {

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return self.alphaFromPoint(point: point) > 32
}

private func alphaFromPoint(point: CGPoint) -> UInt8 {
var pixel: [UInt8] = [0, 0, 0, 0]
let colorSpace = CGColorSpaceCreateDeviceRGB();
let alphaInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
if let context = CGContext(data: &pixel,
width: 1,
height: 1,
bitsPerComponent: 8,
bytesPerRow: 4,
space: colorSpace,
bitmapInfo: alphaInfo.rawValue) {
context.translateBy(x: -point.x, y: -point.y)
self.layer.render(in: context)
}
return pixel[3]
}

}


Don't forget to change the custom class of ImageView to CustomImageView in Xcode in the identity inspector.



If you now tap on transparent areas, the view of the ViewController in the background gets the tap. If you tap on non-transparent areas our image view receives the tap.



Demo



Here is a short demo of the above code using the image and mask from the question:



demo






share|improve this answer














Criteria



A simple test case could define a background color for the view of the ViewController and load the image and mask. Then a UITapGestureRecognizer is added to the ViewController view and to the UIImageView.



When applying a background color to the ViewController view, it is easy to see if masking works.



If you then tap on a non-transparent area, the tap should be received by the UIImageView, otherwise the ViewController view should receive the tap.



Image and Mask Image Size



In most cases, the image and mask image size or at least the aspect ratio of the image and mask image is the same.
It makes sense to use the same contentMode for the masking of UIImageView as for the original UIImageView, otherwise there would be a misalignment when changing the content mode in InterfaceBuilder at the latest.



Test Case



Therefore the test case could look like this:



import UIKit

class ViewController: UIViewController {

@IBOutlet weak var imageView: UIImageView!
private let maskView = UIImageView()

override func viewDidLoad() {
super.viewDidLoad()
self.imageView.image = UIImage(named: "testimage")
self.maskView.image = UIImage(named: "mask")
self.imageView.mask = maskView

let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(backgroundTapped))
self.view.addGestureRecognizer(tapGestureRecognizer)

let imageViewGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(iamgeViewTapped))
self.imageView.addGestureRecognizer(imageViewGestureRecognizer)
}

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.maskView.contentMode = self.imageView.contentMode
self.maskView.frame = self.imageView.bounds
}

@objc private func backgroundTapped() {
print ("background tapped!")
}

@objc private func iamgeViewTapped() {
print ("image view tapped!")
}

}


This code is already running. As expected, however, taps on the transparent area of the UIImageView also get here.



CustomImageView



Therefore we need a CustomImageView, which returns when clicking on a transparent pixel that it is not responsible for it.



This can be achieved by overriding this method:



func point(inside point: CGPoint, 
with event: UIEvent?) -> Bool


see documentation here: https://developer.apple.com/documentation/uikit/uiview/1622533-point




Returns a Boolean value indicating whether the receiver contains the specified point.




There is this cool answer already on SO, that is just slightly adapted: https://stackoverflow.com/a/27923457



import UIKit

class CustomImageView: UIImageView {

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return self.alphaFromPoint(point: point) > 32
}

private func alphaFromPoint(point: CGPoint) -> UInt8 {
var pixel: [UInt8] = [0, 0, 0, 0]
let colorSpace = CGColorSpaceCreateDeviceRGB();
let alphaInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
if let context = CGContext(data: &pixel,
width: 1,
height: 1,
bitsPerComponent: 8,
bytesPerRow: 4,
space: colorSpace,
bitmapInfo: alphaInfo.rawValue) {
context.translateBy(x: -point.x, y: -point.y)
self.layer.render(in: context)
}
return pixel[3]
}

}


Don't forget to change the custom class of ImageView to CustomImageView in Xcode in the identity inspector.



If you now tap on transparent areas, the view of the ViewController in the background gets the tap. If you tap on non-transparent areas our image view receives the tap.



Demo



Here is a short demo of the above code using the image and mask from the question:



demo







share|improve this answer














share|improve this answer



share|improve this answer








edited Dec 2 at 18:38

























answered Dec 2 at 18:22









Stephan Schlecht

2,460188




2,460188












  • Thank you, this answered my question exactly
    – Cristian
    Dec 2 at 20:12


















  • Thank you, this answered my question exactly
    – Cristian
    Dec 2 at 20:12
















Thank you, this answered my question exactly
– Cristian
Dec 2 at 20:12




Thank you, this answered my question exactly
– Cristian
Dec 2 at 20:12


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53384678%2fhow-to-crop-uiimage-to-mask-in-swift%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Tonle Sap (See)

I get strange results when I access the Sqlitedatabase with Unity C# via XAMPP

Guatemaltekische Davis-Cup-Mannschaft