Swift で CSS3 の色を名前で参照する方法

## Swift で CSS3 の色を名前で参照したい

Swift で CSS 3 で使われる色の名前から実際の `UIColor` または `NSColor` を取得する `CSSColor` を紹介します。CSSColor を使えば、W3C の CSS Color Module Level 3 で規定された色の名前を Swift から簡単に利用できるようになります。 


### 色の名前の一覧

```.swift
let names = CSSColor.colorNames // [String]
```

色の名前の一覧を配列として得る事ができます。

### 色の名前から　UIColor または NSColor を取得

```.swift
let color1  = CSSColor.colorNamed("tomato")
let color2  = CSSColor.colorNamed("magenta")
```

名前がはっきりしている場合は、`CSSColor.colorNamed()` で色を取得する事ができます。見つからない場合は `nil` が戻ります。


### メソッド名から取得

```.swift
let color1 = CSSColor.mintcream
let color2 = CSSColor.orchid
```

CSS 3 で規定されている名前付きの色はクラスメソッドで用意されているので、`CSSColor.` の後数文字をタイプすればコード補完が効くので、便利だと思います。

### 色の全名称

全色の名前は以下の通りです。`CSSColor.colorNamed()` からでも利用できますし、`CSSColor.aqua` のように名前で直接参照しても構いません。

| Name | Value |
|:----|:-----|
|aliceblue |#F0F8FF |
|antiquewhite |#FAEBD7 |
|aqua |#00FFFF |
|aquamarine |#7FFFD4 |
|azure |#F0FFFF |
|beige |#F5F5DC |
|bisque |#FFE4C4 |
|black |#000000 |
|blanchedalmond |#FFEBCD |
|blue |#0000FF |
|blueviolet |#8A2BE2 |
|brown |#A52A2A |
|burlywood |#DEB887 |
|cadetblue |#5F9EA0 |
|chartreuse |#7FFF00 |
|chocolate |#D2691E |
|coral |#FF7F50 |
|cornflowerblue |#6495ED |
|cornsilk |#FFF8DC |
|crimson |#DC143C |
|cyan |#00FFFF |
|darkblue |#00008B |
|darkcyan |#008B8B |
|darkgoldenrod |#B8860B |
|darkgray |#A9A9A9 |
|darkgreen |#006400 |
|darkgrey |#A9A9A9 |
|darkkhaki |#BDB76B |
|darkmagenta |#8B008B |
|darkolivegreen |#556B2F |
|darkorange |#FF8C00 |
|darkorchid |#9932CC |
|darkred |#8B0000 |
|darksalmon |#E9967A |
|darkseagreen |#8FBC8F |
|darkslateblue |#483D8B |
|darkslategray |#2F4F4F |
|darkslategrey |#2F4F4F |
|darkturquoise |#00CED1 |
|darkviolet |#9400D3 |
|deeppink |#FF1493 |
|deepskyblue |#00BFFF |
|dimgray |#696969 |
|dimgrey |#696969 |
|dodgerblue |#1E90FF |
|firebrick |#B22222 |
|floralwhite |#FFFAF0 |
|forestgreen |#228B22 |
|fuchsia |#FF00FF |
|gainsboro |#DCDCDC |
|ghostwhite |#F8F8FF |
|gold |#FFD700 |
|goldenrod |#DAA520 |
|gray |#808080 |
|green |#008000 |
|greenyellow |#ADFF2F |
|grey |#808080 |
|honeydew |#F0FFF0 |
|hotpink |#FF69B4 |
|indianred |#CD5C5C |
|indigo |#4B0082 |
|ivory |#FFFFF0 |
|khaki |#F0E68C |
|lavender |#E6E6FA |
|lavenderblush |#FFF0F5 |
|lawngreen |#7CFC00 |
|lemonchiffon |#FFFACD |
|lightblue |#ADD8E6 |
|lightcoral |#F08080 |
|lightcyan |#E0FFFF |
|lightgoldenrodyellow |#FAFAD2 |
|lightgray |#D3D3D3 |
|lightgreen |#90EE90 |
|lightgrey |#D3D3D3 |
|lightpink |#FFB6C1 |
|lightsalmon |#FFA07A |
|lightseagreen |#20B2AA |
|lightskyblue |#87CEFA |
|lightslategray |#778899 |
|lightslategrey |#778899 |
|lightsteelblue |#B0C4DE |
|lightyellow |#FFFFE0 |
|lime |#00FF00 |
|limegreen |#32CD32 |
|linen |#FAF0E6 |
|magenta |#FF00FF |
|maroon |#800000 |
|mediumaquamarine |#66CDAA |
|mediumblue |#0000CD |
|mediumorchid |#BA55D3 |
|mediumpurple |#9370DB |
|mediumseagreen |#3CB371 |
|mediumslateblue |#7B68EE |
|mediumspringgreen |#00FA9A |
|mediumturquoise |#48D1CC |
|mediumvioletred |#C71585 |
|midnightblue |#191970 |
|mintcream |#F5FFFA |
|mistyrose |#FFE4E1 |
|moccasin |#FFE4B5 |
|navajowhite |#FFDEAD |
|navy |#000080 |
|oldlace |#FDF5E6 |
|olive |#808000 |
|olivedrab |#6B8E23 |
|orange |#FFA500 |
|orangered |#FF4500 |
|orchid |#DA70D6 |
|palegoldenrod |#EEE8AA |
|palegreen |#98FB98 |
|paleturquoise |#AFEEEE |
|palevioletred |#DB7093 |
|papayawhip |#FFEFD5 |
|peachpuff |#FFDAB9 |
|peru |#CD853F |
|pink |#FFC0CB |
|plum |#DDA0DD |
|powderblue |#B0E0E6 |
|purple |#800080 |
|red |#FF0000 |
|rosybrown |#BC8F8F |
|royalblue |#4169E1 |
|saddlebrown |#8B4513 |
|salmon |#FA8072 |
|sandybrown |#F4A460 |
|seagreen |#2E8B57 |
|seashell |#FFF5EE |
|sienna |#A0522D |
|silver |#C0C0C0 |
|skyblue |#87CEEB |
|slateblue |#6A5ACD |
|slategray |#708090 |
|slategrey |#708090 |
|snow |#FFFAFA |
|springgreen |#00FF7F |
|steelblue |#4682B4 |
|tan |#D2B48C |
|teal |#008080 |
|thistle |#D8BFD8 |
|tomato |#FF6347 |
|turquoise |#40E0D0 |
|violet |#EE82EE |
|wheat |#F5DEB3 |
|white |#FFFFFF |
|whitesmoke |#F5F5F5 |
|yellow |#FFFF00 |
|yellowgreen |#9ACD32 |


## UIColor, NSColor extension

`CSSColor` を実装するにあたり、`UIColor` または `NSColor` にエクステンションを実装しました。その使い方は以下のような要領です。

```.swift
let color1 = UIColor(hexadecimalString: "#ff0000") // "#rrggbb"
let color2 = UIColor(hexadecimalString: "#ff000080") // "#rrggbbaa"
let color3 = UIColor(hexadecimalString: "#f731") // "#ff773311" と同等
let color4 = UIColor(hexadecimalString: "#248") // "#224488" と同等
let color5 = UIColor(hexadecimalString: "#aAbBcC") // 大文字小文字 OK
```

もちろん規定のフォーマット以外の場合は `UIColor` または `NSColor` を取得する事が出来ず、`nil` を返します。

```.swift
let color6 = UIColor(hexadecimalString: "8A2BE2") // error: missing '#'
let color7 = UIColor(hexadecimalString: "#8A 2B E2") // error: no space please
let color8 = UIColor(hexadecimalString: "Hello World") // error: no kidding
```

もちろん OS X では `NSColor` で同等に使えます。


```.swift
let color1 = NSColor(hexadecimalString: "#a52a2a") // NSColor
```

## おまけ：UIColor と NSColor をどうやって抽象化しているのか？

`CSSColor` では、同じメソッドを呼び出しても、iOSでは `UIColor` を OS X では `NSColor` を戻していますが、`CSSColor` の実装自体は２度書きされているわけではなく、二つのクラスをうまく抽象化しています。実際には、`CSSColor.swift` の冒頭では以下のように定義しています。

```.swift
#if os (OSX)
import Cocoa
typealias XColor = NSColor
#elseif os(iOS)
import UIKit 
typealias XColor = UIColor
#endif
```

これで実装の際には `XColor` を使えば、iOS で `UIColor`、 OS X では `NSColor` として実装されるので、二つのプラットフォームの抽象化には便利です。`UIImage` と `NSImage`、`UIBezierPath` と `NSBezierPath` などにも応用できると思います。もちろん一方のプラットフォームにしか用意されていなメソッドなどは `extension` などで同等な処理を用意してあげるか、割り切って一方だけ用意するかなどの考慮が必要になります。


## おまけ２

実際のメソッド名などを手作業で一つ一つ書いていくには誤操作が混入する可能性もあるし、そもそも面倒なので、`colors.txt` というタブ区切りファイルを用意してあります。

```.colors.txt
aliceblue	#F0F8FF
antiquewhite	#FAEBD7
aqua	#00FFFF
...
```

そして、Playground などで以下のコードを部分的に有効にしたり無効にしたりして、部分的なソースコードやマークダウンのコードを生成させています。ただ、colors.txt 自体は手動で整形しているので、やはりエラーが混入する恐れがあります。

```.swift
extension String {

	func lines() -> [String] {
		var lines = [String]()
		self.enumerateLines { (line, stop) -> () in
			lines.append(line)
		}
		return lines
	}

}

let file = NSBundle.mainBundle().pathForResource("colors", ofType: "txt")!
let text = try! String(contentsOfFile: file)
for line in text.lines() {
	let columns = line.componentsSeparatedByString("\t")
	let name = columns[0]
	let value = columns[1]
	//print("\t\t\"\(name)\": \"\(value)\",")
	//print("\tclass var \(name): XColor { return CSSColor.colorNamed(\"\(name)\")! }")
	//print("|\(name) |\(value) |")
}
```

## サンプルプロジェクト

iOS と OS X 用の Xcode のプロジェクトを用意しました。

<img width="320" alt="Screen Shot (iOS)" src="https://qiita-image-store.s3.amazonaws.com/0/65634/598744b9-7ea6-31fe-2a77-a1cd28e03ed6.png">


<img width="320" alt="Screen Shot (OS X)" src="https://qiita-image-store.s3.amazonaws.com/0/65634/0b66b512-c34b-f7cf-639b-9bfc2a10ff49.png">


## Github

ソースコードは github より入手可能となっています。

https://github.com/codelynx/CSSColor

## フィードバック

誤入力や改善点などを見つけた場合は [Kaz Yoshikawa](kaz.yoshikawa@gmail.com) までご連絡くださいませ。

## License

MIT ライセンスとなっています。