first commit
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
//
|
||||
// ColorWheelView.swift
|
||||
// ColorWheel
|
||||
//
|
||||
// Created by 楊昀羲 on 2019/3/8.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
// 建立 RGB 資料型別
|
||||
typealias RGB = (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)
|
||||
|
||||
// 建立 HSV 資料型別
|
||||
typealias HSV = (hue: CGFloat, saturation: CGFloat, brightness: CGFloat, alpha: CGFloat)
|
||||
|
||||
class ColorWheelView: UIView {
|
||||
|
||||
// 邊距
|
||||
private let BORDER = 20.0
|
||||
|
||||
var wheelLayer: CALayer!
|
||||
|
||||
// 取得螢幕解析度縮放
|
||||
let scale: CGFloat = UIScreen.main.scale
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder);
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
// 色相-飽和度圓盤圖層
|
||||
let width = self.frame.width - (BORDER * 2.0)
|
||||
let height = self.frame.height - (BORDER * 2.0)
|
||||
|
||||
wheelLayer = CALayer()
|
||||
wheelLayer.frame = CGRect(x: BORDER, y: BORDER, width: width, height: height)
|
||||
wheelLayer.contents = createColorWheel(wheelLayer.frame.size)
|
||||
self.layer.addSublayer(wheelLayer)
|
||||
}
|
||||
|
||||
private func createColorWheel(_ size: CGSize) -> CGImage {
|
||||
// 建立色相-飽和度圓盤
|
||||
let originalWidth = size.width
|
||||
let originalHeight = size.height
|
||||
let dimension = min(originalWidth * scale, originalHeight * scale)
|
||||
let bufferLength = Int(dimension * dimension * 4) // 寬 * 高 * 色彩像素(RGBA)
|
||||
|
||||
// 建立點陣圖資料
|
||||
let bitmapData = CFDataCreateMutable(nil, 0)
|
||||
CFDataSetLength(bitmapData, CFIndex(bufferLength))
|
||||
let bitmap = CFDataGetMutableBytePtr(bitmapData)
|
||||
|
||||
// 塞入資料
|
||||
for y in stride(from: CGFloat(0), to: dimension, by: CGFloat(1)) {
|
||||
for x in stride(from: CGFloat(0), to: dimension, by: CGFloat(1)) {
|
||||
var hsv: HSV = (hue: 0, saturation: 0, brightness: 0, alpha: 0)
|
||||
var rgb: RGB = (red: 0, green: 0, blue: 0, alpha: 0)
|
||||
|
||||
let color = hueSaturationAtPoint(CGPoint(x: x, y: y))
|
||||
let hue = color.hue
|
||||
let saturation = color.saturation
|
||||
var a: CGFloat = 0.0
|
||||
if (saturation < 1.0) {
|
||||
// 將邊緣進行反鋸齒處理
|
||||
if (saturation > 0.99) {
|
||||
a = (1.0 - saturation) * 100
|
||||
} else {
|
||||
a = 1.0;
|
||||
}
|
||||
|
||||
hsv.hue = hue
|
||||
hsv.saturation = saturation
|
||||
hsv.brightness = 1.0
|
||||
hsv.alpha = a
|
||||
rgb = hsv2rgb(hsv)
|
||||
}
|
||||
let offset = Int(4 * (x + y * dimension))
|
||||
bitmap?[offset] = UInt8(rgb.red*255)
|
||||
bitmap?[offset + 1] = UInt8(rgb.green*255)
|
||||
bitmap?[offset + 2] = UInt8(rgb.blue*255)
|
||||
bitmap?[offset + 3] = UInt8(rgb.alpha*255)
|
||||
}
|
||||
}
|
||||
|
||||
// 將 bitmap 資料輸出到 CGImage
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let dataProvider = CGDataProvider(data: bitmapData!)
|
||||
let bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo().rawValue | CGImageAlphaInfo.last.rawValue)
|
||||
let imageRef = CGImage(width: Int(dimension), height: Int(dimension), bitsPerComponent: 8, bitsPerPixel: 32, bytesPerRow: Int(dimension) * 4, space: colorSpace, bitmapInfo: bitmapInfo, provider: dataProvider!, decode: nil, shouldInterpolate: false, intent: CGColorRenderingIntent.defaultIntent)
|
||||
return imageRef!
|
||||
}
|
||||
|
||||
// 透過座標取得色相和飽和度
|
||||
func hueSaturationAtPoint(_ position: CGPoint) -> (hue: CGFloat, saturation: CGFloat) {
|
||||
let c = wheelLayer.frame.width * scale / 2
|
||||
let dx = CGFloat(position.x - c) / c
|
||||
let dy = CGFloat(position.y - c) / c
|
||||
let d = sqrt(CGFloat (dx * dx + dy * dy))
|
||||
|
||||
let saturation: CGFloat = d
|
||||
|
||||
var hue: CGFloat
|
||||
if (d == 0) {
|
||||
hue = 0;
|
||||
} else {
|
||||
hue = acos(dx/d) / CGFloat(Double.pi) / 2.0
|
||||
if (dy < 0) {
|
||||
hue = 1.0 - hue
|
||||
}
|
||||
}
|
||||
return (hue, saturation)
|
||||
}
|
||||
|
||||
// 將 HSV 轉換成 RGB
|
||||
func hsv2rgb(_ hsv: HSV) -> RGB {
|
||||
var rgb: RGB = (red: 0.0, green: 0.0, blue: 0.0, alpha: 0.0)
|
||||
var r: CGFloat
|
||||
var g: CGFloat
|
||||
var b: CGFloat
|
||||
|
||||
let i = Int(hsv.hue * 6)
|
||||
let f = hsv.hue * 6 - CGFloat(i)
|
||||
let p = hsv.brightness * (1 - hsv.saturation)
|
||||
let q = hsv.brightness * (1 - f * hsv.saturation)
|
||||
let t = hsv.brightness * (1 - (1 - f) * hsv.saturation)
|
||||
switch (i % 6) {
|
||||
case 0: r = hsv.brightness; g = t; b = p; break;
|
||||
case 1: r = q; g = hsv.brightness; b = p; break;
|
||||
case 2: r = p; g = hsv.brightness; b = t; break;
|
||||
case 3: r = p; g = q; b = hsv.brightness; break;
|
||||
case 4: r = t; g = p; b = hsv.brightness; break;
|
||||
case 5: r = hsv.brightness; g = p; b = q; break;
|
||||
default: r = hsv.brightness; g = t; b = p;
|
||||
}
|
||||
|
||||
rgb.red = r
|
||||
rgb.green = g
|
||||
rgb.blue = b
|
||||
rgb.alpha = hsv.alpha
|
||||
return rgb
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,23 @@
|
||||
// ViewController.swift
|
||||
// ColorWheel
|
||||
//
|
||||
// Created by 楊昀羲 on 2022/5/4.
|
||||
// Created by 楊昀羲 on 2019/3/8.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class ViewController: UIViewController {
|
||||
|
||||
var colorWheelView: ColorWheelView?
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
// Do any additional setup after loading the view.
|
||||
let size = self.view.frame.size.width
|
||||
let frame = CGRect(x: 0, y: 84, width: size, height: size)
|
||||
|
||||
colorWheelView = ColorWheelView(frame: frame)
|
||||
self.view.addSubview(colorWheelView!)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13142" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12042"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
||||
Reference in New Issue
Block a user