2017-08-20 3 views
3

Je suis une référence de ces liens-Comment dessiner une roue de couleurs de dégradé à l'aide de CAGradientLayer?

Je suis passé par le concept de "HSV color space". Mais je veux dessiner une roue de couleur en utilisant RGB avec l'aide de CAGradientLayer.

Voici l'extrait de code de faire une roue de couleur en utilisant de simples tableau de couleurs RVB et UIBezierPath -

func drawColorWheel() 
{ 
    context?.saveGState() 

    range = CGFloat(100.00/CGFloat(colorArray.count)) 

    for 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() 
} 

getAngleAt() et getArcPath() sont les fonctions privées pour dessiner le chemin avec un angle.

Voici le résultat final de mon code - color wheel

Maintenant, ma question est la façon de donner ces couleurs un effet de dégradé de sorte que chaque couleurs se mélangent avec couche de dégradé de couleur?

Répondre

6

Une approche consiste à construire une image et de manipuler la mémoire tampon de pixel manuellement:

  • Créer CGContext de certaine taille et certain type;
  • Accéder à son tampon de données via la propriété data; Reconnaître cela à quelque chose qui rend facile à manipuler ce tampon (j'utilise un Pixel, un struct pour la représentation de 32 bits d'un pixel);
  • Parcourez les pixels, un par un, en les convertissant en angle et radius pour le cercle de cette image; et
  • Créez un pixel de la couleur appropriée s'il se trouve à l'intérieur du cercle; faites-en un pixel zéro-alpha sinon.

Donc, à 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 
    for y in 0 ..< height { 
     for 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) 
} 

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 
    } 
} 

qui donne:

constant saturation color wheel

Ou vous pouvez modifier la luminosité ou la saturation en fonction du rayon :

adjusting brightness

+0

Superbe réponse +1 –