QuartzDemo/QuartzClippingView.swift
/* |
Copyright (C) 2017 Apple Inc. All Rights Reserved. |
See LICENSE.txt for this sample’s licensing information |
Abstract: |
Demonstrates using Quartz for clipping. |
*/ |
import UIKit |
class QuartzClippingView: QuartzView { |
static let image: CGImage = { |
let u = Bundle.main.url(forResource: "Ship", withExtension: "png")! |
let i = UIImage(contentsOfFile: u.path)! |
return i.cgImage! |
}() |
func addStarToContext(_ context: CGContext, centeredAt center: CGPoint, withRadius radius: CGFloat, andAngle angle: CGFloat) { |
var x = radius * CGFloat(sinf(Float(angle) * Float.pi / 5.0)) + center.x |
var y = radius * CGFloat(cosf(Float(angle) * Float.pi / 5.0)) + center.y |
context.move(to: CGPoint(x: x, y: y)) |
for i in 1...4 { |
x = radius * CGFloat(sinf((Float(i) * 4.0 * Float.pi + Float(angle)) / 5.0)) + center.x |
y = radius * CGFloat(cosf((Float(i) * 4.0 * Float.pi + Float(angle)) / 5.0)) + center.y |
context.addLine(to: CGPoint(x: x, y: y)) |
} |
// And close the subpath. |
context.closePath() |
} |
override func drawInContext(_ context: CGContext) { |
centerDrawing(inContext: context, drawingExtent: CGRect(x:0.0, y:0.0, width:320.0, height:160.0)) |
// So that the images in this demo appear right-side-up, we flip the context |
// In doing so we need to specify all of our Y positions relative to the height of the view. |
// The value we subtract from the height is the Y coordinate for the *bottom* of the image. |
let height = self.bounds.size.height |
context.translateBy(x: 0.0, y: height) |
context.scaleBy(x: 1.0, y: -1.0) |
context.setFillColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0) |
// We'll draw the original image for comparision |
context.draw(QuartzClippingView.image, in: CGRect(x: 10.0, y: height - 100.0, width: 90.0, height: 90.0)) |
// First we'll use clipping rectangles to remove the body of the ship. |
// We use CGContext.clip(to: [CGRect]) to clip to a set of rectangles. |
context.savingGState { |
// For this operation we extract the 35 pixel strip on each side of the source image. |
let clips = [ |
CGRect(x: 110.0, y: height - 100.0, width: 35.0, height: 90.0), |
CGRect(x: 165.0, y: height - 100.0, width: 35.0, height: 90.0) |
] |
// While convinient, this is just the equivalent of adding each rectangle to the current path, |
// then calling CGContextClip(). |
context.clip(to: clips) |
context.draw(QuartzClippingView.image, in: CGRect(x: 110.0, y: height - 100.0, width: 90.0, height: 90.0)) |
} |
// You can also clip to aribitrary shapes, which can be useful for special effects. |
// In this case we are going to clip to a star. |
// We will actually clip the image twice, using the different clipping modes. |
addStarToContext(context, centeredAt: CGPoint(x: 55.0, y: height - 150.0), withRadius: 45.0, andAngle: 0.0) |
context.savingGState { |
// Clip to the current path using the non-zero winding number rule. |
context.clip() |
// To make the area we draw to a bit more obvious, we'll the image over a red rectangle. |
context.fill(CGRect(x: 10.0, y: height - 190.0, width: 90.0, height: 90.0)) |
// And finally draw the image |
context.draw(QuartzClippingView.image, in: CGRect(x: 10.0, y: height - 190.0, width: 90.0, height: 90.0)) |
} |
addStarToContext(context, centeredAt: CGPoint(x: 155.0, y: height - 150.0), withRadius: 45.0, andAngle: 0.0) |
context.savingGState { |
// Clip to the current path using the even-odd rule. |
context.clip(using: .evenOdd) |
// To make the area we draw to a bit more obvious, we'll the image over a red rectangle. |
context.fill(CGRect(x: 110.0, y: height - 190.0, width: 90.0, height: 90.0)) |
// And finally draw the image |
context.draw(QuartzClippingView.image, in: CGRect(x: 110.0, y: height - 190.0, width: 90.0, height: 90.0)) |
} |
// Finally making the path slightly more complex by enscribing it in a rectangle changes what is clipped |
// For EO clipping mode this will invert the clip (for non-zero winding this is less predictable). |
addStarToContext(context, centeredAt: CGPoint(x: 255.0, y: height - 150.0), withRadius: 45.0, andAngle: 0.0) |
context.addRect(CGRect(x: 210.0, y: height - 190.0, width: 90.0, height: 90.0)) |
context.savingGState { |
// Clip to the current path using the even-odd rule. |
context.clip(using: .evenOdd) |
// To make the area we draw to a bit more obvious, we'll the image over a red rectangle. |
context.fill(CGRect(x: 210.0, y: height - 190.0, width: 90.0, height: 90.0)) |
// And finally draw the image |
context.draw(QuartzClippingView.image, in: CGRect(x: 210.0, y: height - 190.0, width: 90.0, height: 90.0)) |
} |
} |
} |
Copyright © 2017 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2017-09-19