I would like to blend two images using Core Graphics.
For example, I have an image:
This image represents the frame. I would like to have this image sliceable.
Another image represents the background:
What I am trying to achieve, is to blind those two images like:
The important thing, that this image might not necessary be circle. It might be sliceable.
How can I achieve this by using Core Graphics?
Try following method that uses masking (maskImage is the one that represents "frame", so in your example it would be that black circle, surrounding of the black circle has to be transparent):
import UIKit
class ViewController: UIViewController {
fileprivate let imageView = UIImageView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(imageView)
imageView.clipsToBounds = true
imageView.translatesAutoresizingMaskIntoConstraints = false
let cons = [
imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
imageView.heightAnchor.constraint(equalToConstant: 130),
imageView.widthAnchor.constraint(equalToConstant: 300),
]
NSLayoutConstraint.activate(cons)
setup(image: #imageLiteral(resourceName: "image"), withMask: #imageLiteral(resourceName: "masking"))
}
fileprivate func setup(image: UIImage, withMask maskImage: UIImage) {
imageView.superview?.layoutIfNeeded()
imageView.image = maskImage
let slicedMask = captureView(imageView: imageView)
imageView.image = image
let mask = CALayer()
mask.contents = slicedMask.cgImage
mask.frame = imageView.bounds
imageView.layer.mask = mask
}
func captureView(imageView: UIImageView) -> UIImage {
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, false, UIScreen.main.scale)
let context: CGContext = UIGraphicsGetCurrentContext()!
imageView.layer.render(in: context)
let img: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return img
}
}
I deal with slicing here quite "hacky": first I render the mask in the imageView to get it sliced, then I take a "screenshot" of the rendered sliced mask, and use the screenshot as a mask.
Keep in mind that mask.frame = imageView.bounds has to set frame properly, thus at that point the layout should be done. If later layout of the image changes, you will have to setup the mask again. mask.frame always have to fit the imageView.bounds (so if the layout changes in time, re-setup the image after layout changed).
Related
In photo editor screen , I have imageview and it has background image and on top of imageview I add elements like text (label), stickers(images) etc. , Now for the final image containing all elements added on imageview , I am getting image from below code
clipRect is rect for background image inside imageview, image is aspectfit in imageview
Below is code inside UIView extension which has function to generate image out of view.
self == uiview
let op_format = UIGraphicsImageRendererFormat()
op_format.scale = 1.0
let renderer = UIGraphicsImageRenderer(bounds: CGRect(origin: clipRect!.origin, size: outputSize), format: op_format)
let originalBound = self.bounds
self.bounds = CGRect(origin: clipRect!.origin, size: clipRect!.size)
var finalImage = renderer.image { ctx in
self.drawHierarchy(in: CGRect(origin: self.bounds.origin, size: outputSize), afterScreenUpdates: true)
}
self.bounds = CGRect(origin: originalBound.origin, size: originalBound.size)
Issue here is quality of final image quality is very poor as compared to original background image.
Don't set the scale of your UIGraphicsImageRendererFormat to 1. That forces the output image to #1x (non-retina). For most (all?) iOS devices, that will cause a 2X or 3X loss of resolution. Leave the scale value of the UIGraphicsImageRendererFormat at the default value.
you can take screenshot as well
// Convert a uiview to uiimage
func captureView() -> UIImage {
// Gradually increase the number for high resolution.
let scale = 1.0
UIGraphicsBeginImageContextWithOptions(bounds.size, opaque, scale)
layer.renderInContext(UIGraphicsGetCurrentContext()!)
let image:UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
I would like to create a very simple image editor, same as twitter (for the profile image)
I know how to pinch or move an image.
But i don’t know how to create the "circle layer" and just keep this part of the image, like this :
Make sure to import QuarzCore.
func maskRoundedImage(image: UIImage, radius: CGFloat) -> UIImage {
let imgView: UIImageView = UIImageView(image: image)
let layer = imgView.layer
layer.masksToBounds = true
layer.cornerRadius = radius
UIGraphicsBeginImageContext(imgView.bounds.size)
layer.render(in: UIGraphicsGetCurrentContext()!)
let roundedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return roundedImage!
}
https://github.com/andreaantonioni/AAPhotoCircleCrop
Each view has an underlying layer onto which you apply a corner radius. Then you must apply clipToBounds on that layer in order to apply that mask to the overlying UIView. The corner radius must be half the width of the view in order to get a circle effect. Otherwise the corners of the view will be rounded.
For example:
let square = UIView()
square.center = view.center
square.bounds.size = CGSize(width: 100, height: 100)
square.backgroundColor = .red
view.addSubview(square)
square.layer.cornerRadius = 50
square.clipsToBounds = true
Above mentioned ways are good, But you can not achieved exact output as in above image E.g You can not get alpha effect.
I suggest simple way to do it.
1) Add new image to project with transparent background with Opocity and circle.
2) Add new imageView above to mainview as below.
let image = UIImageView(frame: view.bounds)
mage.image = UIImage.init(named:"imageName")
view.addSubview(image)
Then output should be as per your requirement.
I'm trying to make images circular in a tableview cell, I've the various ways I've seen on stackoverflow but this is the closest I've gotten:
As you can see they look more like elipses than circles. In storyboard I have the constraints set to keeping the aspect ratio 1:1 and the view mode "aspect fill". I'm using this UIImage extension for the circular shape:
extension UIImage {
var circleMask: UIImage {
let square = CGSize(width: min(size.width, size.height), height: min(size.width, size.height))
let imageView = UIImageView(frame: CGRect(origin: CGPoint(x: 0, y: 0), size: square))
imageView.contentMode = UIViewContentMode.scaleAspectFill
imageView.image = self
imageView.layer.cornerRadius = square.width/2
imageView.layer.borderColor = UIColor.white.cgColor
imageView.layer.borderWidth = 5
imageView.layer.masksToBounds = true
UIGraphicsBeginImageContext(imageView.bounds.size)
imageView.layer.render(in: UIGraphicsGetCurrentContext()!)
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return result!
}
}
This is how my cellForRowAt IndexPath looks:
let cell = detailTableView.dequeueReusableCell(withIdentifier: castResuseIdentifier)
as! CastCell
let cast = castArray[indexPath.row]
cell.actorName.text = cast.name
cell.characterName.text = cast.character
cell.actorProfileImage.image = castImageArray[indexPath.row].circleMask
self.detailTableView.rowHeight = 100
detailTableView.allowsSelection = true
return cell
Not sure why they aren't perfect circles, any idea?
That is a really non-performant way of achieving that effect, since you're creating a UIImageView and rendering it to a separate image context every time.
For a quick and easy way to do it, just set the cornerRadius property for the layer of the actorProfileImage view inside your CastCell.
By not using the extension and instead adding this to the cellForRowAtIndexPath the images came out circular
cell.actorProfileImage.layer.cornerRadius = cell.actorProfileImage.frame.size.height/2
cell.actorProfileImage.clipsToBounds = true
cell.actorProfileImage.layer.masksToBounds = true
I'm attempting to apply tint of a UIImageView consisting of programatically loaded animationImages. Currently using iOS 9.3.
I think I've tried every proposed solution found here for applying the tint including:
Setting the .renderMode on load with: let newImage: UIImage? =
UIImage(named: filename as
String)!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
Setting the tintView either in the Storyboard or programatically
with: zeroImageView.tintColor = UIColor.redColor()
Setting the image .renderMode through the UIImageView itself:
zeroImageView.image = zeroImageView.image!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
Setting the UIImageView's renderMode through the Interface Builder
user defined runtime attributes: imageRenderingMode Number 2
The image sequence is of PNGs with transparency, so, I would like to re-colour the image and maintain the transparency.
I've had no luck and am sort of at a loss. Wondering if maybe these methods only work for a still UIAnimationView? Any help would be greatly appreciated, thanks!
Here's some code:
// Load all images
while let element = enumerator.nextObject() as? String {
if element.hasSuffix("png") {
let filename: NSString = "Digits/0/" + element
print(filename)
imageNames.append(filename as String)
let newImage: UIImage? = UIImage(named: filename as String)!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
images.append(newImage!)
zeroImageView.tintColor = UIColor.redColor()
}
}
// Make animated UIImageView
zeroImageView.userInteractionEnabled = false
zeroImageView.animationImages = images
zeroImageView.animationDuration = 2.0
zeroImageView.startAnimating()
zeroImageView.tintColor = UIColor.redColor()
Try this...
extension UIImage {
func image(withTint tint: UIColor) -> UIImage? {
guard let cgImage = cgImage else {
return nil
}
UIGraphicsBeginImageContextWithOptions(size, false, scale)
guard let context = UIGraphicsGetCurrentContext() else {
return nil
}
let rect = CGRect(origin: .zero, size: size)
context.translateBy(x: 0, y: size.height)
context.scaleBy(x: 1.0, y: -1.0)
context.setBlendMode(.normal)
context.clip(to: rect, mask: cgImage)
tint.setFill()
context.fill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
}
If none of those worked the next step I would do is programmatically place an empty UIView on top of the UIImageView. First off, it would not interfere with anything going on in the UIImageView.
I would check out this tutorial here: http://www.apptuitions.com/programmatically-creating-uiview-uislider-uiswitch-using-swift/
this will teach you how to programmatically add a UIView to the storyboard. I would add this code in the viewDidLoad() method.
The main thing you need to change is the background color of the UIView. First you have to decide what the color of the tint (which from what I see in your code is red) and then explicitly change the 'Alpha' of the color so that it is barely showing. You change the 'Alpha' because that is basically the opacity of the color.
Hope this helps.
I have image1, I would like to make that image circle shape and then insert it into image2. How to do it using swift? I can't do this with photoshop or other image editing tool, because my image1 will may be different every time.
EDIT: This what I am trying to achieve:
Flower is image1.
EDIT 2: What I have tried and kind of works:
let image2 = UIImage(named: "RedPin")
let newSize = CGSizeMake(image2!.size.width, image2!.size.height)
UIGraphicsBeginImageContext(newSize)
image2!.drawInRect(CGRectMake(0,0,newSize.width,newSize.height))
let imageView: UIImageView = UIImageView(image: image1)
var layer: CALayer = CALayer()
layer = imageView.layer
layer.masksToBounds = true
layer.cornerRadius = CGFloat(65)
UIGraphicsBeginImageContext(imageView.bounds.size)
layer.renderInContext(UIGraphicsGetCurrentContext()!)
let roundedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
// decrease top image size
roundedImage.drawInRect(CGRectMake(10,10,45,45), blendMode: .Normal, alpha:1.0)
let createdNewImage = UIGraphicsGetImageFromCurrentImageContext()
Yet image1 is more a square with rounded edges and in general image seems to be low quality. Here is what that function above does:
EDIT 3: Toucan library is great at creating rounded images (let roundedImage = Toucan(image: newImage).maskWithEllipse().image), however final image version still looks blurry. Why's that?
I have Set image like this with rounded corner with same code like you.
func UserImageForAnnotation() -> UIImage {
let userPinImg : UIImage = UIImage(named: "pin_user.png")!
UIGraphicsBeginImageContextWithOptions(userPinImg.size, false, 0.0);
userPinImg.drawInRect(CGRect(origin: CGPointZero, size: userPinImg.size))
let roundRect : CGRect = CGRectMake(2, 2, userPinImg.size.width-4, userPinImg.size.width-4)
let myUserImgView = UIImageView(frame: roundRect)
myUserImgView.image = UIImage(named: "pic.png")
// myUserImgView.backgroundColor = UIColor.blackColor()
// myUserImgView.layer.borderColor = UIColor.whiteColor().CGColor
// myUserImgView.layer.borderWidth = 0.5
let layer: CALayer = myUserImgView.layer
layer.masksToBounds = true
layer.cornerRadius = myUserImgView.frame.size.width/2
UIGraphicsBeginImageContextWithOptions(myUserImgView.bounds.size, myUserImgView.opaque, 0.0)
layer.renderInContext(UIGraphicsGetCurrentContext()!)
let roundedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
roundedImage.drawInRect(roundRect)
let resultImg : UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return resultImg
}
Which gives me exact result what I want in my pin image.