Skip to content

Instantly share code, notes, and snippets.

@BenziAhamed
Last active May 24, 2022 22:24
Show Gist options
  • Save BenziAhamed/bcbed0054a6b572c9d8d to your computer and use it in GitHub Desktop.
Save BenziAhamed/bcbed0054a6b572c9d8d to your computer and use it in GitHub Desktop.
Demonstration of using CGCreatePattern in Swift
//: Playground - noun: a place where people can play
//: Copy this to one!
import UIKit
// With helpful insights from
// https://forums.developer.apple.com/message/15725#15725 via http://oleb.net/blog/2015/06/c-callbacks-in-swift/
// This is essential the standalone basic definition of a pattern
// that CGCreatePattern requires
public class PatternDefinition : NSObject {
public let size:CGSize
public var bounds:CGRect
public var colored:Bool = true
public var xStep:CGFloat = 0
public var yStep:CGFloat = 0
public var tiling = CGPatternTiling.ConstantSpacing
public var transform:CGAffineTransform = CGAffineTransformMake(1, 0, 0, 1, 0, 0)
public init(size:CGSize) {
self.size = size
self.bounds = CGRectMake(0, 0, size.width, size.height)
self.xStep = size.width
self.yStep = size.height
}
}
// A block that can create a pattern for a context from a definition
public typealias PatternCreationBlock = @convention(block) (PatternDefinition, CGContext?) -> Void
// The pattern payload consists of the pattern definition
// and a block that given a CG context and pattern definition
// will draw a pattern in the context
public class PatternPayload : NSObject {
public let definition:PatternDefinition
public let createBlock:PatternCreationBlock
public init(definition:PatternDefinition, createBlock:PatternCreationBlock) {
self.definition = definition
self.createBlock = createBlock
}
}
public struct DrawKit {
public static func createPatternImage(size:CGSize, payload:PatternPayload) -> UIImage {
// This is the C-style function that will be called via CGCreatePattern
// we extract the payload, and call its create block which will
// draw the desired pattern in the context
func drawPattern(info:UnsafeMutablePointer<Void>, context:CGContext?) -> Void {
let payload = unsafeBitCast(info, PatternPayload.self)
payload.createBlock(payload.definition, context)
}
UIGraphicsBeginImageContext(size)
let context = UIGraphicsGetCurrentContext()
CGContextSaveGState(context)
CGContextSetAllowsAntialiasing(context, false)
let patternSpace = CGColorSpaceCreatePattern(nil)
CGContextSetFillColorSpace(context, patternSpace)
var callbacks = CGPatternCallbacks(version: 0, drawPattern: drawPattern, releaseInfo: nil)
let def = payload.definition
let pattern = CGPatternCreate(
unsafeBitCast(payload, UnsafeMutablePointer<Void>.self), // oooh!
def.bounds,
def.transform,
def.xStep,
def.yStep,
def.tiling,
def.colored,
&callbacks
)
var alpha:CGFloat = 1
CGContextSetFillPattern(context, pattern, &alpha)
CGContextFillRect(context, CGRectMake(0, 0, size.width, size.height))
CGContextRestoreGState(context)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
// ------- let's create a pattern filled image
let createPatternBlock: PatternCreationBlock = {
(def, context) in
CGContextSetFillColorWithColor(context, UIColor.redColor().CGColor)
CGContextFillRect(context, CGRectMake(0, 0, def.size.width, def.size.height))
CGContextSetFillColorWithColor(context, UIColor.blackColor().colorWithAlphaComponent(0.2).CGColor)
CGContextFillRect(context, CGRectMake(2, 2, def.size.width-2, def.size.height-2))
return
}
let pattern = PatternDefinition(size: CGSizeMake(10,10))
let image = DrawKit.createPatternImage(CGSizeMake(300, 200), payload: PatternPayload(definition: pattern, createBlock: createPatternBlock))
@BenziAhamed
Copy link
Author

screen shot 2015-09-19 at 2 37 19 pm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment