ios - How to draw a gradient color wheel using CAGradientLayer? -
i got reference these links-
i have gone through concept of "hsv colour space". want draw color wheel using rgb of cagradientlayer
.
here code snippet of making color wheel using simple rgb color array , uibezierpath
-
func drawcolorwheel() { context?.savegstate() range = cgfloat(100.00 / cgfloat(colorarray.count)) k in 0 ..< colorarray.count { drawslice(startpercent: cgfloat(k) * range, endpercent: cgfloat(cgfloat(k + 1) * range), color: colorarray.object(at: k) as! uicolor) } context?.restoregstate() } func drawslice(startpercent: cgfloat, endpercent: cgfloat, color: uicolor) { let startangle = getangleat(percentage: startpercent) let endangle = getangleat(percentage: endpercent) let path = getarcpath(startangle: startangle, endangle: endangle) color.setfill() path.fill() }
where getangleat()
, getarcpath()
private functions draw path angle.
now, question how give these colors gradient effect each colors mix gradient color layer?
one approach build image , manipulate pixel buffer manually:
- create
cgcontext
of size , type; - access data buffer via
data
property; - rebind makes easy manipulate buffer (i use
pixel
,struct
32-bit representation of pixel); - loop through pixels, 1 one, converting
angle
,radius
circle within image; and - create pixel of appropriate color if it's inside circle; make zero-alpha pixel if not.
so in swift 3:
func buildhuecircle(in rect: cgrect, radius: cgfloat, scale: cgfloat = uiscreen.main.scale) -> uiimage? { let width = int(rect.size.width * scale) let height = int(rect.size.height * scale) let center = cgpoint(x: width / 2, y: height / 2) let space = cgcolorspacecreatedevicergb() let context = cgcontext(data: nil, width: width, height: height, bitspercomponent: 8, bytesperrow: width * 4, space: space, bitmapinfo: pixel.bitmapinfo)! let buffer = context.data! let pixels = buffer.bindmemory(to: pixel.self, capacity: width * height) var pixel: pixel y in 0 ..< height { x in 0 ..< width { let angle = fmod(atan2(cgfloat(x) - center.x, cgfloat(y) - center.y) + 2 * .pi, 2 * .pi) let distance = hypot(cgfloat(x) - center.x, cgfloat(y) - center.y) let value = uicolor(hue: angle / 2 / .pi, saturation: 1, brightness: 1, alpha: 1) var red: cgfloat = 0 var green: cgfloat = 0 var blue: cgfloat = 0 var alpha: cgfloat = 0 value.getred(&red, green: &green, blue: &blue, alpha: &alpha) if distance <= (radius * scale) { pixel = pixel(red: uint8(red * 255), green: uint8(green * 255), blue: uint8(blue * 255), alpha: uint8(alpha * 255)) } else { pixel = pixel(red: 255, green: 255, blue: 255, alpha: 0) } pixels[y * width + x] = pixel } } let cgimage = context.makeimage()! return uiimage(cgimage: cgimage, scale: scale, orientation: .up) }
where
struct pixel: equatable { private var rgba: uint32 var red: uint8 { return uint8((rgba >> 24) & 255) } var green: uint8 { return uint8((rgba >> 16) & 255) } var blue: uint8 { return uint8((rgba >> 8) & 255) } var alpha: uint8 { return uint8((rgba >> 0) & 255) } init(red: uint8, green: uint8, blue: uint8, alpha: uint8) { rgba = (uint32(red) << 24) | (uint32(green) << 16) | (uint32(blue) << 8) | (uint32(alpha) << 0) } static let bitmapinfo = cgimagealphainfo.premultipliedlast.rawvalue | cgbitmapinfo.byteorder32little.rawvalue static func ==(lhs: pixel, rhs: pixel) -> bool { return lhs.rgba == rhs.rgba } }
that yields:
or can tweak brightness or saturation based upon radius:
Comments
Post a Comment