Quartz 2Dプログラミングガイド

Quartz 2D
プログラミングガイド
目次
概要 13
このドキュメントの対象読者 13
この書類の構成 13
関連項目 15
Quartz 2Dの概要 16
ページ 16
描画先:グラフィックスコンテキスト 17
Quartz 2Dの不透過データ型 18
グラフィックス状態 20
Quartz 2Dの座標系 21
メモリ管理:オブジェクトの所有権 23
グラフィックスコンテキスト 24
ビューグラフィックスコンテキストへの描画(iOS) 24
ウインドウグラフィックスコンテキストの生成(Mac OS X) 25
PDFグラフィックスコンテキストの生成 27
ビットマップグラフィックスコンテキストの生成 31
操作可能なピクセル形式 36
アンチエイリアス 37
印刷用グラフィックスコンテキストの取得 38
パス 39
パスの生成と描画 39
パスの構成要素 40
Points 40
直線 40
円弧 41
曲線 41
サブパスを閉じる処理 42
楕円 43
矩形 43
パスの生成 43
パスの描画 45
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
2
目次
線つけに影響を与えるパラメータ 45
パスの線つけをする関数 47
パスの塗りつぶし 48
ブレンドモードの設定 49
パスを用いたクリッピング処理 54
色と色空間 56
色と色空間について 56
アルファ値 57
色空間の生成 58
デバイス非依存の色空間の生成 58
標準色空間の生成 59
デバイス色空間の生成 60
インデックス付き色空間、パターン色空間の生成 60
色の設定と生成 60
レンダリングインテントの設定 62
座標変換 63
Quartzの変換関数について 64
現在の変換行列の修正 64
アフィン変換の生成 67
アフィン変換の評価 68
ユーザ空間からデバイス空間への変換の取得 68
行列の数学的な取り扱い 69
パターン 72
パターンの解剖 72
色付きパターンとステンシル(色なし)パターン 74
タイリング 74
パターンの使い方 75
色付きパターンの描画 76
色付きパターンセルを描画するコールバック関数の記述 76
色付きパターンの色空間の設定 77
色付きパターンの構造の設定 78
色付きパターンを塗りつぶしや線つけのパターンとして指定 79
色付きパターンを用いた描画 80
色付きパターンを用いる完全な描画関数例 80
ステンシルパターンの描画 82
ステンシルパターンセルを描画するコールバック関数の記述 83
ステンシルパターンの色空間の設定 84
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
3
目次
ステンシルパターンの構造の設定 84
ステンシルパターンを塗りつぶしや線つけのパターンとして指定 85
ステンシルパターンを用いた描画 85
ステンシルパターンを用いる完全な描画関数例 85
影 88
影の描画の考え方 88
コンテキストに応じた影のつけ方 89
影の描画 89
グラデーション 92
軸状/放射状のグラデーションの例 93
CGShadingとCGGradientの違い 94
開始点や終了点の先まで塗りつぶしを延長 95
CGGradientオブジェクトの使い方 96
CGShadingオブジェクトの使い方 99
CGShadingオブジェクトで軸状グラデーションを描画するコードの書き方 100
CGShadingオブジェクトで放射状グラデーションを描画するコードの書き方 107
関連項目 112
透明レイヤ 113
透明レイヤの動作の仕組み 113
透明レイヤへの描画 114
Quartz 2Dにおけるデータ管理 116
データをQuartz 2Dに移動 117
Quartz 2Dからデータを移動 119
Quartz 2DとCore Image間でのデータ交換(Mac OS X) 120
ビットマップ画像と画像マスク 122
ビットマップ画像と画像マスクについて 122
ビットマップ画像に関する情報 123
デコード配列 124
ピクセル形式 124
色空間とビットマップレイアウト 124
画像の生成 125
画像の一部を切り抜いて新しい画像を生成 127
ビットマップグラフィックスコンテキストから画像を生成 128
画像マスクの生成 128
画像のマスク処理 129
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
4
目次
画像マスクを使って画像の一部をマスク 129
別の画像を使って画像をマスク 130
色に基づく画像のマスク処理 131
コンテキストにクリッピング領域を設定することにより画像をマスク 133
画像にブレンドモードを適用 134
標準ブレンドモード 135
乗算ブレンドモード 135
スクリーンブレンドモード 135
オーバーレイブレンドモード 136
比較(暗)ブレンドモード 136
比較(明)ブレンドモード 136
覆い焼きブレンドモード 137
焼き込みブレンドモード 137
ソフトライトブレンドモード 137
ハードライトブレンドモード 138
差の絶対値ブレンドモード 138
除外ブレンドモード 138
色相ブレンドモード 139
彩度ブレンドモード 139
カラーブレンドモード 139
輝度ブレンドモード 139
Core Graphicsのレイヤ描画 141
レイヤ描画の動作 141
レイヤを用いた描画 143
CGLayerオブジェクトの生成(既存のグラフィックスコンテキストで初期化) 143
レイヤのグラフィックスコンテキストを取得 144
CGLayerグラフィックスコンテキストへの描画 144
レイヤを描画先グラフィックスコンテキストに描画 144
例:複数のCGLayerオブジェクトを組み合わせて旗を描画 145
PDFドキュメントの生成、表示、変換 151
PDFのオープン/表示 151
PDFページを対象とする座標変換の生成 153
PDFファイルの生成 155
リンクの追加 157
PDFの中身の保護 158
PDFドキュメントの解析 159
PDFドキュメントの構造の調査 159
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
5
目次
PDFコンテンツの解析 160
演算子を処理するコールバック関数の記述 162
演算子表の生成と設定 162
PDFドキュメントのオープン 163
各ページのコンテンツストリームの走査 164
PostScript変換 166
コールバック関数の記述 166
コールバック構造体の値設定 167
PostScript変換器オブジェクトの生成 168
データプロバイダおよびデータコンシューマの生成 168
変換の実行 168
テキスト 170
用語解説 171
書類の改訂履歴 174
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
6
図、表、リスト
Quartz 2Dの概要 16
図 1-1
図 1-2
図 1-3
図 1-4
図 1-5
表 1-1
ペインターモデル 17
Quartzの描画先 17
Quartz 2Dの描画プリミティブで使われる不透過データ型の例 19
Quartzの座標系 21
座標系の変換により鏡像が描画される様子 22
グラフィックス状態として管理するパラメータ 20
グラフィックスコンテキスト 24
図 2-1
図 2-2
図 2-3
図 2-4
表 2-1
リスト 2-1
リスト 2-2
リスト 2-3
リスト 2-4
リスト 2-5
リスト 2-6
CocoaフレームワークのビューにQuartzで描画した様子 25
CGPDFContextCreateWithURLで生成したPDF 27
ビットマップグラフィックスコンテキストから生成し、ウインドウグラフィックスコン
テキストに描画した画像 36
ぎざぎざが見える画像とアンチエイリアスの処理を施した画像の比較 38
ビットマップグラフィックスコンテキストで扱えるピクセル形式 36
ウインドウグラフィックスコンテキストへの描画 25
関数CGPDFContextCreateWithURLでPDFグラフィックスコンテキストを生成するコード
例 27
関数CGPDFContextCreateでPDFグラフィックスコンテキストを生成するコード例 28
PDFグラフィックスコンテキストへの描画 30
ビットマップグラフィックスコンテキストの生成 33
ビットマップグラフィックスコンテキストへの描画 35
パス 39
図 3-1
図 3-2
図 3-3
図 3-4
図 3-5
図 3-6
図 3-7
図 3-8
図 3-9
図 3-10
Quartzのパスを使って描画した図形 39
2つの図形(サブパス)から成るパス 40
クリッピング領域内に描画を制限している様子 40
多数のパス(ランダムに生成した円)を描画した様子 41
2本の接線と半径を指定して円弧を定義 41
多数のパス(ランダムに生成した曲線)を描画した様子 42
2つの制御点を持つ3次ベジエ曲線 42
1つの制御点を持つ2次ベジエ曲線 42
多数のパス(ランダムに生成した楕円)を描画した様子 43
多数のパス(ランダムに生成した矩形)を描画した様子 43
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
7
図、表、リスト
図 3-11
図 3-12
図 3-13
図 3-14
図 3-15
図 3-16
図 3-17
図 3-18
図 3-19
図 3-20
図 3-21
図 3-22
図 3-23
図 3-24
図 3-25
図 3-26
図 3-27
図 3-28
図 3-29
図 3-30
表 3-1
表 3-2
表 3-3
表 3-4
表 3-5
表 3-6
リスト 3-1
線種パターンの例 47
2通りの規則に従って塗りつぶした同心円 48
背景として描画する矩形群 50
背景の上に重ねて描画する矩形群 50
標準ブレンドモードで描画した矩形群 50
乗算ブレンドモードで描画した矩形群 50
スクリーンブレンドモードで描画した矩形群 51
オーバーレイブレンドモードで描画した矩形群 51
比較(暗)ブレンドモードで描画した矩形群 51
比較(明)ブレンドモードで描画した矩形群 51
覆い焼きブレンドモードで描画した矩形群 51
焼き込みブレンドモードで描画した矩形群 52
ソフトライトブレンドモードで描画した矩形群 52
ハードライトブレンドモードで描画した矩形群 53
差の絶対値ブレンドモードで描画した矩形群 53
除外ブレンドモードで描画した矩形群 53
色相ブレンドモードで描画した矩形群 53
彩度ブレンドモードで描画した矩形群 54
カラーブレンドモードで描画した矩形群 54
輝度ブレンドモードで描画した矩形群 54
パスの線つけに影響を与えるパラメータ 45
角の形状(ジョイン) 46
線端形状 46
パスの線つけをする関数 47
パスを塗りつぶす関数 49
グラフィックスコンテキストにクリッピング領域を設定する関数 55
円形のクリッピング領域の設定 55
色と色空間 56
図 4-1
図 4-2
図 4-3
図 4-4
表 4-1
表 4-2
同じ画像にBGRとRGBの色プロファイルを適用した様子 57
アルファ値を変えながら矩形を描画した様子 57
大域アルファ値を変えて描画した画像の比較 57
CMYK色空間とRGB色空間で表現した同じ塗りつぶし色の比較 61
さまざまな色空間において色を表す値 56
色を設定する関数 61
座標変換 63
図 5-1
図 5-2
図 5-3
拡大縮小と回転を施した様子 64
変換を施す前の画像 65
平行移動した画像 65
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
8
図、表、リスト
図 5-4
図 5-5
図 5-6
図 5-7
図 5-8
表 5-1
回転した画像 65
拡大縮小を施した画像 66
平行移動と回転を施した画像 66
平行移動、拡大縮小、回転を施した画像 66
回転、拡大縮小、平行移動を施した画像 67
平行移動、回転、拡大縮小を施すアフィン変換関数 67
パターン 72
図 6-1
図 6-2
図 6-3
図 6-4
図 6-5
図 6-6
図 6-7
図 6-8
図 6-9
図 6-10
リスト 6-1
リスト 6-2
リスト 6-3
リスト 6-4
リスト 6-5
リスト 6-6
リスト 6-7
リスト 6-8
ウインドウにパターンを描画した様子 72
パターンセル 72
パターンセル(黒の矩形は各セルの境界) 72
パターンセルどうしの間隔 72
拡大縮小を施したパターンセル 74
回転を施したパターンセル 74
平行移動を施したパターンセル 74
色付きパターンには色づけがなされている 74
ステンシルパターンには色の指定がない 74
ステンシルパターンセル 83
色付きパターンセルを描画するコールバック関数 77
基盤となるパターン色空間の生成 78
CGPatternCreate関数の仕様 78
色付きパターンを使って描画する関数の例 80
ステンシルパターンセルを描画するコールバック関数 83
ステンシルパターン用のパターン色空間を生成するコード例 84
ステンシルパターンの色を設定するコード 85
ステンシルパターンを使って描画する関数の例 85
影 88
図 7-1
図 7-2
図 7-3
リスト 7-1
影 88
ぼかしのない影と、柔らかいぼかしを入れた影 88
色付きの影、色なしの影 90
影を設定する関数 90
グラデーション 92
図 8-1
図 8-2
図 8-3
図 8-4
図 8-5
図 8-6
45°の軸に沿った軸状グラデーション 93
7つの点と色を指定して生成した軸状グラデーション 93
2つの円の間で徐々に色が変化する放射状グラデーション 93
アルファ成分のみを変化させて生成した放射状グラデーション 94
1点と円周の間で色が徐々に変化する放射状グラデーション 94
入れ子になった放射状グラデーション 94
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
9
図、表、リスト
図 8-7
図 8-8
図 8-9
図 8-10
図 8-11
図 8-12
表 8-1
リスト 8-1
リスト 8-2
リスト 8-3
リスト 8-4
リスト 8-5
リスト 8-6
リスト 8-7
リスト 8-8
リスト 8-9
リスト 8-10
リスト 8-11
リスト 8-12
リスト 8-13
リスト 8-14
リスト 8-15
軸状グラデーションの延長 96
放射状グラデーションの延長 96
CGGradientオブジェクトを使って描画した放射状グラデーション 98
3つの位置を指定して描画した軸状グラデーション 99
軸状グラデーションをクリッピング領域内に描画した様子 100
CGShadingオブジェクトで生成した放射状グラデーション 107
CGShadingとCGGradientの違い 95
CGGradientオブジェクトの生成 97
CGGradientオブジェクトを使って軸状グラデーションを描画 97
CGGradientオブジェクトを使って放射状グラデーションを描画 98
アルファ値が徐々に変化する放射状グラデーションを生成する際に用いた変数 98
グレースケールのグラデーションを生成するために用いた変数 99
色成分の値の計算 101
CGFunctionオブジェクトの生成 102
軸状グラデーションを描画するCGShadingオブジェクトの生成 103
半円形のクリッピング領域をグラフィックスコンテキストに設定 104
オブジェクトの解除 104
CGShadingオブジェクトで軸状グラデーションを描画するコードの書き方 105
色成分の値の計算 107
放射状グラデーションを描画するCGShadingオブジェクトの生成 108
オブジェクトの解除 109
CGShadingオブジェクトで放射状グラデーションを描画するコードの書き方 109
透明レイヤ 113
図 9-1
図 9-2
図 9-3
リスト 9-1
透明レイヤとしてグループ化した3つの円 113
独立したオブジェクトとして描画した3つの円 113
透明レイヤに描画した3つの矩形 114
透明レイヤへの描画 114
Quartz 2Dにおけるデータ管理 116
図 10-1
表 10-1
表 10-2
Quartz 2Dとのデータの受け渡し(Mac OS X) 117
データをQuartz 2Dに移動する関数 118
データをQuartz 2Dから移動する関数 120
ビットマップ画像と画像マスク 122
図 11-1
図 11-2
図 11-3
図 11-4
図 11-5
ビットマップ画像 122
32/16ビットのピクセル形式(CMYK/RGB色空間) 125
大きな画像の一部を切り抜いて生成した画像 127
画像の一部を切り抜き、拡大して描画した様子 127
元の画像 130
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
10
図、表、リスト
図 11-6
図 11-7
図 11-8
図 11-9
図 11-10
図 11-11
図 11-12
図 11-13
図 11-14
図 11-15
図 11-16
図 11-17
図 11-18
図 11-19
図 11-20
図 11-21
図 11-22
図 11-23
図 11-24
図 11-25
図 11-26
図 11-27
図 11-28
図 11-29
図 11-30
図 11-31
図 11-32
図 11-33
表 11-1
リスト 11-1
リスト 11-2
リスト 11-3
リスト 11-4
リスト 11-5
画像マスク 130
元の画像に画像マスクを適用して得られた画像 130
元の画像に別の画像をマスクとして適用して得られた画像 131
クロマキーによるマスク処理 131
元の画像 132
明るい茶色の部分をマスクして作った画像 132
濃茶から黒の部分をマスクして作った画像 132
所定の色範囲の部分をマスクし、塗りつぶし色を設定して作った画像 133
マスクに用いる画像 134
画像マスクでクリッピング領域を設定したコンテキストに画像を描画した様子 134
画像でクリッピング領域を設定したコンテキストに画像を描画した様子 134
背景(左)とその上に合成する画像(右) 135
標準ブレンドモードで画像を描画した結果 135
乗算ブレンドモードで画像を描画した結果 135
スクリーンブレンドモードで画像を描画した結果 136
オーバーレイブレンドモードで画像を描画した結果 136
比較(暗)ブレンドモードで画像を描画した結果 136
比較(明)ブレンドモードで画像を描画した結果 137
覆い焼きブレンドモードで画像を描画した結果 137
焼き込みブレンドモードで画像を描画した結果 137
ソフトライトブレンドモードで画像を描画した結果 138
ハードライトブレンドモードで画像を描画した結果 138
差の絶対値ブレンドモードで画像を描画した結果 138
除外ブレンドモードで画像を描画した結果 139
色相ブレンドモードで画像を描画した結果 139
彩度ブレンドモードで画像を描画した結果 139
カラーブレンドモードで画像を描画した結果 139
輝度ブレンドモードで画像を描画した結果 140
画像を生成する関数 126
画像の一部を切り抜き、拡大して描画するコード例 127
関数CGImageMaskCreateの引数並び 129
明るい茶色の部分をマスクするコード例 132
濃茶から黒の部分をマスクするコード例 132
所定の色範囲の部分をマスクし、塗りつぶし色を設定するコード例 132
Core Graphicsのレイヤ描画 141
図 12-1
図 12-2
図 12-3
同じ蝶の画像を繰り返し描画した様子 141
レイヤ描画 142
2つの矩形とひと続きの線を描画したレイヤ 144
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
11
図、表、リスト
図 12-4
レイヤを反復描画した様子 145
図 12-5
レイヤを利用してアメリカ国旗を描画した結果 145
リスト 12-1 レイヤを利用して旗を描画するコード 146
PDFドキュメントの生成、表示、変換 151
図 13-1
図 13-2
図 13-3
リスト 13-1
リスト 13-2
リスト 13-3
リスト 13-4
Quartzで高品質のPDFドキュメントを生成 151
PDFドキュメント 151
右に90°回転したPDFページ 154
既存のPDFファイルをもとにCGPDFDocumentオブジェクトを生成 151
PDFページの描画 152
PDFページを対象とするアフィン変換の生成 154
PDFファイルの生成 155
PDFドキュメントの解析 159
図 14-1
図 14-2
表 14-1
リスト 14-1
リスト 14-2
リスト 14-3
リスト 14-4
リスト 14-5
PDFファイル中の2つの画像を記述するメタデータ 159
サムネール画像 160
マーク付きコンテンツ演算子(PDF演算子のうち解析可能なもの) 161
PDFのサムネールビューの取得 160
MP演算子を処理するコールバック関数 162
演算子表にコールバック関数を設定 163
URLに基づいてPDFドキュメントをオープン 163
ドキュメントの各ページの走査 164
PostScript変換 166
図 15-1
PostScript変換アプリケーションの進捗状況表示 166
リスト 15-1 PostScript変換器のコールバック構造体 167
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
12
概要
Quartz 2Dは先進的な2次元(2D)描画エンジンです。iOSアプリケーション開発にも、Mac OS Xのカー
ネル外で稼動するアプリケーション環境でも利用できます。低レベルの軽量2Dレンダリング機能を使
うと、画面表示か印刷出力かにかかわらず、高忠実度の出力が可能です。また、出力機器やその解像
度に依存しない、という特性があるので、Quartz 2D API(Application Programming Interface)を使っ
て描画する際、最終的な出力先を意識する必要はありません。
Quartz 2DのAPIは非常に使いやすく、透明レイヤ、パスベースの描画、オフスクリーンレンダリング、
高度な色管理、アンチエイリアスを施したレンダリング、さらにPDFドキュメントの生成、表示、解
析など、さまざまな機能を利用できます。
APIはCore Graphicsフレームワークの一部として組み込まれているので、QuartzのことをCore Graphics
(あるいは省略してCG)と呼ぶこともあります。
このドキュメントの対象読者
この資料は、次のような機能の実装作業に携わる、iOSやMac OS Xの開発者を対象としています。
●
グラフィック描画
●
アプリケーションに組み込む図形編集機能
●
ビットマップ画像の作成、表示
●
PDFドキュメントに対する処理
この書類の構成
このドキュメントは次の章で構成されています。
●
●
“Quartz 2Dの概要” (16 ページ)では、ページ、描画先、Quartzの不透過データ型、グラフィック
ス状態、座標、メモリ管理について説明し、背後でQuartzがどのように働いているのか概観しま
す。
“グラフィックスコンテキスト” (24 ページ)では、各種の「描画先」を挙げ、各種のグラフィッ
クスコンテキストの作成手順を説明します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
13
概要
この書類の構成
●
●
●
●
●
●
●
●
●
●
●
●
●
●
●
“パス” (39 ページ)では、パスを構成する基本要素、パスを生成、描画する手順、クリッピン
グ領域の設定方法、ブレンドモードによる描画結果の違い、といった事項を説明します。
“色と色空間” (56 ページ)では、色を表す値や、透明度を表すアルファ値の使い方について説
明した後、色空間を生成し、色を設定し、色オブジェクトを生成し、レンダリングインテントを
設定する手順について述べます。
“座標変換” (63 ページ)では、「現在の変換行列」の考え方とその値の変更方法を示し、アフィ
ン変換の設定、ユーザ空間とデバイス空間の変換について述べた後、Quartzが実行する数学演算
の背景知識を解説します。
“パターン” (72 ページ)では、パターンおよびその構成要素であるパターンセルについて説明
し、描画方法を指示する方法、色付きパターンやステンシルパターンの生成方法を示します。
“影” (88 ページ)では、影とは何か、どのように生成するかを説明し、描画方法を示します。
“グラデーション” (92 ページ)では、軸状グラデーションと放射状グラデーションについて説
明し、CGShadingオブジェクト、CGGradientオブジェクトの生成方法や使い方を解説します。
“透明レイヤ” (113 ページ)では、透明レイヤがどのように見えるか例を示し、動作原理を解説
した後、具体的な実装手順を説明します。
“Quartz 2Dにおけるデータ管理” (116 ページ)では、Quartzにデータを組み込み、また、これを取
り出す手順を示します。
“ビットマップ画像と画像マスク” (122 ページ)では、ビットマップ画像の構成要素を説明し、
Quartzの描画プリミティブとしてビットマップを使う方法を解説します。さらに、画像の操作技
法のひとつ、「マスク」について説明し、画像を描画する際にブレンドモードをうまく使って実
現できる、さまざまな効果を示します。
“Core Graphicsのレイヤ描画” (141 ページ)では、描画レイヤを利用してパターンを高速描画する
方法、オフスクリーン描画を行う手順を説明します。
“PDFドキュメントの生成、表示、変換” (151 ページ)では、PDFドキュメントを開いて表示し、
変換操作を施し、PDFファイルを生成し、そのメタデータにアクセスし、リンクを追加し、セキュ
リティ機能(パスワード保護など)を施す手順を解説します。
“PDFドキュメントの解析” (159 ページ)では、CGPDFScannerオブジェクト、CGPDFContentStream
オブジェクトを使って、PDFドキュメントを解析する方法を説明します。
“PostScript変換” (166 ページ)では、Mac OS X上でPostScriptファイルをPDFドキュメントに変換す
る機能の概要を示します。ただしiOSでは利用できません。
“テキスト” (170 ページ)では、テキストやグリフを扱うQuartz 2Dの低レベルの機能について説
明した後、高レベルの機能やUnicodeテキストの操作機能を利用するための代替手段を紹介しま
す。さらに、フォントバリエーションのコピー作成についても説明します。
“用語解説” (171 ページ)では、この資料に出てくる用語を解説します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
14
概要
関連項目
関連項目
Quartz 2Dを利用する際は次の資料等も参考になるでしょう。
●
●
●
●
『Quartz 2D Reference Collection 』は、ヘッダファイル別に編成された、Quartz 2D APIの完全なリ
ファレンスになっています。
『Color Management Overview 』では、色の認識、色空間、色管理システムの原理を簡単に紹介し
ています。
メーリングリスト。Quartz 2Dについて議論するメーリングリスト、quartz-devに参加をお勧めし
ます。
「Programming With Quartz: 2D and PDF Graphics in Mac OS X」にはQuartzの使い方に関するさらに
詳しい情報が載っています。同書はMac OS X v10.4までを対象として、iOSの公開前に執筆したも
のです。Mac OS Xの旧版でも動作するようにする方法、v10.4で新たに導入された機能を使う方法
の例が載っています。出版元では同書に載っているコード例を配布しています。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
15
Quartz 2Dの概要
Quartz 2Dは2次元描画エンジンです。iOS環境でも、Mac OS Xのカーネル外で稼動するアプリケーショ
ン環境でも利用できます。Quartz 2D API(Application Programming Interface)を介して、パスベース
の描画、任意の透明度での塗りつぶし、陰影処理、影の描画、透明レイヤ、色管理、アンチエイリア
スを施したレンダリング、PDFドキュメントの生成、PDFメタベースへのアクセスなど、さまざまな
機能を利用できます。さらに、グラフィックスハードウェアが組み込まれている環境では、その能力
を最大限引き出すようになっています。
Mac OS Xでは、Quartz 2Dは他のグラフィックス技術や画像技術(Core Image、Core Video、OpenGL、
QuickTime)とも連携して動作します。したがって、QuickTimeのGraphics Importerで取り込んだ画像を
もとに、QuickTimeの関数GraphicsImportCreateCGImageを呼び出して、Quartz上で使う画像を生成
する、といったことも可能です。詳しくは、『QuickTimeFrameworkReference 』を参照してください。
“Quartz 2DとCore Image間でのデータ交換(Mac OS X)” (120 ページ)では、画像処理に対応したフ
レームワークであるCore Imageに、画像を渡す方法を説明しています。
同様にiOSでも、Quartz 2Dは他のグラフィックス技術やアニメーション技術(Core Animation、OpenGL
ES、UIKitクラス)と連携して動作します。
ページ
Quartz 2Dでは画像処理にペインターモデルを採用しています。このモデルでは、一連の描画操作は、
描画したいもの(ペイント)のレイヤを出力「キャンバス」に重ねる処理に対応します。この「キャ
ンバス」を一般にページと呼びます。ページ上に置いたペイントは、引き続き描画操作を施して別の
ペイントを塗り重ねる、という方法で修正できます。逆に言うと、ページ上に描画したオブジェクト
を修正するためには、ペイントを塗り重ねるしかありません。このモデルでは、ごく少数の強力な描
画プリミティブから、非常に洗練された画像を構築できます。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
16
Quartz 2Dの概要
描画先:グラフィックスコンテキスト
図 1-1にこのモデルの動作原理を示します。図の上側では、まず左側の図を描画し、次に右側の、枠
内をすべて塗りつぶした図を描画しています。その結果、先に描画した図は、縁を除いてまったく見
えなくなってしまいます。図の下側では、順序を逆にし、枠内をすべて塗りつぶした図を先に描画し
ています。このようにペインターモデルでは、描画順序が重要なのです。
図 1-1
ペインターモデル
実際のページは、(出力デバイスがプリンタの場合のように)本物の紙であったり、(出力デバイス
がPDFファイルである場合のように)仮想的な紙であったり、あるいはビットマップ画像であったり
します。ページの具体的な特性は、その時に使っているグラフィックスコンテキストによって決まり
ます。
描画先:グラフィックスコンテキスト
グラフィックスコンテキストは不透過データ型のひとつ(CGContextRef)で、画像を出力デバイス
(PDFファイル、ビットマップ、ディスプレイ上のウインドウなど)に描画するために必要な情報を
カプセル化するものです。グラフィックス描画パラメータと、ページ上に描画した内容をデバイス特
有の形で表現したデータを保持しています。Quartzでは、オブジェクトはすべて、グラフィックスコ
ンテキストに描画する、すなわちデータとして保持させることになります。
図 1-2のように、グラフィックスコンテキストを描画先と同一視してもよいでしょう。Quartzで描画
する際、デバイス特有の特性はすべて、対応する型のグラフィックスコンテキストに設定されていま
す。言い替えると、同じ画像を異なるデバイスに描画する場合、それぞれに応じたグラフィックスコ
ンテキストに対して、同じ描画ルーチンを同じ順序で実行すればよいのです。個々のデバイスに特有
の処理はQuartz側に任せておいて構いません。
図 1-2
Quartzの描画先
次のようなグラフィックスコンテキストがアプリケーションから使えます。
●
●
ビットマップグラフィックスコンテキスト:ここに、RGB、CMYK、グレースケールのいずれかで
表した色を塗って、ビットマップを生成できます。ビットマップとは、ピクセルを矩形に並べた
配列(あるいはラスタ)のことで、各ピクセルは、画像のある特定の点を表します。標本化(サ
ンプリング)された画像 とも言います。詳しくは、“ビットマップグラフィックスコンテキスト
の生成” (31 ページ)を参照してください。
PDFグラフィックスコンテキスト:これを使ってPDFファイルを生成できます。PDFファイルは、
描画内容を一連のコマンドの形で保持しています。ビットマップと比べると、次のような大きな
違いがあります。
●
PDFファイルは、ビットマップと違い、一般に複数のページから成ります。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
17
Quartz 2Dの概要
Quartz 2Dの不透過データ型
●
PDFファイルの内容を異なるデバイスに出力すると、各デバイスの表示特性に合わせて最適
化されます。
●
PDFファイルはその性質上、出力デバイスの解像度に非依存です。制限なく伸縮可能であり、
いくら拡大しても画質が損なわれることはありません。これに対し、ビットマップ画像の画
質は、作成時に意図した解像度と出力デバイスとの関係で変わります。
詳しくは、“PDFグラフィックスコンテキストの生成” (27 ページ)を参照してください。
●
●
●
ウインドウグラフィックスコンテキスト:ウインドウ内に描画するためのグラフィックスコンテ
キストです。Quartz 2Dはグラフィックスエンジンであってウインドウ管理システムではないの
で、何らかのアプリケーションフレームワークを用いて、ウインドウのグラフィックスコンテキ
ストを取得することになります。詳しくは、“ウインドウグラフィックスコンテキストの生成(Mac
OS X)” (25 ページ)を参照してください。
レイヤコンテキスト(CGLayerRef)はオフスクリーンの描画先で、他のグラフィックスコンテ
キストと組み合わせて使います。いったんレイヤに描画しておき、その生成元であるグラフィッ
クスコンテキストに描画内容を転記する際に、最適な性能が得られるようになっています。この
目的で使うのであればビットマップグラフィックスコンテキストよりも優れています。詳しく
は、“Core Graphicsのレイヤ描画” (141 ページ)を参照してください。
Mac OS Xでは、印刷したい場合、印刷フレームワークが管理するPostScriptグラフィックスコンテ
キストに描画内容を送信します。詳しくは、“印刷用グラフィックスコンテキストの取得” (38 ペー
ジ)を参照してください。
Quartz 2Dの不透過データ型
Quartz 2D APIには、グラフィックスコンテキスト以外にもさまざまな不透過データ型が定義されてい
ます。APIはCore Graphicsフレームワークの一部となっているので、データ型や、これを操作するルー
チンには、「CG」という接頭辞がついています。
Quartz 2Dを利用するアプリケーションは、不透過データ型のオブジェクトを生成し、これを操作する
ことにより所定の描画出力を得るようになっています。図 1-3に、Quartz 2Dに組み込まれた3種類の
(不透過データ型)オブジェクトの例と、これに対して描画操作を施して得られる出力を示します。
●
●
図形を回転してPDFのページに出力することが可能です。PDFページオブジェクトを生成し、グラ
フィックスコンテキストに回転操作を施した後、ページをグラフィックスコンテキストに描画す
るようQuartz 2Dに指示します。
パターンを描画できます。パターンオブジェクトを生成し、パターンの構成要素の形状を定義し
た上で、グラフィックスコンテキストに描画する際、塗りつぶしにこのパターンを使うよう設定
します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
18
Quartz 2Dの概要
Quartz 2Dの不透過データ型
●
領域を塗りつぶす際、軸状または放射状のグラデーションを適用できます。グラデーションオブ
ジェクトを生成し、各点の塗り方を決める関数を設定し、塗りつぶし色としてこのグラデーショ
ンを適用するよう指示します。
図 1-3
Quartz 2Dの描画プリミティブで使われる不透過データ型の例
ほかにもQuartz 2Dには、次のような不透過データ型が定義されています。
●
CGPathRef:ベクトル画像の描画に必要な、塗りつぶす(フィル)、あるいは線つけする(スト
ローク)パスを生成します。“パス” (39 ページ)を参照してください。
●
CGImageRef:ビットマップ画像やビットマップ画像マスクを表します。サンプルデータを渡し
て生成します。“ビットマップ画像と画像マスク” (122 ページ)を参照してください。
●
CGLayerRef:描画レイヤを表し、(背景やパターンの)反復描画や、オフスクリーン描画に使
います。“Core Graphicsのレイヤ描画” (141 ページ)を参照してください。
●
CGPatternRef:ある画像(パターン)を反復描画するために使います。“パターン” (72 ペー
ジ)を参照してください。
●
CGShadingRef、CGGradientRef:グラデーションを施した塗りつぶしに使います。“グラデー
ション” (92 ページ)を参照してください。
●
CGFunctionRef:引数として任意の数の浮動小数点数を取るコールバック関数を定義するために
使います。シェーディング(グラデーションをより細かく制御できるようにしたもの)を生成す
る際に必要となるデータ型です。“グラデーション” (92 ページ)を参照してください。
●
CGColorRef、CGColorSpaceRef:色値の解釈方法を指示するために使います。“色と色空
間” (56 ページ)を参照してください。
●
CGImageSourceRef、CGImageDestinationRef:Quartzにデータを組み込み、または取り出すた
めに使います。“Quartz 2Dにおけるデータ管理” (116 ページ)および『Image I/O Programming
Guide 』を参照してください。
●
CGFontRef:テキストの描画に使います。“テキスト” (170 ページ)を参照してください。
●
CGPDFDictionaryRef、CGPDFObjectRef、CGPDFPageRef、CGPDFStream、CGPDFStringRef、
CGPDFArrayRef:PDFメタデータにアクセスするために使います。“PDFドキュメントの生成、表
示、変換” (151 ページ)を参照してください。
●
CGPDFScannerRef、CGPDFContentStreamRef:PDFメタデータの解析に使います。“PDFドキュメ
ントの解析” (159 ページ)を参照してください。
●
CGPSConverterRef:PostScriptをPDFに変換するために使います。iOSでは利用できません。
“PostScript変換” (166 ページ)を参照してください。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
19
Quartz 2Dの概要
グラフィックス状態
グラフィックス状態
描画処理の結果に影響を与えるものとして、現在のグラフィックス状態のパラメータがあります。描
画ルーチンに、あるパラメータを引数として明示的に指定しなかった場合、グラフィックス状態の設
定値が代わりに使われます。グラフィックスコンテキストに描画するルーチンは、グラフィックス状
態を参照してレンダリング方法を決めるのです。たとえば、塗りつぶし色の設定関数を呼び出すと、
現在のグラフィックス状態の設定値が修正されます。ほかにも、線幅、現在位置、テキストのフォン
トサイズなどさまざまなパラメータが、現在のグラフィックス状態として管理されます。
グラフィックスコンテキストでは、グラフィックス状態をスタックに積んで管理します。グラフィッ
クスコンテキストを生成した時点では、スタックは空です。グラフィックス状態の保存を指示する
と、Quartzの内部では、現在のグラフィックス状態のコピーをスタックに積みます。その後、グラ
フィックス状態を復元するよう指示すると、スタックの一番上に積んであるグラフィックス状態を降
ろし、これを現在のグラフィックス状態として復元するようになっています。
現在のグラフィックス状態を保存する際には、関数CGContextSaveGStateを呼び出して、そのコピー
をスタックに積みます。直前に保存したグラフィックス状態を復元するためには、関数
CGContextRestoreGStateを呼び出して、スタックの頂上に積まれているグラフィックス状態を降ろ
し、これを現在のグラフィックス状態として置き換えることになります。
なお、描画環境に影響を与えるパラメータのすべてが、グラフィックス状態として管理されているわ
けではありません。たとえば「現在のパス」は、グラフィックス状態として管理する対象ではないの
で、関数CGContextSaveGStateを呼び出しても保存されないのです。この関数を呼び出したときに
保存されるグラフィックス状態のパラメータを表 1-1に示します。
表 1-1
グラフィックス状態として管理するパラメータ
パラメータ
解説している章
現在の変換行列(CTM)
“座標変換” (63 ページ)
クリッピング領域
“パス” (39 ページ)
線:幅、角の形状(ジョイン)、線端形状
(キャップ)、線種(ダッシュ)、角の限度(マ
イターリミット)
“パス” (39 ページ)
曲線推定(平坦度)の精度
“パス” (39 ページ)
アンチエイリアスの設定
“グラフィックスコンテキスト” (24 ペー
ジ)
色:塗りつぶし(フィル)と線つけ(ストロー
ク)の設定
“色と色空間” (56 ページ)
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
20
Quartz 2Dの概要
Quartz 2Dの座標系
パラメータ
解説している章
アルファ値(透明度)
“色と色空間” (56 ページ)
レンダリングインテント
“色と色空間” (56 ページ)
色空間:塗りつぶし(フィル)と線つけ(スト
ローク)の設定
“色と色空間” (56 ページ)
テキスト:フォント、フォントサイズ、文字間の
間隔、テキスト描画モード
“テキスト” (170 ページ)
ブレンドモード
“パス” (39 ページ)、“ビットマップ画
像と画像マスク” (122 ページ)
Quartz 2Dの座標系
座標系(図 1-4を参照)は平面上の位置の表し方を定義するもので、ページ上に描画するオブジェク
トの位置や大きさを表すために使います。グラフィックスの位置や大きさは、ユーザ空間座標系(あ
るいは単にユーザ空間)で指定します。座標の値はすべて浮動小数点数で表します。
図 1-4
Quartzの座標系
デバイスによって画像処理能力は異なるので、グラフィックスの位置や大きさは、デバイスに依存し
ない方法で指定しなければなりません。たとえば、スクリーン表示デバイスは高々96ピクセル/イン
チの解像度でしか描画できないのに対し、プリンタは300ピクセル/インチでの印刷が可能です。デバ
イスに依存して(この例で言えば96ピクセル/インチあるいは300ピクセル/インチ単位の)座標系を定
義すると、同じオブジェクトを他のデバイスに描画したとき、想定よりも小さく出力される、あるい
は逆に大きくなってしまうことになるのです。
Quartzではデバイス非依存性を実現するため、独立した座標系(ユーザ空間)を用意し、現在の変換
行列(CTM、Current Transformation Matrix)を使って出力デバイスの座標系(デバイス空間)に写像
しています。行列は数学の「言葉」のひとつで、変換式をコンパクトに表現、記述することができま
す。現在の変換行列は、アフィン変換と呼ばれる特殊な行列で、平行移動、回転、拡大縮小の演算
(座標系を移動、回転、拡大縮小する計算)を施すことにより、ある座標系の点を別の座標系に写像
するために使います。
現在の変換行列にはもうひとつ、オブジェクトの描画方法を変換する、という使い方もあります。た
とえば45°傾いた矩形を描画する場合、ページの座標系を回転するようCTMを設定した後、普通に矩形
を描画すればよいことになります。Quartzは回転した座標系を使って出力デバイスに描画します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
21
Quartz 2Dの概要
Quartz 2Dの座標系
ユーザ空間上の点は、座標値の組(x , y )で表します。x は横軸(左右)方向の位置、y は縦軸方向(上
下)の位置です。ユーザ座標空間の原点とは、点(0, 0)のことであり、ページの左下隅にあります(図
1-4 (21 ページ)を参照)。Quartzの既定の座標系では、x軸の値はページの左から右に向かって増
えるようになっています。同様にy軸の値は、下から上に向かって増えます。
Quartzとは異なる座標系を既定の座標系としてグラフィックスコンテキストを設定するシステムもい
くつかあります。Quartzを基準とすればこれは修正座標系なので、何らかの補正をしてから描画する
必要があります。よく目にする修正座標系としては、原点がコンテキストの左上隅にあり、y軸の値
が上から下に向かって増えていく、というものがあります。これはたとえば次のようなところで使わ
れています。
●
(Mac OS X)NSViewのisFlippedメソッドをオーバーライドしてYESを返すようにしたサブクラ
ス。
●
(iOS)UIViewが返す描画コンテキスト。
●
(iOS)関数UIGraphicsBeginImageContextWithOptionsで生成する描画コンテキスト。
UIKitが返す描画コンテキストが修正座標系になっているのは、UIKitで座標を取り扱う規約がQuartzと
は異なるからです。そこで、この規約に合致するよう、生成したQuartzコンテキストに変換を施して
います。アプリケーションを開発する際、同じ描画ルーチンでUIViewオブジェクトとPDFグラフィッ
クスコンテキスト(Quartzで生成した、既定の座標系を用いるもの)の両方に描画したい場合は、PDF
グラフィックスコンテキストも同じ修正座標系になるよう、変換を施す必要があります。具体的に
は、原点をPDFコンテキストの左上隅に移動し、y座標の値に-1を掛ける、という変換です。
y座標の向きを反転する変換により、描画に関するQuartz側の規約にも影響があります。たとえば、関
数CGContextDrawImageでコンテキストに画像を描画すると、その画像には変換が施されます。同様
に、パス描画ルーチンには円弧の向き(時計回りか反時計回りか)を引数で指定しますが、この向き
は既定の 座標系を想定したものです。修正座標系であれば円弧の向きも変わります。画像が鏡像にな
るのと同じことです。図 1-5に、同じ引数を指定して描画しても、既定の座標系では時計回り、y座標
を反転した修正座標系では反時計回りになる様子を示します。
図 1-5
座標系の変換により鏡像が描画される様子
コンテキストに変換が設定されている場合、Quartzの関数を呼び出す際に適切な調整をするのはアプ
リケーション側の責任です。たとえば、画像やPDFがグラフィックスコンテキストに正しく描画され
るよう、そのCTMを一時的に変更する必要があるかもしれません。iOSの場合、生成したUIImageオブ
ジェクトをCGImageオブジェクトでラップすれば、CTMを修正する必要はありません。UIImageオブ
ジェクトが自動的に、UIKitが適用した修正座標系を補正するからです。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
22
Quartz 2Dの概要
メモリ管理:オブジェクトの所有権
Important: iOS上で、Quartzを直接操作するアプリケーションを開発する場合、以上の点を理解し
ておくことが大切ですが、これだけで充分ではありません。iOS 3.2以降、UIKitはアプリケーション
用に描画コンテキストを生成する際、既定のUIKitの規約に合わせてさらにコンテキストを修正す
るようになりました。特にパターンや影は、CTMの影響を受けないものですが、UIKitの座標系に合
わせて個別に調整されます。UIKit側の振る舞いに合わせてQuartz側のコンテキストを調整する、
CTMのような簡便な機構はありません。アプリケーション側で描画先コンテキストの種類を認識
し、調整する必要があるのです。
メモリ管理:オブジェクトの所有権
QuartzはCore Foundationのメモリ管理モデルを採用しているので、オブジェクトは参照カウントの対
象になります。Core Foundationのオブジェクトを生成した時点では、参照カウントの値は1です。オ
ブジェクトを保持(retain)する関数を呼び出すことによりこの値を増やし、また、解除(release)
する関数を呼び出すことにより値を減らすことができます。解除(release)した結果、参照カウント
の値が0になると、オブジェクトは解放(free)されます。このモデルには、オブジェクトが他のオブ
ジェクトへの参照を安全に共有できる、という利点があります。
次の規則を頭に入れておいてください。
●
●
●
オブジェクトを生成または複製すれば、それを所有することになるので、自らの責任で解除しな
ければなりません。一般に、「Create」や「Copy」という語が名前に含まれる関数でオブジェク
トを取得した場合、使用後は解除する必要があります。これを怠るとメモリリークが発生する恐
れがあります。
「Create」や「Copy」という語が名前に含まれない関数でオブジェクトを取得した場合、そのオ
ブジェクトへの参照を所有してはいないので、解除してはいけません。代わりにその所有者が、
将来のある時点で解除します。
自分が所有しているのではないオブジェクトを、一定の期間使う必要がある場合は、これを保持
し、使い終わった時点で解除します。保持や解除には、オブジェクトの種類ごとに用意された
Quartz 2Dの関数を使います。たとえばCGColorSpaceオブジェクトの参照を受け取った場合、必要
に応じ、関数CGColorSpaceRetainやCGColorSpaceReleaseでこれを保持、解除します。Core
Foundationの関数であるCFRetainやCFReleaseを使っても構いませんが、NULLを渡さないよう注
意してください。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
23
グラフィックスコンテキスト
グラフィックスコンテキストは、描画先と(論理的に)同じものに相当します。描画コマンドの実行
に必要な、描画パラメータやデバイス特有の情報を保持しています。たとえば、描画時に使用する
色、クリッピング領域、線の幅やスタイル、フォント、画像の合成オプションなど、基本的な描画属
性を定義しています。
グラフィックスコンテキストの取得には、Quartzのコンテキスト生成関数、またはMac OS Xフレーム
ワークやiOSのUIKitフレームワークが提供する高レベルの関数を使います。Quartzには、ビットマップ
やPDFなど、各種のグラフィックスコンテキストを扱う関数が付属しており、これを使って独自のコ
ンテンツを作成できます。
この章では、描画先に応じた各種のグラフィックスコンテキストを生成する手順を解説します。コー
ド上では、グラフィックスコンテキストはCGContextRefという型で表されます。これは不透過デー
タ型です。取得したグラフィックスコンテキストに対し、Quartz 2Dの関数を使って、図形を描画し、
(平行移動などの)操作を施し、グラフィックス状態のパラメータ(線幅、塗りつぶし色など)を変
更することができます。
ビューグラフィックスコンテキストへの描画(iOS)
iOSアプリケーションで画面に描画するためには、UIViewオブジェクトをセットアップし、実際に描
画を行うdrawRect:メソッドを実装する必要があります。ビューのdrawRect:メソッドは、ビューが
画面上に現れ、その中身を更新する必要が生じた時点で呼び出されます。カスタムのdrawRect:メ
ソッドを呼び出す前に、ビューオブジェクトは自動的に描画環境を設定し、コードがただちに描画を
開始できるようにします。描画環境の設定の一環として、UIViewオブジェクトは、現在の描画環境
に対応するグラフィックスコンテキスト(CGContextRef不透過型)を作成します。drawRect:メソッ
ドでは、UIKitの関数UIGraphicsGetCurrentContextを使って、このグラフィックスコンテキストを
取得します。
UIKitで一貫して使われる既定の座標系は、Quartzの座標系とは違います。原点が左上隅にあり、y軸は
下向きが正になるのです。UIViewオブジェクトは、QuartzグラフィックスコンテキストのCTMを修正
して、UIKitの規約に合わせます。原点をビューの左上隅に移動し、y軸の値に-1を掛けて向きを反転
しているのです。修正座標系とその描画コードに対する影響については、“Quartz 2Dの座標系” (21 ペー
ジ)を参照してください。
UIViewオブジェクトについては、『View Programming Guide for iOS 』に詳しく説明されています。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
24
グラフィックスコンテキスト
ウインドウグラフィックスコンテキストの生成(Mac OS X)
ウインドウグラフィックスコンテキストの生成(Mac OS X)
Mac OS Xで描画する際には、フレームワークに応じたウインドウグラフィックスコンテキストを生成
する必要があります。Quartz 2D API自体に、このグラフィックスコンテキストを取得する関数はあり
ません。Cocoaフレームワークを使い、Cocoaで生成したウインドウのコンテキストを取得することに
なります。
Quartzグラフィックスコンテキストを、CocoaアプリケーションのdrawRect:ルーチン内で、次のよう
なコードで取得します。
CGContextRef myContext = [[NSGraphicsContext currentContext] graphicsPort];
メソッドcurrentContextは、現在のスレッドのNSGraphicsContextインスタンスを返します。メ
ソッドgraphicsPortが返すのは、レシーバによって表される低レベルでプラットフォーム特有のグ
ラフィックスコンテキストで、これがQuartzのグラフィックスコンテキストになります(メソッド名
が紛らわしいのですが、これは歴史的理由でそうなっています)。詳細については、『NSGraphicsContext
Class Reference 』を参照してください。
グラフィックスコンテキストを取得すると、Cocoaアプリケーション内で、Quartz 2Dの描画関数を自
由に呼び出せるようになります。また、Quartz 2DとCocoaの描画関数を組み合わせて使うことも可能
です。CocoaのビューにQuartz 2Dで描画した例を図 2-1に示します。ここでは、不透明の赤い矩形の
一部に、透明な青い矩形を重ねて描画しています。透明度については、“色と色空間” (56 ページ)
を参照してください。どの位「透けて見える」かを制御できる点は、Quartz 2Dの特徴的な機能です。
図 2-1
CocoaフレームワークのビューにQuartzで描画した様子
図 2-1のように描画する手順を説明しましょう。まず、CocoaアプリケーションのXcodeプロジェクト
を生成します。Interface Builderで、Custom Viewをウインドウにドラッグし、そのサブクラスを定義し
てください。このサブクラスに、描画処理をリスト 2-1のように実装します。この例では、ビューの
サブクラスにMyQuartzViewという名前を与えています。そのdrawRect:メソッドに、Quartzの描画
コードをすべて実装します。コード例を示した後、番号がついている行について詳しく説明します。
注意: クラスのdrawRect:NSViewメソッドは、ビューの描画が必要になる都度、自動的に
呼び出されます。drawRect:メソッドのオーバーライドについて詳しくは、『NSView Class
Reference 』を参照してください。
リスト 2-1
ウインドウグラフィックスコンテキストへの描画
@implementation MyQuartzView
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
25
グラフィックスコンテキスト
ウインドウグラフィックスコンテキストの生成(Mac OS X)
- (id)initWithFrame:(NSRect)frameRect
{
self = [super initWithFrame:frameRect];
return self;
}
- (void)drawRect:(NSRect)rect
{
CGContextRef myContext = [[NSGraphicsContext
// 1
currentContext] graphicsPort];
// ********** Your drawing code here **********
// 2
CGContextSetRGBFillColor (myContext, 1, 0, 0, 1);
// 3
CGContextFillRect (myContext, CGRectMake (0, 0, 200, 100 ));
// 4
CGContextSetRGBFillColor (myContext, 0, 0, 1, .5);
// 5
CGContextFillRect (myContext, CGRectMake (0, 0, 100, 200));
// 6
}
@end
このコードが実行することを以下に示します。
1.
ビューのグラフィックスコンテキストを取得します。
2.
ここに描画コードを記述します。以降の4行はQuartz 2D関数の使用例になっています。
3.
塗りつぶし色として、完全に不透明な赤を設定します。色とアルファ値(透明度)については、
“色と色空間” (56 ページ)を参照してください。
4.
矩形を描画します。その原点は(0,0)、幅は200、高さは100です。矩形の描画については、“パ
ス” (39 ページ)を参照してください。
5.
塗りつぶし色として、半透明の青を設定します。
6.
矩形を描画します。その原点は(0,0)、幅は100、高さは200です。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
26
グラフィックスコンテキスト
PDFグラフィックスコンテキストの生成
PDFグラフィックスコンテキストの生成
PDFグラフィックスコンテキストを生成してそこに描画すると、対応する一連のPDF描画コマンドが
ファイルに記録されます。描画に際しては、PDF出力先と、既定のメディアボックス(ページ境界を
表す矩形)を指定します。図 2-2に、PDFグラフィックスコンテキストに描画した後、PDFを生成し、
プレビュー(Preview)で開いた様子を示します。
図 2-2
CGPDFContextCreateWithURLで生成したPDF
Quartz 2D APIにはPDFグラフィックスコンテキストを生成する関数が2つあります。
CGPDFContextCreateWithURLは、PDFの出力先をCore Foundation URLで指定したい場合に使いま
●
す。リスト 2-2 (27 ページ)に、この関数でPDFグラフィックスコンテキストを生成する方法を
示します。
CGPDFContextCreateは、PDFの出力先をデータコンシューマとしたい場合に使います(詳しく
●
は、“Quartz 2Dにおけるデータ管理” (116 ページ)を参照)。リスト 2-3 (28 ページ)に、この
関数でPDFグラフィックスコンテキストを生成する方法を示します。
コード例を示した後、番号がついている行について詳しく説明します。
iOSにおける注意事項: iOSのPDFグラフィックスコンテキストでは、Quartzの既定の座標系
をそのまま使います。UIKitの座標系に合わせて変換することはありません。PDFグラフィッ
クスコンテキストと、UIViewオブジェクトのグラフィックスコンテキストとで、同じ描画
コードを共有したい場合は、PDFグラフィックスコンテキストのCTMを設定し直して、座標
系を修正する必要があります。“Quartz 2Dの座標系” (21 ページ)を参照してください。
リスト 2-2
関数CGPDFContextCreateWithURLでPDFグラフィックスコンテキストを生成するコード例
CGContextRef MyPDFContextCreate (const CGRect *inMediaBox,
CFStringRef path)
{
CGContextRef myOutContext = NULL;
CFURLRef url;
url = CFURLCreateWithFileSystemPath (NULL,
path,
kCFURLPOSIXPathStyle,
false);
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
27
// 1
グラフィックスコンテキスト
PDFグラフィックスコンテキストの生成
if (url != NULL) {
myOutContext = CGPDFContextCreateWithURL (url,
// 2
inMediaBox,
NULL);
CFRelease(url);
// 3
}
return myOutContext;
// 4
}
このコードが実行することを以下に示します。
1.
Core Foundationの関数を使ってCFURLオブジェクトを生成します。関数MyPDFContextCreateに
引数として渡されたCFStringオブジェクトを、パス(第2引数)として指定します。第1引数には
NULLを指定して、既定のアロケータを使うよう指示しています。また、パスの形式も指定しま
す。この例ではPOSIXスタイルのパス名を指定しています。
2.
Quartz 2Dの関数を使ってPDFグラフィックスコンテキストを生成します。引数として、PDF出力
先(先に生成したCFURLオブジェクト)と、PDFの境界を表す矩形を渡します。矩形(CGRect)
は関数MyPDFContextCreateに引数として渡されたもので、PDFの既定のページメディア境界ボッ
クスです。
3.
CFURLオブジェクトを解除します。
4.
PDFグラフィックスコンテキストを返します。グラフィックスコンテキストは、不要になった時
点で呼び出し元が解除しなければなりません。
リスト 2-3
関数CGPDFContextCreateでPDFグラフィックスコンテキストを生成するコード例
CGContextRef MyPDFContextCreate (const CGRect *inMediaBox,
CFStringRef path)
{
CGContextRef
myOutContext = NULL;
CFURLRef
url;
CGDataConsumerRef
dataConsumer;
url = CFURLCreateWithFileSystemPath (NULL,
path,
kCFURLPOSIXPathStyle,
false);
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
28
// 1
グラフィックスコンテキスト
PDFグラフィックスコンテキストの生成
if (url != NULL)
{
dataConsumer = CGDataConsumerCreateWithURL (url);
// 2
if (dataConsumer != NULL)
{
myOutContext = CGPDFContextCreate (dataConsumer,
// 3
inMediaBox,
NULL);
CGDataConsumerRelease (dataConsumer);
// 4
}
CFRelease(url);
// 5
}
return myOutContext;
// 6
}
このコードが実行することを以下に示します。
1.
Core Foundationの関数を使ってCFURLオブジェクトを生成します。関数MyPDFContextCreateに
引数として渡されたCFStringオブジェクトを、パス(第2引数)として指定します。第1引数には
NULLを指定して、既定のアロケータを使うよう指示しています。また、パスの形式も指定しま
す。この例ではPOSIXスタイルのパス名を指定しています。
2.
CFURLオブジェクトを引数として渡し、Quartzデータコンシューマオブジェクトを生成します。
PDFデータの出力先がCFURLオブジェクトでは指定できないなどの場合、CFURLオブジェクトを使
う代わりに、別途実装したコールバック関数を組み合わせて、データコンシューマを生成するこ
とも可能です。詳しくは、“Quartz 2Dにおけるデータ管理” (116 ページ)を参照してください。
3.
Quartz 2Dの関数を使ってPDFグラフィックスコンテキストを生成します。引数として、データコ
ンシューマと、CGRect関数に渡された矩形(MyPDFContextCreate型)を指定します。この矩形
は、PDFの既定のページメディア境界ボックスです。
4.
データコンシューマを解除します。
5.
CFURLオブジェクトを解除します。
6.
PDFグラフィックスコンテキストを返します。グラフィックスコンテキストは、不要になった時
点で呼び出し元が解除しなければなりません。
リスト 2-4に、MyPDFContextCreateルーチンを呼び出して実際に描画する例を示します。コード例
を示した後、番号がついている行について詳しく説明します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
29
グラフィックスコンテキスト
PDFグラフィックスコンテキストの生成
リスト 2-4
PDFグラフィックスコンテキストへの描画
CGRect mediaBox;
// 1
mediaBox = CGRectMake (0, 0, myPageWidth, myPageHeight);
// 2
myPDFContext = MyPDFContextCreate (&mediaBox, CFSTR("test.pdf"));
// 3
CFStringRef myKeys[1];
// 4
CFTypeRef myValues[1];
myKeys[0] = kCGPDFContextMediaBox;
myValues[0] = (CFTypeRef) CFDataCreate(NULL,(const UInt8 *)&mediaBox, sizeof
(CGRect));
CFDictionaryRef pageDictionary = CFDictionaryCreate(NULL, (const void **)
myKeys,
(const void **) myValues,
1,
&kCFTypeDictionaryKeyCallBacks,
&
kCFTypeDictionaryValueCallBacks);
CGPDFContextBeginPage(myPDFContext, &pageDictionary);
// ********** Your drawing code here **********
// 5
// 6
CGContextSetRGBFillColor (myPDFContext, 1, 0, 0, 1);
CGContextFillRect (myPDFContext, CGRectMake (0, 0, 200, 100 ));
CGContextSetRGBFillColor (myPDFContext, 0, 0, 1, .5);
CGContextFillRect (myPDFContext, CGRectMake (0, 0, 100, 200 ));
CGPDFContextEndPage(myPDFContext);
// 7
CFRelease(pageDictionary);
// 8
CFRelease(myValues[0]);
CGContextRelease(myPDFContext);
このコードが実行することを以下に示します。
1.
矩形を表す変数を宣言します。これはPDFメディアボックスの定義に使います。
2.
メディアボックスの原点を(0,0)、幅と高さをアプリケーションで別途指定された値に設定しま
す。
3.
関数MyPDFContextCreate(リスト 2-3 (28 ページ)を参照)を使ってPDFグラフィックスコン
テキストを取得します。このとき、引数としてメディアボックスとパス名を渡します。マクロ
CFSTRは文字列をCFStringRefデータ型に変換します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
30
グラフィックスコンテキスト
ビットマップグラフィックスコンテキストの生成
4.
辞書にページオプションを設定します。この例ではメディアボックスだけを指定しています。PDF
グラフィックスコンテキストのセットアップに使ったのと同じ矩形を渡す必要はありません。こ
こで追加設定したメディアボックスが優先して使われるからです。
5.
ページを開始する旨の合図を送ります。この関数は、PDFをはじめとする、ページの概念がある
媒体へのグラフィックス処理に使います。
6.
Quartz 2Dの描画関数を呼び出します。これ以降の5行は、アプリケーションに応じた実際の描画
コードで置き換えてください。
7.
PDFページを終了する旨の合図を送ります。
8.
辞書とPDFグラフィックスコンテキストは不要になったので、ここで解除します。
アプリケーションの機能に応じ、画像、テキスト、パスなど、どのような内容でもPDFに出力できま
す。リンクの追加や暗号化も可能です。詳しくは、“PDFドキュメントの生成、表示、変換” (151 ペー
ジ)を参照してください。
ビットマップグラフィックスコンテキストの生成
ビットマップグラフィックスコンテキストは、メモリバッファ(ビットマップデータ用のストレージ
空間)を指すポインタを渡して生成します。このグラフィックスコンテキストに対して描画すると、
実際にはバッファの内容が更新されます。グラフィックスコンテキストを解除しても、所定のピクセ
ル形式で、内容が更新済みのビットマップが、バッファに残っています。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
31
グラフィックスコンテキスト
ビットマップグラフィックスコンテキストの生成
注意: ビットマップグラフィックスコンテキストを、オフスクリーン描画のために使うこと
も可能です。この目的で使うのが適切かどうか判断する際には、“Core Graphicsのレイヤ描
画” (141 ページ)を参照してください。CGLayerオブジェクト(CGLayerRef)は、オフスク
リーン描画用に、できるだけビデオカードにレイヤをキャッシュするよう最適化されていま
す。
iOSにおける注意事項: iOSアプリケーションは、ここで説明する低レベルのQuartz関数では
なく、関数UIGraphicsBeginImageContextWithOptionsを使うようにしてください。Quartz
側でオフスクリーンビットマップを生成すると、ビットマップグラフィックスコンテキスト
が使う座標系は、Quartzの既定の座標系になります。一方、関数
UIGraphicsBeginImageContextWithOptionsで画像コンテキストを生成すれば、UIViewオ
ブジェクトのグラフィックスコンテキストに対するのと同じ変換が、コンテキストの座標系
に適用されるようになります。したがって、座標系の違いを意識することなく、どちらにも
同じ描画コードが使えるのです。座標変換行列を別途調整して同じ結果を得ることも可能で
すが、そうしたからと言って性能上の利点はありません。
ビットマップグラフィックスコンテキストの生成には関数CGBitmapContextCreateを使います。こ
の関数は次の引数を取ります。
●
data - メモリ上のバッファを指すポインタ。描画すると、この領域が更新されることになりま
す。メモリブロックの大きさは(bytesPerRow×height)バイト以上必要です。
●
width - ビットマップの幅をピクセル単位で指定。
●
height - ビットマップの高さをピクセル単位で指定。
●
bitsPerComponent - メモリ上でピクセルの各成分に割り当てるビット数を指定。たとえば32ビッ
トのピクセル形式で、色空間としてRGBを用いる場合、各成分に8ビットの値を指定することにな
ります。“操作可能なピクセル形式” (36 ページ)を参照してください。
●
bytesPerRow - ビットマップの各行に対して割り当てるメモリのバイト数。
ヒント: ビットマップグラフィックスコンテキストを生成する際、データやbytesPerRow
を16バイト境界に揃えると、処理性能が向上します。
●
colorspace - ビットマップ画像の色空間。Gray、RGB、CMYK、NULLのいずれかを指定します。
色空間や色管理の原理について詳しくは、『Color Management Overview 』を参照してください。
Quartzで色空間を生成、利用する方法は、“色と色空間” (56 ページ)に説明されています。適用
可能な色空間については、“ビットマップ画像と画像マスク” (122 ページ)の“色空間とビットマッ
プレイアウト” (124 ページ)を参照してください。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
32
グラフィックスコンテキスト
ビットマップグラフィックスコンテキストの生成
bitmapInfo - ビットマップのレイアウト情報をCGBitmapInfo定数で表します。アルファ成分を
●
扱うか、(扱う場合)ピクセル上のアルファ成分の相対位置、各成分にアルファ値をあらかじめ
掛けておくか、色成分の値は整数か浮動小数点数か、の指定が可能です。具体的な定数やその用
途、Quartzで操作可能なビットマップグラフィックスコンテキストや画像のピクセル形式につい
ては、“ビットマップ画像と画像マスク” (122 ページ)の“色空間とビットマップレイアウ
ト” (124 ページ)を参照してください。
リスト 2-5に、ビットマップグラフィックスコンテキストの生成方法を示します。このビットマップ
グラフィックスコンテキストに描画すると、所定のメモリブロックに、ビットマップデータの形で描
画結果が記録されます。コード例を示した後、番号がついている行について詳しく説明します。
リスト 2-5
ビットマップグラフィックスコンテキストの生成
CGContextRef MyCreateBitmapContext (int pixelsWide,
int pixelsHigh)
{
CGContextRef
context = NULL;
CGColorSpaceRef colorSpace;
void *
bitmapData;
int
bitmapByteCount;
int
bitmapBytesPerRow;
bitmapBytesPerRow
= (pixelsWide * 4);
bitmapByteCount
= (bitmapBytesPerRow * pixelsHigh);
// 1
colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
// 2
bitmapData = calloc( bitmapByteCount );
// 3
if (bitmapData == NULL)
{
fprintf (stderr, "Memory not allocated!");
return NULL;
}
context = CGBitmapContextCreate (bitmapData,
pixelsWide,
pixelsHigh,
8,
// bits per component
bitmapBytesPerRow,
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
33
// 4
グラフィックスコンテキスト
ビットマップグラフィックスコンテキストの生成
colorSpace,
kCGImageAlphaPremultipliedLast);
if (context== NULL)
{
free (bitmapData);
// 5
fprintf (stderr, "Context not created!");
return NULL;
}
CGColorSpaceRelease( colorSpace );
// 6
return context;
// 7
}
このコードが実行することを以下に示します。
1.
行当たりのバイト数を表す変数を宣言します。この例では、ビットマップの各ピクセルを4バイ
トで表現します。赤、緑、青、アルファの各成分が8ビットずつです。
2.
標準RGB色空間を生成します。CMYK色空間を生成することも可能です。色空間に関する詳細、標
準色空間とデバイス依存色空間の違いについては、“色と色空間” (56 ページ)を参照してくだ
さい。
3.
関数callocで、ビットマップデータを格納するメモリブロックを確保し、内容をクリアします。
この例では32ビットRGBAビットマップ(ピクセル当たり32ビットの配列で、各ピクセルは、赤、
緑、青、アルファの成分(それぞれ8ビット)から成る)を生成します。ビットマップの各ピク
セルは4バイトを占めます。Mac OS X 10.6およびiOS 4では、この処理は省略しても構いません。
関数CGBitmapContextCreateの第1引数にビットマップデータとしてNULLを渡せば、必要なメモリ
空間が自動的に割り当てられます。
4.
ビットマップグラフィックスコンテキストを生成します。ビットマップデータ、ビットマップの
幅と高さ、成分当たりビット数、行当たりのバイト数、色空間、定数(アルファチャネルを含む
かどうか、およびピクセル内のアルファ成分の相対位置を表す)を、引数として生成関数に渡し
ます。定数kCGImageAlphaPremultipliedLastは、各ピクセルの末尾バイトにアルファ成分を格
納すること、色成分にはあらかじめこのアルファ値を掛けた値を格納することを表します。アル
ファ値をあらかじめ各成分に掛けておく処理については、“アルファ値” (57 ページ)を参照し
てください。
5.
何らかの原因で生成に失敗した場合は、ビットマップデータ用に割り当てたメモリを解放しま
す。
6.
色空間を解除します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
34
グラフィックスコンテキスト
ビットマップグラフィックスコンテキストの生成
7.
ビットマップグラフィックスコンテキストを返します。グラフィックスコンテキストは、不要に
なった時点で呼び出し元が解除しなければなりません。
リスト 2-6に、関数MyCreateBitmapContextでビットマップグラフィックスコンテキストを生成し、
これを使ってCGImageオブジェクトを生成した後、得られた画像をウインドウグラフィックスコンテ
キストに描画するコード例を示します。実際にウインドウに画像が描画されている様子を図
2-3 (36 ページ)に示します。コード例を示した後、番号がついている行について詳しく説明しま
す。
リスト 2-6
ビットマップグラフィックスコンテキストへの描画
CGRect myBoundingBox;
// 1
myBoundingBox = CGRectMake (0, 0, myWidth, myHeight);
// 2
myBitmapContext = MyCreateBitmapContext (400, 300);
// 3
// ********** Your drawing code here **********
// 4
CGContextSetRGBFillColor (myBitmapContext, 1, 0, 0, 1);
CGContextFillRect (myBitmapContext, CGRectMake (0, 0, 200, 100 ));
CGContextSetRGBFillColor (myBitmapContext, 0, 0, 1, .5);
CGContextFillRect (myBitmapContext, CGRectMake (0, 0, 100, 200 ));
myImage = CGBitmapContextCreateImage (myBitmapContext);
// 5
CGContextDrawImage(myContext, myBoundingBox, myImage);
// 6
char *bitmapData = CGBitmapContextGetData(myBitmapContext);
// 7
CGContextRelease (myBitmapContext);
// 8
if (bitmapData) free(bitmapData);
// 9
CGImageRelease(myImage);
// 10
このコードが実行することを以下に示します。
1.
境界ボックスの原点と寸法を格納する変数を宣言します。Quartzはビットマップグラフィックス
コンテキストから生成した画像を、このボックス内に描画することになります。
2.
境界ボックスの原点を(0,0)、幅と高さを宣言済みの変数(コード例では省略)の値に設定しま
す。
3.
アプリケーション側で実装した関数MyCreateBitmapContext(リスト 2-5 (33 ページ)を参照)
を呼び出して、幅400ピクセル、高さ300ピクセルのビットマップコンテキストを生成します。用
途に応じて、どのような寸法のビットマップグラフィックスコンテキストでも生成可能です。
4.
Quartz 2Dの関数を使ってビットマップグラフィックスコンテキストに描画します。これ以降の5
行は、アプリケーションに応じた実際の描画コードで置き換えてください。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
35
グラフィックスコンテキスト
ビットマップグラフィックスコンテキストの生成
5.
ビットマップグラフィックスコンテキストからQuartz 2Dの画像(CGImageRef)を生成します。
6.
ウインドウグラフィックスコンテキストの、境界ボックスで指定した領域に、画像を描画しま
す。境界ボックスは、ユーザ空間における位置と寸法で、画像の描画領域を指定します。
この例ではウインドウグラフィックスコンテキストの生成処理は省略します。実際の生成方法に
ついては、“ウインドウグラフィックスコンテキストの生成(Mac OS X)” (25 ページ)を参照し
てください。
7.
ビットマップグラフィックスコンテキストから対応するビットマップデータを取得します。
8.
ビットマップグラフィックスコンテキストは不要になったので解除します。
9.
ビットマップデータがあればそれを解放します。
10. 画像は不要になった時点で解除します。
図 2-3
ビットマップグラフィックスコンテキストから生成し、ウインドウグラフィックスコンテキスト
に描画した画像
操作可能なピクセル形式
表 2-1に、ビットマップグラフィックスコンテキストで扱えるピクセル形式、対応する色空間(cs)、
この形式が使えるようになったMac OS Xの最初の版を要約して示します。ピクセル形式は、ピクセル
当たりビット数(bpp、bits per pixel)と成分当たりビット数(bpc、bits per component)で表します。
表にはピクセル形式に対応するビットマップ情報定数も示してあります。それぞれのビットマップ情
報定数の意味については、『CGImage Reference 』を参照してください。
表 2-1
ビットマップグラフィックスコンテキストで扱えるピクセル形式
色空間
ピクセル形式とビットマップ情報定数
利用可能な環境
Null
8 bpp、8 bpc、kCGImageAlphaOnly
Mac OS X、iOS
Gray
8 bpp、8 bpc、kCGImageAlphaNone
Mac OS X、iOS
Gray
8 bpp、8 bpc、kCGImageAlphaOnly
Mac OS X、iOS
Gray
16 bpp、16 bpc、kCGImageAlphaNone
Mac OS X
32 bpp、32 bpc、kCGImageAlphaNone | kCGBitmapFloat-
Mac OS X
Gray
Components
RGB
16 bpp、5 bpc、kCGImageAlphaNoneSkipFirst
Mac OS X、iOS
RGB
32 bpp、8 bpc、kCGImageAlphaNoneSkipFirst
Mac OS X、iOS
RGB
32 bpp、8 bpc、kCGImageAlphaNoneSkipLast
Mac OS X、iOS
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
36
グラフィックスコンテキスト
ビットマップグラフィックスコンテキストの生成
色空間
ピクセル形式とビットマップ情報定数
利用可能な環境
RGB
32 bpp、8 bpc、kCGImageAlphaPremultipliedFirst
Mac OS X、iOS
RGB
32 bpp、8 bpc、kCGImageAlphaPremultipliedLast
Mac OS X、iOS
RGB
64 bpp、16 bpc、kCGImageAlphaPremultipliedLast
Mac OS X
RGB
64 bpp、16 bpc、kCGImageAlphaNoneSkipLast
Mac OS X
RGB
128 bpp、32 bpc、kCGImageAlphaNoneSkipLast |
Mac OS X
kCGBitmapFloatComponents
RGB
128 bpp、32 bpc、kCGImageAlphaPremultipliedLast |
Mac OS X
kCGBitmapFloatComponents
CMYK
32 bpp、8 bpc、kCGImageAlphaNone
Mac OS X
CMYK
64 bpp、16 bpc、kCGImageAlphaNone
Mac OS X
128 bpp、32 bpc、kCGImageAlphaNone | kCGBitmapFloat-
Mac OS X
CMYK
Components
アンチエイリアス
ビットマップグラフィックスコンテキストにはアンチエイリアスの機能があります。これは、テキス
トや図形をビットマップ画像として描画したとき、縁がぎざぎざになる現象(エイリアス)を修正
し、滑らかに見せる処理のことです。人の目が認知できる解像度に比べて、ビットマップの解像度が
著しく低い場合にこの現象が起こります。これを滑らかに見せるため、図形の外周に沿ったピクセル
の色に細工を施します。こうして色を混ぜ合わせることにより、滑らかに見えるようになるのです。
アンチエイリアスの効果を図 2-4に示します。あるビットマップグラフィックスコンテキストでアン
チエイリアスの処理を解除したい場合は、関数CGContextSetShouldAntialiasを使います。アンチ
エイリアスの設定はグラフィックス状態のひとつです。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
37
グラフィックスコンテキスト
印刷用グラフィックスコンテキストの取得
グラフィックスコンテキストごとに、アンチエイリアスの処理を施すかどうか、関数
CGContextSetAllowsAntialiasingで制御できます。この関数にtrueを渡して呼び出せばアンチエ
イリアスの処理を施し、falseを渡せばしないようになります。この設定はグラフィックス状態とは
無関係です。実際にアンチエイリアスの処理を施すのは、コンテキストとグラフィックス状態のどち
らも、設定がtrueとなっている場合です。
図 2-4
ぎざぎざが見える画像とアンチエイリアスの処理を施した画像の比較
印刷用グラフィックスコンテキストの取得
Mac OS X上で動作するCocoaアプリケーションは、印刷機能を実装するために、NSViewのカスタムサ
ブクラスを使います。印刷する旨の指示は、このビューのprint:メソッドを起動することにより行
います。ビューはプリンタを描画先とするグラフィックスコンテキストを生成し、そのdrawRect:メ
ソッドを呼び出します。アプリケーションは、画面に描画する場合と同じ描画コードでプリンタにも
出力できます。逆に、drawRect:メソッドをカスタマイズして、画面に描画するときとは違う画像を
プリンタに送ることも可能です。
Cocoaにおける印刷処理について詳しくは、『Printing Programming Guide for Mac 』を参照してくださ
い。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
38
パス
パスには、図形の形状を定める働きがあります。図形はいくつかの部分(サブパス)に分かれていて
も構いません。サブパスは、直線や曲線、あるいはその両方を組み合わせて作ることができます。ま
た、開いたパス、閉じたパスという区別もあります。サブパスには、線、円、矩形、星形などの単純
な図形のほか、山脈のシルエット、いたずら書きなどといった、より複雑な図形もあります。図 3-1
に、作成可能なパスの例を示します。左上の直線は破線になっていますが、実線にすることももちろ
ん可能です。不規則な曲線のパス(中央上)は曲線を組み合わせて作ったものです。これは開いたパ
スの例にもなっています。右上は、2つの同心円で囲まれる領域を塗りつぶし、しかし縁取り(線つ
け)はしていない図形です。カリフォルニア州の図形(左下)は閉じたパスであり、多くの曲線や直
線を組み合わせ、縁取り(線つけ)をした上に内側を塗りつぶしてあります。星形については、2種
類の塗りつぶし方を示します(詳しくは後述)。
図 3-1
Quartzのパスを使って描画した図形
この章では、パスを構成する基本要素、パスの線つけ(ストローク)と塗りつぶし(フィル)、パス
の外観を決めるパラメータについて解説します。
パスの生成と描画
パスの生成と描画は、別々に実行するべき作業です。まずパスを生成します。その後、必要になった
時点で、描画するようQuartzに指示します。図 3-1に示したように、パスの線つけの有無、塗りつぶ
しの有無を、それぞれ選択できます。また、他のオブジェクトを描画する際、パスで囲まれた範囲内
のみ描画するよう制限することも可能です。これをクリッピング領域と言います。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
39
パス
パスの構成要素
図 3-2に、2つのサブパスから成るパスを描画した例を示します。左側のサブパスは矩形、右側のサブ
パスは直線と曲線を組み合わせて作った図形です。どちらも、塗りつぶしと線つけを施してありま
す。
図 3-2
2つの図形(サブパス)から成るパス
図 3-3に、多数のパスをばらばらに描画した様子を示します。各パスはランダムに生成した曲線で、
塗りつぶしや線つけの有無もそれぞれ異なります。その上で、円内に描画を制限しています(クリッ
ピング領域)。
図 3-3
クリッピング領域内に描画を制限している様子
パスの構成要素
サブパスは、直線、円弧、曲線を組み合わせて作ります。矩形や楕円を1回の関数呼び出しで追加で
きる便宜関数もあります。点もパスを組み立てる重要な構成要素です。図形の開始位置、終了位置を
定義する働きがあるからです。
Points
点は、ユーザ空間における位置を表す、x座標とy座標の値で指定します。関数CGContextMoveToPoint
で、新しいサブパスの開始位置を指定できます。パスを組み立てる際、Quartzは常に、直近に到達し
た位置、すなわち現在点を保持しています。たとえば、関数CGContextMoveToPointで位置を(10, 10)
と設定すると、現在点は(10, 10)に移動します。次に長さ50単位の水平線を描画すると、線の終端であ
る(60, 10)が現在点になります。直線、円弧、曲線はいずれも、現在点から描画が始まります。
通常、点を指定する際には、x座標とy座標を表す2つの浮動小数点数を、Quartzの関数に渡して行いま
す。関数によっては、2つの浮動小数点数を保持するCGPoint型のデータ構造体を引数として渡すよ
うになっています。
直線
直線(線分)はその終了点を指定して定義します。現在点がそのまま直線の開始点になるので、終了
点を指定するだけでよいのです。関数CGContextAddLineToPointで、サブパスに直線をひとつ追加
できます。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
40
パス
パスの構成要素
連続する複数の直線(折れ線)をまとめて追加したい場合は、関数CGContextAddLinesを使います。
この関数には点の配列を渡します。配列の先頭の点は、1本目の直線の開始点です。それ以外は各直
線の終了点です。先頭の点から開始し、それぞれの終了点に向かって順次、直線をつないでいくこと
により、パスを生成します。
円弧
円弧とは円の一部を切り取ったもののことです。円弧を生成する関数は2つあります。関数
CGContextAddArcは、円のどの部分を切り取るか、という形で描画する円弧を指定します。円の中心
と半径、中心角(ラジアン単位の開始角と終了角)を引数として渡します。中心角として2πを指定
すれば、円全体になります。図 3-4に、多数のパスをばらばらに描画した様子を示します。各パスは
ランダムに生成した円で、塗りつぶしや線つけの有無もそれぞれ異なります。
図 3-4
多数のパス(ランダムに生成した円)を描画した様子
CGContextAddArcToPointも円弧を描画する関数ですが、これは矩形の隅を丸くしたいような場合に
向いています。現在点と、指定された2つの点から、2本の線分を引いて、これが接線になるような円
弧を描画します。関数には円弧の半径も指定します。2本の線分に接する、指定された半径の円を描
くと、その接点で垂直に交わる2本の直線の交点が円の中心になります。接点からもう一方の接点ま
での間を実際に描画します。図 3-5に赤で示した部分です。
図 3-5
2本の接線と半径を指定して円弧を定義
この関数を呼び出す前の時点で、現在のパスにサブパスが含まれていれば、現在点と円弧の開始点を
結ぶ直線が追加されます。そうでなければ、円弧の開始点から始まるサブパスが新たに追加されます
(円弧の開始点に到る直線は追加されません)。
曲線
2次および3次のベジエ曲線は、代数曲線の一種で、曲線で囲まれたさまざまな図形を指定できます。
曲線上の点は、開始点と終了点、およびいくつかの制御点を、多項式に当てはめて計算します。この
ように定義した図形が、ベクトルグラフィックスの基盤となります。式に当てはめる方式には、ビッ
トマップ画像に比べてデータ量が小さくて済むだけでなく、解像度に合わせて曲線を生成し直すこと
ができる、という利点があります。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
41
パス
パスの構成要素
図 3-6に、多数のパスをばらばらに描画した様子を示します。各パスはランダムに生成した曲線で、
塗りつぶしや線つけの有無もそれぞれ異なります。
図 3-6
多数のパス(ランダムに生成した曲線)を描画した様子
2次および3次のベジエ曲線を生成する多項式や、この式から実際に曲線を生成する方法については、
数学の文献や、コンピュータグラフィックスに関するオンラインの資料を参照してください。ここで
は詳細に深入りしません。
制御点と終了点を指定して関数CGContextAddCurveToPointを実行することにより、現在点からの3
次ベジエ曲線を追加できます。図 3-7に、現在点、制御点、終了点と、この各点から求めた3次ベジエ
曲線を示します。2つの制御点の位置により、曲線の形状が決まります。制御点がどちらも開始/終了
点より上側にあれば、曲線は上に湾曲した形になります。どちらも下側であれば下に湾曲します。2
つめの制御点が1つめの制御点よりも現在点(開始点)に近ければ、曲線は自分自身と交差し、ルー
プが生じます。
図 3-7
2つの制御点を持つ3次ベジエ曲線
現在点から2次ベジエ曲線を引くためには、制御点と終了点を指定して関数
CGContextAddQuadCurveToPointを実行します。図 3-8に、終了点を揃え、制御点の位置だけを変え
て作った2つの曲線を示します。制御点は曲線が湾曲する方向を定めます。2次ベジエ曲線は制御点が
1つだけなので、3次ベジエ曲線のように多様な曲線を作ることはできません。たとえば自分自身に交
差する曲線にはならないのです。
図 3-8
1つの制御点を持つ2次ベジエ曲線
サブパスを閉じる処理
サブパスを閉じるためには、関数CGContextClosePathを使います。この関数には、現在点とサブパ
スの開始点を結ぶ線分を追加して、サブパスを閉じる働きがあります。サブパスの開始点に、直線、
円弧、曲線の端がちょうど重なったとしても、それだけでサブパスが閉じるわけではありません。明
示的に関数CGContextClosePathを実行する必要があります。
Quartzの関数の中には、サブパスが閉じていなくても、閉じていると看做して処理するものがありま
す。明示的にCGContextClosePathを実行しなくても、アプリケーションがこれを実行した場合と同
じように、サブパスの開始点に向かう線分を追加するのです。
サブパスを閉じた後、直線、円弧、曲線をパスに追加する関数をさらに呼び出すと、今閉じたサブパ
スの開始点と同じ位置を開始点とする、新しいサブパスが生成されます。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
42
パス
パスの生成
楕円
楕円は、実際には円を押しつぶしたものです。2つの点(焦点)を指定し、そこからの距離の和が一
定になるような点を結んで生成します。図 3-9に、多数のパスをばらばらに描画した様子を示します。
各パスはランダムに生成した楕円で、塗りつぶしや線つけの有無もそれぞれ異なります。
図 3-9
多数のパス(ランダムに生成した楕円)を描画した様子
楕円を現在のパスに追加するためには、関数CGContextAddEllipseInRectを使います。楕円に外接
する矩形を引数として渡します。これを、いくつかのベジエ曲線で近似して描画するようになってい
ます。楕円の中心は、外接矩形の中心に一致します。矩形の幅と高さが等しい(すなわち正方形)な
らば、楕円は、半径がその幅(あるいは高さ)の半分の円になります。等しくない場合は、その長さ
によって長軸と短軸が決まります。
パスに楕円を追加すると、描画の前に起点に移動する処理、描画の後にサブパスを閉じる処理が追加
されます。移動はすべて時計回りの方向です。
矩形
矩形を現在のパスに追加するためには、関数CGContextAddRectを使います。引数として、矩形の原
点、幅、高さを設定したCGRect構造体を渡します。
パスに矩形を追加すると、描画の前に起点に移動する処理、描画の後にサブパスを閉じる処理が追加
されます。移動はすべて反時計回りの方向です。
現在のパスに、複数の矩形をまとめて追加したい場合は、CGContextAddRects構造体の配列を引数
として、関数CGRectを実行してください。図 3-10に、多数のパスをばらばらに描画した様子を示し
ます。各パスはランダムに生成した矩形で、塗りつぶしや線つけの有無もそれぞれ異なります。
図 3-10
多数のパス(ランダムに生成した矩形)を描画した様子
パスの生成
グラフィックスコンテキストにパスを構築するためには、まず関数CGContextBeginPathを実行し
て、Quartzに合図を送ります。次に、そのパスのうち最初に描画する図形(あるいはサブパス)の開
始点を、関数CGContextMoveToPointで設定します。その後、直線、円弧、曲線をパスに追加してい
きますが、次の点に注意してください。
●
新たにパスを開始する前に、関数CGContextBeginPathを実行してください。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
43
パス
パスの生成
●
●
直線、円弧、曲線は、現在点から描画が始まります。空のパスには現在点がありません。関数
CGContextMoveToPointで最初のサブパスの開始点を設定するか、同等の処理をする便宜関数を
実行してください。
現在のサブパスを閉じる(開始点との間を線分で結ぶ)ためには、関数CGContextClosePathを
使います。その後、パスを追加する関数を呼び出すと、新しいサブパスが生成されます。このと
きは明示的に開始点を設定する必要がありません。
●
円弧を描画すると、現在点と円弧の開始点との間に直線が引かれます。
●
楕円や矩形を追加するQuartzのルーチンは、閉じたサブパスを新たに生成してパスに追加します。
●
パスの内部を塗りつぶす、あるいは線つけするためには、描画関数を呼び出す必要があります。
パスを生成しただけでは描画されません。詳しくは、“パスの描画” (45 ページ)を参照してく
ださい。
パスは描画するとグラフィックスコンテキストから消えてしまいます。複雑な図形を繰り返し描画す
るなど、簡単に消えてしまっては困る場合もあるでしょう。そこでQuartzには、何度でも使えるパス
を生成するために用いる、CGPathRefおよびCGMutablePathRefというデータ型が用意されています。
関数CGPathCreateMutableでCGPathオブジェクトを生成し、直線、円弧、曲線、矩形を追加するこ
とができます。Quartzには、“パスの構成要素” (40 ページ)で説明した関数に対応して、CGPathに
対して同様の処理を行う関数群があります。グラフィックスコンテキストではなくCGPathオブジェク
トに作用する点が異なります。具体的には次のような関数です。
●
CGPathCreateMutable:関数に対応CGContextBeginPath
●
CGPathMoveToPoint:関数CGContextMoveToPointに対応
●
CGPathAddLineToPoint:関数CGContextAddLineToPointに対応
●
CGPathAddCurveToPoint:関数CGContextAddCurveToPointに対応
●
CGPathAddEllipseInRect:関数CGContextAddEllipseInRectに対応
●
CGPathAddArc:関数CGContextAddArcに対応
●
CGPathAddRect:関数CGContextAddRectに対応
●
CGPathCloseSubpath:関数CGContextClosePathに対応
パス関数すべての一覧が『Quartz 2D Reference Collection 』に載っています。
パス(CGPath)をグラフィックスコンテキストに追加するためには、関数CGContextAddPathを使い
ます。このパスは、描画するとグラフィックスコンテキストから消えてしまいますが、
CGContextAddPathを実行すれば何度でも追加できます。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
44
パス
パスの描画
注意: グラフィックスコンテキスト内のパスは、関数
CGContextReplacePathWithStrokedPathで線つけしたパスに変換できます。
パスの描画
パスの描画は、線つけや塗りつぶしにより行います。線つけ(ストローク)とは、パスに沿った線を
描画する、という操作です。塗りつぶし(フィル)とは、パスで囲まれた領域を塗る、という操作で
す。Quartzには、線つけする、塗りつぶす、両方をまとめて行う、という関数が用意されています。
線の特性(幅、色など)、塗りつぶし色、塗りつぶし領域を求める方法は、いずれも「グラフィック
ス状態」として管理されます(“グラフィックス状態” (20 ページ)を参照)。
線つけに影響を与えるパラメータ
パスを線つけする方法は、表 3-1に示すパラメータで調整できます。いずれも「グラフィックス状態」
の管理対象なので、いったん値を変更すれば、再び変更するまで有効です。
表 3-1
パスの線つけに影響を与えるパラメータ
パラメータ
値を設定する関数
線幅
CGContextSetLineWidth
角の形状(ジョイン)
CGContextSetLineJoin
線端形状(キャップ)
CGContextSetLineCap
角の限度(マイターリミット)
CGContextSetMiterLimit
線種(ダッシュ)
CGContextSetLineDash
色空間
CGContextSetStrokeColorSpace
色
CGContextSetStrokeColor、CGContextSetStrokeColorWithColor
パターン
CGContextSetStrokePattern
線幅は線の全幅であり、ユーザ空間の単位で表します。パスの両側にまたがるように、それぞれ全幅
の半分の幅の帯が描画されます。
角の形状は、線分のつなぎ目をどのように接続するか、を表します。Quartzで描画できる角の形状を
表 3-2に示します。明示的に指定しなければ尖頭型になります。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
45
パス
パスの描画
表 3-2
角の形状(ジョイン)
形状
外観
解説
尖頭型(マイ
ター)
額縁のように、パスの外側の縁をそのまま交差するところまで
延長します。この角度があまりに急峻である場合は、代わりに
平頭型で描画します。急峻であるかどうかの判断は、パスから
飛び出た部分の長さを線幅で割った値を、「角の限度」値と比
較して行います。
角丸型(ラウン
ド)
パスの交点を中心として、直径が線幅に等しい半円を描き、囲
まれた領域を塗りつぶします。
平頭型(ベベル)
交差する2つの線分の線頭形状を「先太」にします。その上で、
線分の端から飛び出たくぼみ部分を三角形で塗りつぶします。
線端形状は、CGContextStrokePathで線の端点を描画する方法を表します。Quartzで描画できる線端
形状を表 3-3に示します。明示的に指定しなければ先太型になります。
表 3-3
線端形状
形状
外観
解説
先太型(バット)
パスの端点位置で切り落とした形状です。端点から延長
される部分はありません。
丸型(ラウンド)
パスの先端を中心として、直径が線幅に等しい半円を描
き、囲まれた領域を塗りつぶします。
突出型(プロジェクショ
ン)
パスの端点から、線幅の半分の長さだけ延長します。延
長部分の先端は直角に切り落とした形です。
サブパスを閉じると、開始点も連続する線分のつなぎ目と看做され、「角の形状」の設定に従って描
画されます。これに対し、開始点と同じ点に到る線分を引いて見かけ上パスを閉じた場合、その両端
は「線端形状」の設定に従って描画されます。
線種を指定することにより、パスに沿って、さまざまなパターンで破断する線を描画できます。破線
を構成する個々の線分の長さと間隔を表す配列、および破線の位相を引数として渡し、
CGContextSetLineDash関数で設定します。
void CGContextSetLineDash (
CGContextRef ctx,
CGFloat phase,
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
46
パス
パスの描画
const CGFloat lengths[],
size_t count
);
引数lengthsの各要素に、塗りつぶす部分と間隔をあける部分の長さを交互に指定します。引数phase
は、線端をパターンのどの位置から描き出すか、を表します。図 3-11に線種パターンをいくつか示し
ます。
図 3-11
線種パターンの例
色空間は、色の値をどのように解釈するか、を表します。色と色空間をまとめてカプセル化した、
CGColorRefデータ型で指定することも可能です。色空間と色の設定については、“色と色空間” (56 ペー
ジ)を参照してください。
パスの線つけをする関数
現在のパスに沿って線つけをする関数を表 3-4に示します。矩形や楕円の塗りつぶしをする便宜関数
もあります。
表 3-4
パスの線つけをする関数
関数
解説
CGContextStrokePath
現在のパスに沿って線つけします。
CGContextStrokeRect
指定した矩形を縁取りします。
CGContextStrokeRectWithWidth
指定した線幅で、指定した矩形を縁取りします。
CGContextStrokeEllipseInRect
指定した矩形に内接ずる楕円を縁取りします。
CGContextStrokeLineSegments
一連の直線(折れ線)に沿って線つけします。
CGContextDrawPath
定数kCGPathStrokeを渡した場合、現在のパスに沿って線
つけします。パスの塗りつぶしと線つけをまとめて実行す
る関数については、“パスの塗りつぶし” (48 ページ)を参
照してください。
関数CGContextStrokeLineSegmentsは次のコードと同等です。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
47
パス
パスの描画
CGContextBeginPath (context);
for (k = 0; k < count; k += 2) {
CGContextMoveToPoint(context, s[k].x, s[k].y);
CGContextAddLineToPoint(context, s[k+1].x, s[k+1].y);
}
CGContextStrokePath(context);
関数CGContextStrokeLineSegmentsを呼び出す際には、点を2つずつ並べた配列の形で、線分の組
を指定します。各組はそれぞれ、線分の開始点と終了点を表します。たとえば、配列の第1要素の点
は1本目の線分の開始点、第2要素の点は終了点、第3要素の点は2本目の線分の開始点、などとなりま
す。
パスの塗りつぶし
現在のパスを塗りつぶす処理では、パスに含まれるサブパスはすべて閉じているものと看做します。
この閉じたサブパスを参照して、どのピクセルを塗りつぶすか計算するのです。塗りつぶす領域を計
算する方法は2通りあります。楕円や矩形のような単純なパスであれば、塗りつぶす領域に紛れはあ
りません。しかし、いくつかの線分や円弧が重なっている、あるいはパスが複数のサブパスから成る
(たとえば図 3-12のような同心円)場合、塗りつぶす領域を決める規則は2通り考えられます。
明示的に指定しなければ、塗りつぶす領域は「非ゼロ」巻数規則によって決まります。まず、調べよ
うとする点から描画領域の境界に向かって、直線を引きます。初期値を0として、この直線に沿って
進みながら、パスが左から右に交差したら1を加算、右から左に交差したら1を減算します。その結
果、0になった場合は塗りつぶさず、0以外であれば塗りつぶす、と判定します。この判定にはパスの
向きが影響します。図 3-12 (48 ページ)に、2組の同心円を、「非ゼロ」巻数規則に従って塗りつ
ぶした様子を示します。2つの円を同じ方向に描画した場合は、両方の円の内部が塗りつぶされます。
一方、逆方向に描画した場合、内側の円の内部は塗りつぶされません。
もうひとつ、「偶奇」巻数規則に従って塗りつぶすことも可能です。まず、調べようとする点から描
画領域の境界に向かって、直線を引きます。この直線に沿って進みながら、パスを交差する回数を数
えます。その結果、奇数になった場合は塗りつぶし、偶数ならば塗りつぶさない、と判定します。こ
の場合、パスの向きは結果に影響を与えません。図 3-12に示すように、円を描画する向きにかかわら
ず、塗りつぶしの結果は同じです。
図 3-12
2通りの規則に従って塗りつぶした同心円
パスを塗りつぶす関数を表 3-5に示します。矩形や楕円の塗りつぶしをする便宜関数もあります。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
48
パス
パスの描画
表 3-5
パスを塗りつぶす関数
関数
解説
CGContextEOFillPath
「偶奇」巻数規則に従って現在のパスを塗りつぶします。
CGContextFillPath
「非ゼロ」巻数規則に従って現在のパスを塗りつぶします。
CGContextFillRect
指定した矩形内の領域を塗りつぶします。
CGContextFillRects
指定した複数の矩形内の領域をまとめて塗りつぶします。
CGContextFillEllipseInRect
指定した矩形に内接する楕円内の領域を塗りつぶします。
CGContextDrawPath
kCGPathFill(「非ゼロ」巻数規則)またはkCGPathEOFill
(「偶奇」巻数規則)を指定した場合は、現在のパスを塗りつぶ
します。kCGPathFillStrokeまたはkCGPathEOFillStrokeを指
定した場合は、現在のパスを塗りつぶし、かつ線つけ(縁取り)
をします。
ブレンドモードの設定
ブレンドモードは、背景の色に、どのように新しい色を混ぜ合わせて描画するか、を表します。既定
値は「標準」ブレンドモードで、次の式によって背景色と混ぜ合わせます。
result = (alpha * foreground) + (1 - alpha) * background
“色と色空間” (56 ページ)に、色の透明度を表す、アルファ成分について詳しく説明します。この
節の例では、完全に不透明(アルファ値が1.0)と想定します。不透明の場合、「標準」ブレンドモー
ドで描画すると、背景は完全に見えなくなってしまいます。
ブレンドモードを表す適当な定数を指定して関数CGContextSetBlendModeを実行することにより、
ブレンドモードを設定し、さまざまな効果を得ることができます。また、ブレンドモードはグラフィッ
クス状態として管理する対象です。あらかじめ関数CGContextSaveGStateを実行しておけば、ブレ
ンドモードを変更した後、関数CGContextRestoreGStateで元の「標準」ブレンドモードに戻すこと
ができます。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
49
パス
パスの描画
以下、図 3-13に示す背景の上に、それぞれのブレンドモードで、図 3-14に示す矩形群を描画した結果
を示します。図 3-15から図 3-30までのいずれも、背景は「標準」ブレンドモードで描画したもので
す。ブレンドモードの変更は、適当な定数を指定して関数CGContextSetBlendModeを実行すること
により行います。その状態で、背景に重ねて前面の矩形群を描画します。
図 3-13
背景として描画する矩形群
図 3-14
背景の上に重ねて描画する矩形群
注意: ブレンドモードを利用して、2つの画像を合成したり、グラフィックスコンテキスト
に描画した上に画像を重ねたりすることも可能です。“画像にブレンドモードを適用” (134 ペー
ジ)に、ブレンドモードを利用して画像を合成する方法と、2つの画像にブレンドモードを
適用した結果を示します。
標準ブレンドモード
これは既定のブレンドモードなので、他の何らかのブレンドモードにした後、定数を指定して関数
CGContextSetBlendModekCGBlendModeNormalを実行するだけで、既定のブレンドモードに戻すこと
ができます。図 3-15に、図 3-14 (50 ページ)の上に標準ブレンドモードで図 3-13 (50 ページ)を
描画した結果を示します。
図 3-15
標準ブレンドモードで描画した矩形群
乗算ブレンドモード
乗算ブレンドモードは、背景画像の色値に前面画像の色値を掛け合わせます。その結果得られる色
は、背景と前面のどちらよりも暗くなります。図 3-16に、図 3-13 (50 ページ)の上に乗算ブレンド
モードで図 3-14 (50 ページ)を描画した結果を示します。定数を渡して関数
CGContextSetBlendModekCGBlendModeMultiplyを実行することにより、このブレンドモードに切り
替えます。
図 3-16
乗算ブレンドモードで描画した矩形群
スクリーンブレンドモード
スクリーンブレンドモードは、背景画像の色値を反転し、前面画像の色値を反転して掛け合わせま
す。その結果得られる色は、背景と前面のどちらよりも明るくなります。図 3-17に、図 3-13 (50 ペー
ジ)の上にスクリーンブレンドモードで図 3-14 (50 ページ)を描画した結果を示します。定数を渡
して関数CGContextSetBlendModekCGBlendModeScreenを実行することにより、このブレンドモードに
切り替えます。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
50
パス
パスの描画
図 3-17
スクリーンブレンドモードで描画した矩形群
オーバーレイブレンドモード
背景色に応じて、乗算ブレンドモードとスクリーンブレンドモードのいずれか適用します。背景の明
るさまたは暗さを反映した色になります。図 3-18に、図 3-13 (50 ページ)の上にオーバーレイブレ
ンドモードで図 3-14 (50 ページ)を描画した結果を示します。定数を渡して関数
CGContextSetBlendModekCGBlendModeOverlayを実行することにより、このブレンドモードに切り替
えます。
図 3-18
オーバーレイブレンドモードで描画した矩形群
比較(暗)ブレンドモード
背景画像と前面画像の色のうち、暗い方を選びます。背景画像よりも前面画像の方が暗い箇所は、前
面画像の色になります。そうでない箇所は背景色のままです。図 3-19図 3-13 (50 ページ)の上に比
較(暗)ブレンドモードで図 3-14 (50 ページ)を描画した結果を示します。定数を渡して関数
CGContextSetBlendModekCGBlendModeDarkenを実行することにより、このブレンドモードに切り替
えます。
図 3-19
比較(暗)ブレンドモードで描画した矩形群
比較(明)ブレンドモード
背景画像と前面画像の色のうち、明るい方を選びます。背景画像よりも前面画像の方が明るい箇所
は、前面画像の色になります。そうでない箇所は背景色のままです。図 3-20図 3-13 (50 ページ)の
上に比較(明)ブレンドモードで図 3-14 (50 ページ)を描画した結果を示します。定数を渡して関
数CGContextSetBlendModekCGBlendModeLightenを実行することにより、このブレンドモードに切り
替えます。
図 3-20
比較(明)ブレンドモードで描画した矩形群
覆い焼きブレンドモード
背景画像の色を明るくして、前面画像の色に反映します。前面画像の色が黒である箇所は、背景画像
のまま変化しません。図 3-21図 3-13 (50 ページ)の上に覆い焼きブレンドモードで図 3-14 (50 ペー
ジ)を描画した結果を示します。定数を渡して関数CGContextSetBlendModekCGBlendModeColorDodge
を実行することにより、このブレンドモードに切り替えます。
図 3-21
覆い焼きブレンドモードで描画した矩形群
焼き込みブレンドモード
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
51
パス
パスの描画
背景画像の色を暗くして、前面画像の色に反映します。前面画像の色が白である箇所は、背景画像の
まま変化しません。図 3-22図 3-13 (50 ページ)の上に焼き込みブレンドモードで図 3-14 (50 ペー
ジ)を描画した結果を示します。定数を渡して関数CGContextSetBlendModekCGBlendModeColorBurn
を実行することにより、このブレンドモードに切り替えます。
図 3-22
焼き込みブレンドモードで描画した矩形群
ソフトライトブレンドモード
前面画像の色に応じて、暗く、または明るくします。前面画像の色が50%グレーよりも明るい箇所
は、覆い焼きと同様に背景色を明るくします。そうでない箇所は、焼き込みと同様に背景色を暗くし
ます。50%グレーと等しければ、背景はそのままです。前景画像が純粋な黒や白の箇所は暗く/明るく
なりますが、純粋な黒や白にはなりません。背景画像上に乱反射するスポットライトを照らしたよう
な効果が生まれます。場面のある箇所を強調するために使うとよいでしょう。図 3-23図 3-13 (50 ペー
ジ)の上にソフトライトブレンドモードで図 3-14 (50 ページ)を描画した結果を示します。定数を
渡して関数CGContextSetBlendModekCGBlendModeSoftLightを実行することにより、このブレンドモー
ドに切り替えます。
図 3-23
ソフトライトブレンドモードで描画した矩形群
ハードライトブレンドモード
前面画像の色に応じて、乗算ブレンドモードまたはスクリーンブレンドモードを適用します。前面画
像の色が50%グレーよりも明るい箇所は、スクリーンと同様に背景色を明るくします。そうでない箇
所は、乗算と同様に背景色を暗くします。50%グレーと等しければ、背景はそのままです。前景画像
が純粋な黒や白の箇所は、結果も純粋な黒や白になります。背景画像上にどぎつい色のスポットライ
トを照らしたような効果が生まれます。場面のある箇所を強調するために使うとよいでしょう。図
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
52
パス
パスの描画
3-24図 3-13 (50 ページ)の上にハードライトブレンドモードで図 3-14 (50 ページ)を描画した結
果を示します。定数を渡して関数CGContextSetBlendModekCGBlendModeHardLightを実行することに
より、このブレンドモードに切り替えます。
図 3-24
ハードライトブレンドモードで描画した矩形群
差の絶対値ブレンドモード
背景と前面のどちらの輝度が大きいかに応じて、背景画像の色値から前面画像の色値を引くか、また
はその逆を行います。前面画像が黒である箇所は背景色のままです。白であれば背景色が反転しま
す。図 3-25図 3-13 (50 ページ)の上に差の絶対値ブレンドモードで図 3-14 (50 ページ)を描画し
た結果を示します。定数を渡して関数CGContextSetBlendModekCGBlendModeDifferenceを実行するこ
とにより、このブレンドモードに切り替えます。
図 3-25
差の絶対値ブレンドモードで描画した矩形群
除外ブレンドモード
kCGBlendModeDifferenceを指定した場合とよく似た効果ですが、コントラストは低くなります。前
面画像が黒である箇所は背景色のままです。白であれば背景色が反転します。図 3-26図 3-13 (50 ペー
ジ)の上に除外ブレンドモードで図 3-14 (50 ページ)を描画した結果を示します。定数を渡して関
数CGContextSetBlendModekCGBlendModeExclusionを実行することにより、このブレンドモードに切
り替えます。
図 3-26
除外ブレンドモードで描画した矩形群
色相ブレンドモード
背景画像の輝度と彩度、前面画像の色相を持つ色になります。図 3-27図 3-13 (50 ページ)の上に色
相ブレンドモードで図 3-14 (50 ページ)を描画した結果を示します。定数を渡して関数
CGContextSetBlendModekCGBlendModeHueを実行することにより、このブレンドモードに切り替えま
す。
図 3-27
色相ブレンドモードで描画した矩形群
彩度ブレンドモード
背景画像の輝度と色相、前面画像の彩度を持つ色になります。彩度が0の領域(純粋なグレー領域)
は背景色のままです。図 3-28図 3-13 (50 ページ)の上に彩度ブレンドモードで図 3-14 (50 ページ)
を描画した結果を示します。定数を渡して関数CGContextSetBlendModekCGBlendModeSaturationを実
行することにより、このブレンドモードに切り替えます。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
53
パス
パスを用いたクリッピング処理
図 3-28
彩度ブレンドモードで描画した矩形群
カラーブレンドモード
背景画像の輝度、前面画像の色相と彩度を持つ色になります。画像のグレーレベルはそのまま維持さ
れます。モノクロや淡色の画像に色を乗せる場合に有用です。図 3-29図 3-13 (50 ページ)の上にカ
ラーブレンドモードで図 3-14 (50 ページ)を描画した結果を示します。定数を渡して関数
CGContextSetBlendModekCGBlendModeColorを実行することにより、このブレンドモードに切り替え
ます。
図 3-29
カラーブレンドモードで描画した矩形群
輝度ブレンドモード
背景画像の色相と彩度、前面画像の輝度を持つ色になります。kCGBlendModeColorを指定した場合
とは正反対の効果があります。図 3-30図 3-13 (50 ページ)の上に輝度ブレンドモードで図
3-14 (50 ページ)を描画した結果を示します。定数を渡して関数
CGContextSetBlendModekCGBlendModeLuminosityを実行することにより、このブレンドモードに切
り替えます。
図 3-30
輝度ブレンドモードで描画した矩形群
パスを用いたクリッピング処理
現在のクリッピング領域は、パスをマスクとして使って生成します。ページ中に描画したくない部分
があるとき、実際に描画を行わないようにするために使います。たとえば、非常に大きなビットマッ
プ画像のごく一部分だけを表示したい場合、クリッピング領域を設定することにより、必要な部分だ
けを表示できます。
描画の際、Quartzはクリッピング領域内のみレンダリング処理を実行します。クリッピング領域の閉
じたサブパス内で描画した内容は、実際に目に見えるようになります。サブパス外は見えるようにな
りません。
グラフィックスコンテキストを生成した時点では、コンテキストのうち描画可能な領域(たとえば
PDFコンテキストのメディアボックス)全体が、クリッピング領域になっています。現在のパスを設
定し、描画関数の代わりにクリッピング関数を実行することにより、このクリッピング領域を変更で
きます。クリッピング関数は、現在のパスのうち塗りつぶされた領域と、現在のクリッピング領域と
の共通部分を、新しいクリッピング領域にします。したがって、画像のうち目に見える部分を縮める
ことは可能ですが、クリッピング領域を拡げることはできません。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
54
パス
パスを用いたクリッピング処理
クリッピング領域はグラフィックス状態として管理する対象です。クリッピング領域を以前の状態に
戻したい場合は、あらかじめグラフィックス状態を保存しておき、クリッピング領域を使って描画を
終えてから、グラフィックス状態を復元してください。
リスト 3-1に、円の内部をクリッピング領域として設定するコード例を示します。こうすると図
3-3 (40 ページ)のように、クリッピング領域外は描画されないようになります(ほかに“グラデー
ション” (92 ページ)の章の“コンテキストのクリッピング” (104 ページ)も参照)。
リスト 3-1
円形のクリッピング領域の設定
CGContextBeginPath (context);
CGContextAddArc (context, w/2, h/2, ((w>h) ? h : w)/2, 0, 2*PI, 0);
CGContextClosePath (context);
CGContextClip (context);
表 3-6
グラフィックスコンテキストにクリッピング領域を設定する関数
関数
解説
CGContextClip
「非ゼロ」巻数規則に従い、現在のパスと現在のクリッピングパ
スとの共通部分を求めます。
CGContextEOClip
「偶奇」巻数規則に従い、現在のパスと現在のクリッピングパス
との共通部分を求めます。
CGContextClipToRect
現在のクリッピング領域と指定された矩形の共通部分を、新しい
クリッピング領域として設定します。
CGContextClipToRects
現在のクリッピング領域と指定された矩形(複数指定可)の共通
部分を、新しいクリッピング領域として設定します。
CGContextClipToMask
指定された矩形にマスクをマップし、グラフィックスコンテキス
トの現在のクリッピング領域との共通部分を求めます。これ以降、
このグラフィックスコンテキストに対してパスを描画すると、ク
リッピング処理が施されるようになります(“コンテキストにク
リッピング領域を設定することにより画像をマスク” (133 ページ)
を参照)。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
55
色と色空間
デバイス(ディスプレイ、プリンタ、スキャナ、カメラなど)によって、色の処理方法はさまざまで
す。忠実に再現できる色の範囲はそれぞれ異なります。あるデバイスで生成した色が、他のデバイス
でも同じように再現できるとは限りません。
色を効果的に処理し、Quartz 2Dの関数が色や色空間を扱う方式を理解するためにも、『Color
Management Overview 』に出てくる用語を把握しておくべきでしょう。この資料には、色の認識、色
値、デバイス非依存およびデバイス固有の色空間、色合わせに関する問題、レンダリングインテント
(再現できない色の処理方法)、色管理モジュール、ColorSyncに関する解説があります。
この章では、Quartzが色や色空間を表す方法と、アルファ成分とは何かについて解説します。また、
次のような処理の手順も説明します。
●
色空間の生成
●
色の生成と設定
●
レンダリングインテントの設定
色と色空間について
Quartzでは、色をいくつかの値の組で表します。この値は、色空間、すなわち色情報の解釈方法を指
定しなければ意味を持ちません。たとえば、表 4-1に示した値は、いずれも濃い青を表します。しか
し、色空間や、その色空間で取りうる値の範囲について知らなければ、値の組が与えられても、どの
ような色を表すのか判断できません。
表 4-1
さまざまな色空間において色を表す値
値
色空間
成分
240°、100%、100%
HSB
色相(Hue)、彩度(Saturation)、明度(Brightness)
0, 0, 1
RGB
赤(Red)、緑(Green)、青(Blue)
1, 1, 0, 0
CMYK
シアン(Cyan)、マゼンタ(Magenta)、イエロー
(Yellow)、ブラック(Black)
1, 0, 0
BGR
青(Blue)、緑(Green)、赤(Red)
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
56
色と色空間
アルファ値
色空間の指定を誤ると、図 4-1のようにまるで違う画像になってしまうことがあります。BGRとRGBの
色空間では、緑成分は同じように解釈されますが、赤と青の値は入れ替わるからです。
図 4-1
同じ画像にBGRとRGBの色プロファイルを適用した様子
色空間によって、成分の個数も変わることがあります。表に示した色空間のうち3つは3成分ですが、
CMYK色空間は4成分です。取りうる値の範囲もそれぞれ異なります。Quartzでは、大部分の色空間で
値の範囲を0.0~1.0としています(1.0が最大強度)。たとえばRGB色空間で、B(青)成分の強度が最
大である色の値は、(0, 0, 1.0)となります。Quartzでは、上記の各成分に加え、色の透明度を表すアル
ファ値も設定できます。表 4-1ではアルファ値を省略していました。
アルファ値
アルファ値はグラフィックス状態として管理するパラメータで、何かを描画したページの上に、新た
にオブジェクトを描画して混ぜ合わせるやり方を制御します。これが最大値であれば、新たに描画す
るオブジェクトは不透明です。一方、0であれば、このオブジェクトは透明で目に見えません。図 4-2
に、アルファ値を1.0、0.75、0.5、0.1、0.0と変えながら矩形を描画した様子を示します。大きな矩形
の透明度が増すにつれ、奥に描画されていた、赤い不透明の小矩形が見えるようになってきます。
図 4-2
アルファ値を変えながら矩形を描画した様子
ページ上のオブジェクトとページ自身のいずれも、あらかじめグラフィックスコンテキストの(大域
的に適用される)アルファ値を設定してから描画することにより、透明度を変えることができます。
図 4-3に、大域アルファ値を0.5にした場合と、既定値である1.0の場合とを並べて示します。
図 4-3
大域アルファ値を変えて描画した画像の比較
標準ブレンドモード(グラフィックス状態の既定値)の場合、アルファブレンディング(半透明な画
像の重ね合わせ)処理は、混合元の色の成分を、次の式に従って、混合先の色の成分と混ぜ合わせる
ことにより実行します。
destination = (alpha * source) + (1 - alpha) * destination
ここで、sourceは新たに塗り重ねる色の成分、destinationは背景色の成分です。この計算を、新
たに描画する図形や画像ごとに実行します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
57
色と色空間
色空間の生成
描画するオブジェクトは、アルファ値を1.0とすれば完全に不透明に、0.0ならば完全に透明になり
ます。と0.01.0の間の値であれば、その値に応じた半透明のオブジェクトになります。色を設定す
るルーチンはいずれも、最後の色成分としてアルファ値を指定できるようになっています。さらに、
関数CGContextSetAlphaで大域アルファ値を設定できます。両方のアルファ値を設定すると、描画
の際にはその積が適用されることになります。
ページ自身を完全に透明にしたい場合は、関数CGContextClearRectで、グラフィックスコンテキス
トのアルファチャネルを明示的にクリアしてください。これは、ウインドウグラフィックスコンテキ
スト、またはビットマップグラフィックスコンテキストの場合に適用できます。たとえば、アイコン
用の透明マスクを生成する、ウインドウの背景を透明にする、などの用途があります。
色空間の生成
Quartzは、デバイス非依存の色空間の基準として色管理システムが用いる色空間のほか、標準色空
間、インデックス付き色空間、パターン色空間も扱えます。デバイス非依存の色空間は、どのデバイ
スにも通用するやり方で色を表現します。また、あるデバイスに固有の色空間から、別のデバイスの
それに、色データを変換するためにも使えます。この色空間で表した色は、各デバイスの能力の範囲
内で、どのデバイスにも同じように再現できます。したがって、色を表現する方法として最適と言え
るでしょう。
精度よく色を表現する必要があるアプリケーションでは、デバイス非依存の色空間を使うようにして
ください。その中でも広く使われるものとして、標準色空間があります。この場合、オペレーティン
グシステムが最適な色空間を提供するので、アプリケーション側で特別な処理をする必要はありませ
ん。ディスプレイ上の表示もプリンタ出力も、人の目には同じように認識されます。
Important: iOSはデバイス非依存の色空間(標準色空間)を扱うことができないので、iOSアプリ
ケーションはデバイスに応じた色空間を使わなければなりません。
デバイス非依存の色空間の生成
デバイス非依存の色空間を生成するためには、個々のデバイスの参照白点、参照黒点、ガンマ値を与
える必要があります。Quartzはこの情報をもとに、色の値を、指定された色空間から各出力デバイス
の色空間に変換します。
Quartzで利用可能なデバイス非依存の色空間と、これを生成する関数には、次のようなものがありま
す。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
58
色と色空間
色空間の生成
●
L*a*b*は、マンセル表色系(色を色相、明度、彩度によって表現する系)を非線形に変換したも
のです。人が認識する(心理的な)色の差が、色空間における距離に合致するようになっていま
す。L*成分は明度、a*成分は緑から赤の間の位置、b*成分は青から黄の間の位置を表します。人
の目(脳)が色を認識するやり方を摸擬するように設計されました。生成には関数
CGColorSpaceCreateLabを使います。
●
ICCはInternational Color Consortiumが定義した色空間で、ICCカラープロファイルと呼ばれるもの
を使って処理します。これは、個々のデバイスが処理できる、色域その他の特性を表すデータの
ことです。この情報を使うと、あるデバイスの色空間から別のデバイスの色空間に、正確に変換
できます。多くのデバイスについて、製造元がICCプロファイルを公表しています。カラーモニタ
やプリンタの中には、ICCプロファイル情報が埋め込まれているものもあります(TIFFなどのビッ
トマップ画像形式と同様)。生成には関数CGColorSpaceCreateICCBasedを使います。
●
●
較正済みRGBは、デバイス非依存のRGB色空間で、出力デバイスが生成できる最も白い点である、
参照白点を基準として色を表現します。生成には関数CGColorSpaceCreateCalibratedRGBを使
います。
較正済みグレーは、デバイス非依存のグレースケール色空間で、出力デバイスが生成できる最も
白い点である、参照白点を基準として色を表現します。生成には関数
CGColorSpaceCreateCalibratedGrayを使います。
標準色空間の生成
標準色空間を使えば、色合わせの処理をシステムに委ねることができます。一般的な目的には充分と
言ってよいでしょう。標準グレー、標準RGB、標準CMYKというように「標準」という名前がついてい
ますが、デバイス非依存の色空間の中でも特別なものです。
参照点の情報を与える必要がないので、使うのは容易です。関数CGColorSpaceCreateWithNameに次
のいずれかの定数を渡して生成します。
●
kCGColorSpaceGenericGray:標準グレー、モノクロの色空間です。色値は1つで、完全な黒を
表す0.0から、完全な白を表す1.0までの範囲で指定します。
●
kCGColorSpaceGenericRGB:標準RGBの色空間です。赤、緑、青の3つの成分で表します。カラー
モニター上の個々のピクセルを合成する方法がモデルになっています。各成分の値は、強度が最
小である0.0から、最大である1.0までの範囲で指定します。
●
kCGColorSpaceGenericCMYK:標準CMYKの色空間です。シアン、マゼンタ、イエロ、ブラック
の4つの成分で表します。インクを重ね合わせて印刷する方法がモデルになっています。各成分
の値は、インクが紙にまったく付着しない0.0から、最大量が付着する1.0までの範囲で指定しま
す。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
59
色と色空間
色の設定と生成
デバイス色空間の生成
デバイス色空間は主としてiOSアプリケーションが利用します(他の手段が使えないため)。Mac OS
Xアプリケーションであれば、通常は標準色空間を使ってください。ただし、Quartzのルーチンの中
には、画像がデバイス色空間に基づいて表現されていると想定するものがあります。たとえば、関数
CGImageCreateWithMaskで画像をマスクとして指定する場合、その画像はデバイス依存のグレー色
空間で表現されたものでなければなりません。
デバイス色空間の生成には次のいずれかの関数を使います。
●
CGColorSpaceCreateDeviceGray:デバイス依存のグレースケール色空間を生成します。
●
CGColorSpaceCreateDeviceRGB:デバイス依存のRGB色空間を生成します。
●
CGColorSpaceCreateDeviceCMYK:デバイス依存のCMYK色空間を生成します。
インデックス付き色空間、パターン色空間の生成
インデックス付き色空間では、最大256項目まで収容できる色テーブルを使います。また、基底色空
間も設定します。色テーブルの各項目の値は、基底色空間におけるひとつの色を表します。生成には
関数CGColorSpaceCreateIndexedを使います。
パターン色空間(“パターン” (72 ページ)を参照)は、(特定の色の代わりに)パターンを指定し
て描画する(塗りつぶすなど)場合に使います。生成には関数CGColorSpaceCreatePatternを使い
ます。
色の設定と生成
Quartzには、塗りつぶしや線つけの色、色空間、アルファ値を設定する関数群があります。いずれも
グラフィックス状態として管理する対象なので、いったん設定すれば、他の値に設定し直すまでその
値が適用されます。
色を表すためには、どの色空間で表現するか、を指定しなければなりません。これがなければ、色の
値をどのように解釈すればよいのかわからないからです。さらに、その色空間は、描画先に応じて適
切なものを選択しなければなりません。図 4-4の左側は、CMYK色空間における青で塗りつぶしたもの
です。これを、RGB色空間の青で塗りつぶした、右側の図と比べてみてください。画面上にこの資料
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
60
色と色空間
色の設定と生成
を表示しているのであれば、この2つの塗りつぶし色はかなり違って見えるはずです。理論的には同
じ色のはずですが、実際にそう見えるようにするためには、RGBの色をRGBデバイスに、CMYKの色を
CMYKデバイスに表示しなければなりません。
図 4-4
CMYK色空間とRGB色空間で表現した同じ塗りつぶし色の比較
関数CGContextSetFillColorSpaceおよびCGContextSetStrokeColorSpaceで、塗りつぶしや線つ
けの色空間を設定できます。また、デバイス色空間の色を設定する便宜関数もあります(表 4-2を参
照)。
表 4-2
色を設定する関数
関数
色を設定する対象の色空間
CGContextSetRGBStrokeColor
デバイスRGB。PDF生成時には、対応する標準色空間にお
ける色と看做して処理します。
CGContextSetRGBFillColor
CGContextSetCMYKStrokeColor
デバイスCMYK。PDF生成時もデバイスCMYKのままです。
CGContextSetCMYKFillColor
CGContextSetGrayStrokeColor
CGContextSetGrayFillColor
任意の色空間。色空間を表すCGColorオブジェクトを引数
として指定します。同じ色が繰り返し必要になる場合に
使うとよいでしょう。
CGContextSetStrokeColorWithColor
CGContextSetFillColorWithColor
CGContextSetStrokeColor
CGContextSetFillColor
デバイスグレー。PDF生成時には、対応する標準色空間
における色と看做して処理します。
現在の色空間。非推奨。代わりに、CGColorオブジェクト
を用意し、関数CGContextSetStrokeColorWithColorま
たはCGContextSetFillColorWithColorで設定してくだ
さい。
塗りつぶし色や線つけ色は、塗りつぶし色空間、線つけ色空間における値として指定します。たとえ
ばRGB色空間における純色の赤は、(1.0, 0.0, 0.0, 1.0)という4つの値の配列で指定します。このうち先頭
から3つは、赤の強度が最大値、緑と青の強度が0であることを表します。4つめはアルファ値で、色
の透明度を表すために使います。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
61
色と色空間
レンダリングインテントの設定
アプリケーションで同じ色を繰り返し利用する場合、塗りつぶし色や線つけ色を設定するには、CGColor
オブジェクトを生成し、関数CGContextSetFillColorWithColorや
CGContextSetStrokeColorWithColorに引数として渡す、という方法が最も効率的です。CGColorオ
ブジェクトは必要なくなるまでそのまま保持していて構いません。CGColorオブジェクトを直接使う
ことにより、アプリケーションの性能も向上できます。
CGColorオブジェクトの生成には関数CGColorCreateを使います。CGColorspaceオブジェクトと、色
の各成分を表す浮動小数点数の配列を、引数として指定します。配列の末尾の要素はアルファ値を表
します。
レンダリングインテントの設定
レンダリングインテントは、ある色空間における色を、別の色空間の色に変換する方法を表します。
変換元の色が、変換先の色空間では再現できない(色域外である)場合に、この設定が問題になりま
す。特に設定しなければ、ビットマップ画像以外の描画には「相対的な色域を維持」、ビットマップ
画像には「視覚的な関係を維持」を使うようになっています。
レンダリングインテントの設定は、関数CGContextSetRenderingIntentに、グラフィックスコンテ
キストと次のいずれかの定数を指定して行います。
●
kCGRenderingIntentDefault - コンテキストに応じた既定のレンダリングインテントを使いま
す。
●
kCGRenderingIntentAbsoluteColorimetric - 絶対的な色域を維持。出力デバイスの色域外の
色を、色域内でできるだけ近い色に対応づけます。その結果、クリッピング効果が生じる場合が
あります。グラフィックスコンテキストの色域内にある異なる色が、出力デバイスの色域内にあ
る同じ色に変換されるからです。グラフィックスに使われている色がすべて、変換元と変換先の
両方の色域内に収まる場合、この方法が最適です。ロゴを描画する、特色を用いるなどの場合、
通常はこの条件を満たします。
●
kCGRenderingIntentRelativeColorimetric - 相対的な色域を維持。グラフィックスコンテキ
ストの白点と、出力デバイスの白点との差を考慮しながら、色域内を含むすべての色を相対的に
ずらします。
●
kCGRenderingIntentPerceptual - 視覚的な関係を維持。色と色との間の視覚的な関係を維持す
るよう、グラフィックスコンテキストの色域を、出力デバイスの色域内に圧縮します。写真その
他、複雑で細かな画像に向いています。
●
kCGRenderingIntentSaturation - 相対的な彩度を維持。色の相対的な彩度を維持しながら、出
力デバイスの色域内に変換します。その結果、明るく鮮やかな色が得られます。図表やグラフな
ど、細かな装飾のない画像に向いています。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
62
座標変換
Quartz 2Dの描画モデルには、完全に独立した2つの座標系が定義されています。ドキュメントのペー
ジを表現するユーザ空間と、デバイス固有の解像度に基づくデバイス空間です。ユーザ空間の座標値
は、デバイス空間の解像度(ピクセル数)とは無関係に決まる浮動小数点数です。ドキュメントを印
刷、表示する際、Quartzはユーザ空間の座標値をデバイス空間の座標値に変換します。したがって、
アプリケーションのコードを記述し直したり、追加したりすることなく、各デバイスに最適な状態で
出力されるよう調整できるのです。
既定のユーザ空間は、現在の変換行列(CTM、Current Transformation Matrix)を操作することにより
変更できます。グラフィックスコンテキストを生成した時点では、CTMは恒等行列になっています。
Quartzの変換関数を施すことにより、CTMを変更し、したがってユーザ空間における描画方法を変え
ることができます。
この章では次のような事項を扱います。
●
座標変換用の関数の概要
●
CTMの変更方法
●
アフィン変換行列の生成方法
●
2つの変換が同等のものであることの判定法
●
ユーザ空間からデバイス空間への変換行列を取得する方法
●
アフィン変換の基盤となる数学の知識
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
63
座標変換
Quartzの変換関数について
Quartzの変換関数について
描画内容の平行移動、拡大縮小、回転は、Quartz 2Dに組み込みの変換関数を使って簡単に実行できま
す。数行程度のコードを記述するだけで、さまざまな変換を自由に組み合わせて実行できるのです。
図 5-1に、画像に拡大縮小と回転を施した様子を示します。各変換ではCTMを変更します。CTMはい
つでも、その時点における、ユーザ空間とデバイス空間の対応づけを表しています。したがって、出
力先がどのようなディスプレイやプリンタであっても、それに応じて最適の出力が得られるのです。
図 5-1
拡大縮小と回転を施した様子
Quartz 2Dには、CTMを取得し、変更するための関数が5つあります。回転、平行移動、拡大縮小だけ
でなく、一般のアフィン変換行列をCTMに結合する(行列を掛ける)ことも可能です。詳しくは、“現
在の変換行列の修正” (64 ページ)を参照してください。
ユーザ空間には作用しない(明示的に適用しない限り、CTMには結合されない)アフィン変換も生成
できます。専用の関数でアフィン変換を生成しておき、必要になった時点でCTMに結合することにな
ります。詳しくは、“アフィン変換の生成” (67 ページ)を参照してください。
いずれも、使うだけであれば、行列の数学的な意味を知っている必要はありません。しかし、変換関
数を呼び出したときQuartzの内部で実行している処理を理解しておきたい場合は、“行列の数学的な取
り扱い” (69 ページ)を参照してください。
現在の変換行列の修正
CTMを操作することにより、ページに回転、拡大縮小、平行移動を施したうえで画像を描画すること
ができます。その結果、オブジェクトに対して回転、拡大縮小、平行移動を施したのと同じ効果が得
られます。CTMを修正する前にグラフィックス状態を保存し、描画後は元に戻せるようにしてくださ
い。また、CTMに一般のアフィン変換を結合することも可能です(“アフィン変換の生成” (67 ペー
ジ)を参照)。この章では、4種類の演算(並行移動、回転、拡大縮小、結合)と、これを実行する
CTM関数について解説します。
次のコードで画像を描画できます。ただし、有効なグラフィックスコンテキスト、描画範囲を表す矩
形を指すポインタ、有効なCGImageオブジェクトがあらかじめ用意されているとします。ここで描画
するのは鶏の画像です(図 5-2を参照)。以下、この画像にさまざまな変換を施して描画する方法を
説明します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
64
座標変換
現在の変換行列の修正
CGContextDrawImage (myContext, rect, myImage);
図 5-2
変換を施す前の画像
平行移動は、x軸方向とy軸方向の移動量を指定し、座標空間の原点を移動する演算です。関数
CGContextTranslateCTMで、各点のx座標、y座標を、指定した量だけずらすことができます。図 5-3
に、次のコードを実行して、x軸方向に100単位、y軸方向に50単位だけ平行移動した画像を示します。
CGContextTranslateCTM (myContext, 100, 50);
図 5-3
平行移動した画像
回転は、角度を指定し、原点を中心として座標空間を回転する演算です。関数CGContextRotateCTM
で、ラジアン単位で指定した角度の回転ができます。図 5-4に、次のコードを実行して、原点(ウイ
ンドウの左下隅)を中心に-45°回転した画像を示します。
CGContextRotateCTM (myContext, radians(–45.));
回転の結果、画像の一部がコンテキスト外に出てしまうため、クリッピングが発生しています。回転
角はラジアン単位で指定してください。
回転を多用する場合は、ラジアンの変換ルーチンを用意するとよいかもしれません。
#include <math.h>
static inline double radians (double degrees) {return degrees * M_PI/180;}
図 5-4
回転した画像
拡大縮小は、x座標とy座標にそれぞれ、指定した値を掛けることにより、画像を拡大または縮小する
演算です。掛け合わせる値が1より大きいか小さいかによって、画像が拡大されるか縮小されるかが
決まります。さらに、x座標に負の値を掛ければ、x軸に沿って(左右に)座標が反転します。同様
に、y座標に負の値を掛ければ、横軸を中心として座標が反転します。x軸方向、y軸方向の拡大縮小
率を指定して、関数CGContextScaleCTMを実行してください。図 5-5に、次のコードを実行して、x
座標を0.5倍、y座標を0.75倍に縮小した画像を示します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
65
座標変換
現在の変換行列の修正
CGContextScaleCTM (myContext, .5, .75);
図 5-5
拡大縮小を施した画像
結合は、2つの行列を掛け合わせることにより、変換を組み合わせる操作です。各行列による変換を
順次施したのと同じ効果を、ひとつの行列で実現できます。CTMに掛け合わせるアフィン変換行列を
指定して、関数CGContextConcatCTMを実行してください。アフィン変換およびその行列を生成する
関数については、“アフィン変換の生成” (67 ページ)を参照してください。
複数の変換を順次施すためには、グラフィックス状態を復元せずに、変換関数を順次実行する、とい
う方法もあります。図 5-6に、次のコードを実行して、画像を平行移動し、次に回転した結果を示し
ます。
CGContextTranslateCTM (myContext, w,h);
CGContextRotateCTM (myContext, radians(-180.));
図 5-6
平行移動と回転を施した画像
図 5-7に、次のコードを実行して、画像を平行移動し、縮小し、次いで回転した結果を示します。
CGContextTranslateCTM (myContext, w/4, 0);
CGContextScaleCTM (myContext, .25,
.5);
CGContextRotateCTM (myContext, radians ( 22.));
図 5-7
平行移動、拡大縮小、回転を施した画像
複数の変換を施す場合はその順序も重要です。たとえば、上記とは逆の順序で変換を施すと、違う結
果になります。図 5-7を生成したときとは逆順に、次のコードで変換を施した結果を図 5-8に示しま
す。
CGContextRotateCTM (myContext, radians ( 22.));
CGContextScaleCTM (myContext, .25,
.5);
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
66
座標変換
アフィン変換の生成
CGContextTranslateCTM (myContext, w/4, 0);
図 5-8
回転、拡大縮小、平行移動を施した画像
アフィン変換の生成
Quartzには、CTMではなく行列そのものに演算を施す、アフィン変換関数があります。この関数群を
使って変換行列を組み立てておき、必要な時点で、関数CGContextConcatCTMでCTMに適用すること
ができるのです。アフィン変換関数の演算対象や戻り値はCGAffineTransformデータ構造体です。
アフィン変換行列をいくつでも用意しておき、必要に応じて繰り返し使うことが可能です。
CTM関数と同様、アフィン変換行列に対しても、平行移動、回転、拡大縮小、結合の演算が可能で
す。表 5-1に、演算を施す関数とその使い方を示します。平行移動、回転、拡大縮小のそれぞれにつ
いて、2つずつ関数があることに注意してください。
表 5-1
平行移動、回転、拡大縮小を施すアフィン変換関数
関数
用途
CGAffineTransformMakeTranslation
移動量(x、y)を指定して、新規に変換行列を組み立てま
す。
CGAffineTransformTranslate
既存のアフィン変換行列に平行移動の演算を施します。
CGAffineTransformMakeRotation
回転角をラジアン単位で指定して、新規に変換行列を組
み立てます。
CGAffineTransformRotate
既存のアフィン変換行列に回転の演算を施します。
CGAffineTransformMakeScale
x軸方向、y軸方向の拡大縮小率を指定して、新規に変換行
列を組み立てます。
CGAffineTransformScale
既存のアフィン変換行列に拡大縮小の演算を施します。
Quartzには逆行列を求めるアフィン変換関数CGAffineTransformInvertも用意されています。逆行
列は一般に、変換済みのオブジェクト内の点を逆変換するために使います。逆変換は行列によって変
換された値の元の値を取得する場合に便利です。つまり、行列を逆変換し、得られた値に逆変換行列
を乗じた結果が元の値です。通常は、逆変換が必要になることはありません。CTMによる変換効果を
元に戻すためには、あらかじめグラフィックス状態を保存しておき、復元すればよいからです。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
67
座標変換
アフィン変換の評価
空間全体でなく、ある特定の点や大きさを表す値を変換する必要が生じることもあります。また、
CGPoint構造体に対して変換を施したい場合は、関数CGPointApplyAffineTransformを使います。
また、CGSize構造体に対して変換を施したい場合は、関数CGSizeApplyAffineTransformを使いま
す。CGRect構造体については、関数CGRectApplyAffineTransformで変換を施します。この関数は、
引数として渡された矩形の頂点を変換し、それを内包する、辺が水平および垂直である最小の矩形を
返します。変換が拡大縮小と平行移動だけであれば、矩形の頂点の変換先は、戻り値である矩形の頂
点の位置と一致します。
どのようなアフィン変換でも関数CGAffineTransformMakeで生成できますが、他の生成関数と違い、
変換行列を引数として渡す必要があります。この関数を活用するためには、行列の数学的な取り扱い
を理解しなければなりません。“行列の数学的な取り扱い” (69 ページ)を参照してください。
アフィン変換の評価
あるアフィン変換が別のアフィン変換と等しいかどうか、関数CGAffineTransformEqualToTransform
で判定できます。等しければtrue、そうでなければfalseを返すようになっています。
関数CGAffineTransformIsIdentityは、ある変換が恒等変換であるかどうかを判断するために使い
ます。恒等変換は、平行移動も拡大縮小も回転もしません。どのような座標値を入力しても、値がそ
のまま返されます。Quartzの定数CGAffineTransformIdentityは恒等変換を表します。
ユーザ空間からデバイス空間への変換の取得
Quartz 2Dでは通常、描画はユーザ空間でのみ行います。デバイス空間との変換はQuartz側で自動的に
実行するようになっています。ユーザ空間からデバイス空間への変換に用いるアフィン変換を、アプ
リケーション側で取得する必要があれば、関数CGContextGetUserSpaceToDeviceSpaceTransform
を使ってください。
次の形状寸法について、ユーザ空間とデバイス空間の変換を行う便宜関数が用意されています。関数
CGContextGetUserSpaceToDeviceSpaceTransformでアフィン変換を取得して適用するよりも容易
でしょう。
●
●
●
Points. 関数CGContextConvertPointToDeviceSpaceおよびCGContextConvertPointToUserSpace
は、CGPointデータ型の変換を行います。
大きさ。関数CGContextConvertSizeToDeviceSpaceおよびCGContextConvertSizeToUserSpace
は、CGSizeデータ型の変換を行います。
矩形. 関数CGContextConvertRectToDeviceSpaceおよびCGContextConvertRectToUserSpace
は、CGRectデータ型の変換を行います。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
68
座標変換
行列の数学的な取り扱い
行列の数学的な取り扱い
Quartz 2Dの関数のうち、行列の数学的な取り扱いを理解していなければ使えないのは、関数
CGAffineTransformMakeだけです。3 x 3行列のうち6つの要素を指定して、アフィン変換を生成する
関数です。アフィン変換行列を独自に生成する必要がなくても、変換関数の基盤となっている数学に
は興味があるかもしれません。特に関心がなければ次の章まで読み飛ばしてください。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
69
座標変換
行列の数学的な取り扱い
3 x 3の変換行列のうち重要な6つの要素、すなわち、a 、b 、c 、d 、tx 、ty を示します。
注意: 行列の一番右の列は常に定数(0, 0, 1)です。これは結合演算ができるようにするために
必要です(詳しくは後述)。数学的に正しい記述にするために載せてあります。
上述の3 x 3変換行列が与えられれば、次の式で点(x , y )を点(x’, y ’)に変換できます。
得られた結果は、点の位置を、変換行列の要素(変数)で決まる、別の座標系で表示したものになり
ます。行列を使って変換式を表示しましたが、これは次の計算を表します。
次の行列は恒等行列です。平行移動、拡大縮小、回転のいずれもしません。ある座標にこの行列を掛
けると、常に同じ座標が得られます。
先に示した変換式を当てはめると、この行列により得られる新しい点(x ', y ')は、元の点(x , y )と同じで
あることがわかります。
次の行列は平行移動演算を表します。
平行移動の計算は次の式で行います。
次の行列は、点(x , y )に対する拡大縮小演算を表します。
拡大縮小の計算は次の式で行います。
次の行列は、点(x , y )を反時計回りに角度aだけ回転する、回転演算を表します。
回転の計算は次の式で行います。
次の式は、回転演算と平行移動演算の結合を表します。
変換の計算は次の式で行います。
行列を結合する順序は重要です。行列の積は、可換ではありません。すなわち、行列Aに行列Bを掛け
た結果が、行列Bに行列Aを掛けた結果と等しくなるとは限らないのです。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
70
座標変換
行列の数学的な取り扱い
先に説明したように、アフィン変換行列に定数(0, 0, 1)の第3列があるのは、この結合演算ができるよ
うにするのが目的です。行列の積を計算できるのは、ある行列の列数が、もう一方の行列の行数と一
致している場合に限ります。2 x 3行列に別の2 x 3行列を掛けることはできません。そのため、定数の
列を追加する必要があるのです。
逆演算は、変換後の座標から元の座標を求めます。ある座標(x , y )を、行列Aで新しい座標(x ', y ')に変
換したとき、Aの逆行列を使って座標(x ', y ')を変換すると、元の座標(x , y )が得られます。行列とその
逆行列を掛けると恒等行列になります。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
71
パターン
パターンとは、描画演算を反復してグラフィックスコンテキスト上に描画したもののことです。パ
ターンは色と同じように使えます。(色の代わりに)パターンを指定して描画すると、Quartzはペー
ジをパターン画像と同じ大きさのセル群に分割し、別途渡されたコールバック関数を使って、各セル
に描画します。図 6-1に、ウインドウグラフィックスコンテキストにパターンを描画した様子を示し
ます。
図 6-1
ウインドウにパターンを描画した様子
パターンの解剖
パターンセルはパターンの基本成分です。図 6-1 (72 ページ)のパターンで使ったパターンセルを
図 6-2に示します。ただし周囲の黒い矩形は、パターンの一部ではありません。パターンセルの境界
を示すためにつけたものです。
図 6-2
パターンセル
このパターンセルの中には、色付きの4つの矩形と、その上側や右側にある空間が含まれます(図 6-3
を参照)。周囲の黒い矩形は、パターンの一部ではありません。パターンセルの境界を示すためにつ
けたものです。パターンセルを生成する際には、セルの境界を定義し、その内部に描画することにな
ります。
図 6-3
パターンセル(黒の矩形は各セルの境界)
パターンセルを並べるときの、水平方向と垂直方向の間隔も指定できます。図 6-3では、あるパター
ンセルのちょうど端の位置から次のパターンセルが始まるようにして、パターンセルどうしが接触す
るように配置してあります。これに対して図 6-4では、水平方向、垂直方向ともに、若干の間隔を設
けています。水平方向と垂直方向とで異なる間隔を指定しても構いません。また、間隔を負の値にす
れば、パターンセルどうしが重なり合うようになります。
図 6-4
パターンセルどうしの間隔
パターンセルを描画する際、座標系としてはパターン空間を使います。これは、パターンを生成する
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
72
パターン
パターンの解剖
際に指定した変換行列(パターン行列)によって既定のユーザ空間を変換した、抽象的な座標空間で
す。
注意: パターン空間は、ユーザ空間とは独立です。変換を施す前のパターン空間が、現在の
変換行列の状態にかかわらず、基盤となる(変換を施す前の)ユーザ空間にマップされま
す。パターン空間に変換を施す場合、その対象はパターン空間だけです。
パターン座標系に関する規約は、特段の設定をしていなければ、もとになったグラフィック
スコンテキストの規約がそのまま使われます。したがって、Quartzが使う座標系は、x軸の
右方向、y軸の上方向が正となります。一方、UIKitが生成するグラフィックスコンテキスト
では、y軸の下方向が正となっています。この規約は通常、座標系に所定の変換を結合する
ことによりグラフィックスコンテキストに適用しますが、この場合はQuartz側でも 、パター
ン空間の既定の規約を修正します。
変換行列として恒等行列を指定すれば、パターンセルには何も変換が施されません。しかし、適当な
変換行列を与えると、面白い効果が生じます。図 6-5に、図 6-2のパターンセルに拡大縮小を施した様
子を示します。図 6-6はパターンセルに回転を施した例です。このように、パターンセルに変換を施
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
73
パターン
色付きパターンとステンシル(色なし)パターン
すと、著しい効果が得られます。図 6-7に、パターンセルを水平方向と垂直方向に移動したとき、パ
ターンの原点が移動している様子を示します。図 6-1 (72 ページ)と違い、パターンがウインドウ
の端に接触していないことがわかります。
図 6-5
拡大縮小を施したパターンセル
図 6-6
回転を施したパターンセル
図 6-7
平行移動を施したパターンセル
色付きパターンとステンシル(色なし)パターン
色付きパターンには、文字通り色づけがなされています。パターンセルの生成時に決めた色を変更す
ると、パターンとしての意味が失われてしまいます。スコティッシュタータンチェック(たとえば図
6-8)は色付きパターンのひとつです。色付きパターンの色は、パターンセルの描画過程ではなく、
生成過程で指定します。
図 6-8
色付きパターンには色づけがなされている
これに対し、形状だけが定義されたパターンもあります。ステンシルパターンや色なしパターン、場
合によっては画像マスクと呼ばれます。図 6-9に示す赤と黒の星パターンは、同じパターンセルをも
とに描画したものです。セル自体は、塗りつぶした星形という、ひとつの図形から成ります。パター
ンセルを定義する時点では色を決めないでおき、描画の際に指定します。
図 6-9
ステンシルパターンには色の指定がない
Quartz 2Dではどちらのパターンも生成できます。
タイリング
タイリングとは、ページのある部分にパターンセルを描画する処理のことです。デバイスにパターン
を描画する際には、デバイス空間に合わせて調整する必要が生じることがあります。というのも、
ユーザ空間で定義したパターンセルは、その単位とデバイス上のピクセルに差があるため、ぴったり
と(誤差なく)描画することができないのです。
そこで、必要に応じてパターンを調整する方法が、3通り組み込まれています。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
74
パターン
パターンの使い方
●
●
●
パターンを保存。パターンセル間の間隔を最小限(デバイスの1ピクセル未満)調整します。こ
れを歪みなし方式と呼びます。
セル間の間隔を保存。パターンセルを最小限(デバイスの1ピクセル未満)歪ませます。これを
一定間隔(最小限の歪み)方式と呼びます。
セル間の間隔を保存(上記の方式と同様)。ただし、高速にタイリングできるよう、セルについ
ても若干の歪みを容認します。これを一定間隔方式と呼びます。
パターンの使い方
パターンは、色と同じように、塗りつぶしや線つけのパターンを設定した上で描画関数を呼び出す、
という手順で使います。設定したパターンを、いわば「塗料」として使うわけです。たとえば、矩形
を無地の色で塗りつぶす場合、まずCGContextSetFillColorなどの関数で塗りつぶし色を設定しま
す。次に関数CGContextFillRectで、この色の塗りつぶし矩形を描画します。一方、パターンを指
定して描画する場合は、まず関数CGContextSetFillPatternでパターンを設定します。次に関数
CGContextFillRectで、このパターンの塗りつぶし矩形を描画します。色とパターンの違いは、パ
ターンには「定義する」過程が必要であることです。パターンや色に関する情報を、関数
CGContextSetFillPatternに渡して設定します。パターンを生成、設定、描画する手順については、
“色付きパターンの描画” (76 ページ)、“ステンシルパターンの描画” (82 ページ)を参照してくだ
さい。
指定したパターンで描画する際、Quartzの内部で実行している処理の例を以下に示します。パターン
を指定して塗りつぶしや線つけをするとき、概念的には、次のようにしてパターンセルを描画してい
ます。
1.
グラフィックス状態を保存します。
2.
現在の変換行列(CTM)を、パターンセルの原点に平行移動するものにします。
3.
CTMにパターン行列を結合します。
4.
パターンセルの境界矩形に合わせてクリッピングするよう設定します。
5.
パターンセルを描画するコールバック関数を呼び出します。
6.
グラフィックス状態を元の状態に復元します。
タイリング、すなわち、描画空間にパターンセルを反復して描画し、空間全体を埋め尽くす処理は、
すべてQuartz側で実行します。パターンを使って、塗りつぶしや線つけが可能です。パターンセルの
大きさも自由です。パターンがはっきりわかるように描画するためには、パターンセル全体が描画範
囲内に納まるようにしなければなりません。たとえば、パターンセルの大きさが8 x 10単位、これを
使って引く線の幅が2単位であれば、パターンセルの方が線幅よりも広いのでクリッピングされてし
まいます。これでは、どんなパターンなのかわからないでしょう。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
75
パターン
色付きパターンの描画
色付きパターンの描画
色付きパターンを描画する5段階の手順を、以下の各節で説明します。
1.
“色付きパターンセルを描画するコールバック関数の記述” (76 ページ)
2.
“色付きパターンの色空間の設定” (77 ページ)
3.
“色付きパターンの構造の設定” (78 ページ)
4.
“色付きパターンを塗りつぶしや線つけのパターンとして指定” (79 ページ)
5.
“色付きパターンを用いた描画” (80 ページ)
手順はステンシルパターンの場合もほとんど同じです。色情報の設定方法が違うだけです。上記の手
順全体を盛り込んだコード例については、“色付きパターンを用いる完全な描画関数例” (80 ページ)
を参照してください。
色付きパターンセルを描画するコールバック関数の記述
パターンセルの外観は、開発者が自由に決めることができます。たとえばリスト 6-1 (77 ページ)
のコードは、図 6-2 (72 ページ)に示すパターンセルを描画します。先に説明したように、パター
ンセルを囲む黒線は、セルを構成する一部ではありません。パターンセルの境界が、コードで描画さ
れる矩形よりも大きいことを示すために示してあります。パターンの大きさは別途指定します。
パターンセルの描画関数は、次のような形式のコールバックです。
typedef void (*CGPatternDrawPatternCallback) (
void *info,
CGContextRef context
);
関数名は自由に決めて構いません。リスト 6-1ではMyDrawColoredPatternという関数名にしていま
す。コールバック関数は2つの引数を取ります。
●
info:パターンに関連づけられたプライベートデータを指す汎用ポインタ。省略可。必要がない
場合はNULLを渡します。このコールバック関数に渡されるデータは、後でパターンを生成する際
に渡すデータと同じです。
●
context:パターンセルの描画に用いるグラフィックスコンテキスト。
リスト 6-1のコードで描画するパターンセルは、どのようなものでも構いません。生成したいパター
ンに応じて、自由に描画コードを記述してください。このコードについては次の点が重要です。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
76
パターン
色付きパターンの描画
パターンの大きさは別途宣言します。描画コードを記述する際には、この大きさを念頭に置いて
おかなければなりません。ここでは大域的に大きさを宣言しています。注釈を除くと、描画関数
内に大きさを明示している箇所はありません。パターンの大きさはこの後で指定します。“色付き
パターンの構造の設定” (78 ページ)を参照してください。
●
描画関数の仕様は、CGPatternDrawPatternCallbackというコールバック型として定義されてい
ます。
●
コード内では色を設定しています。これが色付きパターンであるゆえんです。
●
リスト 6-1
色付きパターンセルを描画するコールバック関数
#define H_PATTERN_SIZE 16
#define V_PATTERN_SIZE 18
void MyDrawColoredPattern (void *info, CGContextRef myContext)
{
CGFloat subunit = 5; // the pattern cell itself is 16 by 18
CGRect
myRect1 = {{0,0}, {subunit, subunit}},
myRect2 = {{subunit, subunit}, {subunit, subunit}},
myRect3 = {{0,subunit}, {subunit, subunit}},
myRect4 = {{subunit,0}, {subunit, subunit}};
CGContextSetRGBFillColor (myContext, 0, 0, 1, 0.5);
CGContextFillRect (myContext, myRect1);
CGContextSetRGBFillColor (myContext, 1, 0, 0, 0.5);
CGContextFillRect (myContext, myRect2);
CGContextSetRGBFillColor (myContext, 0, 1, 0, 0.5);
CGContextFillRect (myContext, myRect3);
CGContextSetRGBFillColor (myContext, .5, 0, .5, 0.5);
CGContextFillRect (myContext, myRect4);
}
色付きパターンの色空間の設定
リスト 6-1 (77 ページ)のコードでは、色を指定してパターンセルを描画しています。描画ルーチ
ンで指定した通りの色で描画されるよう、基盤となるパターン色空間としてNULLを設定してください
(リスト 6-2を参照)。コード例を示した後、番号がついている行について詳しく説明します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
77
パターン
色付きパターンの描画
リスト 6-2
基盤となるパターン色空間の生成
CGColorSpaceRef patternSpace;
patternSpace = CGColorSpaceCreatePattern (NULL);
// 1
CGContextSetFillColorSpace (myContext, patternSpace);
// 2
CGColorSpaceRelease (patternSpace);
// 3
このコードが実行することを以下に示します。
1.
色付きパターンの描画に用いる適切なパターン色空間を生成するため、基盤色空間として
CGColorSpaceCreatePatternを渡して関数NULLを実行します。
2.
塗りつぶし色空間として、パターン色空間を設定します。パターンを使って線つけをするのであ
れば、CGContextSetStrokeColorSpaceを実行します。
3.
パターン色空間を解除します。
色付きパターンの構造の設定
パターンの構造に関する情報をCGPatternオブジェクトに設定します。CGPatternオブジェクトの生成
には関数CGPatternCreateを使います。その仕様(引数並び)をリスト 6-3に示します。
リスト 6-3
CGPatternCreate関数の仕様
CGPatternRef CGPatternCreate (
void *info,
CGRect bounds,
CGAffineTransform matrix,
CGFloat xStep,
CGFloat yStep,
CGPatternTiling tiling,
bool isColored,
const CGPatternCallbacks *callbacks );
引数infoはプライベートデータを指すポインタで、これを介して描画コールバック関数に任意の情報
を渡すことができます。“色付きパターンセルを描画するコールバック関数の記述” (76 ページ)も
参照してください。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
78
パターン
色付きパターンの描画
パターンセルの大きさを、引数boundsで指定します。引数matrixでパターン行列を指定します。パ
ターン座標系を、グラフィックスコンテキストの既定の座標系に変換する行列です。グラフィックス
コンテキストと同じ座標系で描画する場合は、恒等行列を指定してください。引数xStepおよびyStep
には、セル間の水平方向、垂直方向の間隔を、パターン座標系で指定します。境界、パターン行列、
間隔については、“パターンの解剖” (72 ページ)を参照してください。
引数tilingには次のいずれかの値を指定します。
●
kCGPatternTilingNoDistortion
●
kCGPatternTilingConstantSpacingMinimalDistortion
●
kCGPatternTilingConstantSpacing
タイリングについては、“タイリング” (74 ページ)を参照してください。
引数isColoredは、パターンセルが色付き(true)かステンシル(false)かを表します。trueを指
定した場合、パターン描画コールバック関数でパターン色を指定し、さらに、色付きのパターン色空
間を設定しなければなりません(“色付きパターンの色空間の設定” (77 ページ)を参照)。
関数CGPatternCreateに渡す最後の引数は、CGPatternCallbacksデータ構造体を指すポインタで
す。この構造体は3つの要素から成ります。
struct CGPatternCallbacks
{
unsigned int version;
CGPatternDrawPatternCallback drawPattern;
CGPatternReleaseInfoCallback releaseInfo;
};
versionには0を設定してください。drawPatternには描画コールバック関数のポインタを設定しま
す。要素releaseInfoは、CGPatternオブジェクトの解除時に呼び出されるコールバック関数のポイン
タです。この中で、描画コールバック関数に渡した引数infoの領域を解除します。この引数にデータ
を渡していない場合は、関数ポインタとしてNULLを設定してください。
色付きパターンを塗りつぶしや線つけのパターンとして指定
パターンを塗りつぶしや線つけに用いるためには、関数CGContextSetFillPatternまたは
CGContextSetStrokePatternを使います。この関数の呼び出し以降、指定したパターンが、塗りつ
ぶしや線つけに使われるようになります。
いずれの関数も、次の3つの引数を取ります。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
79
パターン
色付きパターンの描画
●
グラフィックスコンテキスト
●
先に生成したCGPatternオブジェクト
●
色成分の配列
色付きパターンはそれ自身に色が設定されていますが、別にアルファ値をひとつ指定して、全体がそ
の透明度で描画されるようにする必要があります。アルファ値は1(完全に不透明)から0(完全に透
明)の範囲で指定します。塗りつぶしに用いる色付きパレットの透明度を設定するコード例を以下に
示します。
CGFloat alpha = 1;
CGContextSetFillPattern (myContext, myPattern, &alpha);
色付きパターンを用いた描画
以上の準備が終わると、Quartz 2Dの関数を自由に呼び出して描画ができるようになります。描画の
際、パターンはいわば「塗料」として使われます。CGContextStrokePath、CGContextFillPath、
CGContextFillRectなど、さまざまな描画関数を自由に呼び出して使えます。
色付きパターンを用いる完全な描画関数例
リスト 6-4に、色付きパターンを使って描画する関数の例を示します。これまでに説明した処理をす
べて組み込んであります。コード例を示した後、番号がついている行について詳しく説明します。
リスト 6-4
色付きパターンを使って描画する関数の例
void MyColoredPatternPainting (CGContextRef myContext,
CGRect rect)
{
CGPatternRef
pattern;
// 1
CGColorSpaceRef patternSpace;
// 2
CGFloat
alpha = 1,
// 3
width, height;
// 4
CGPatternCallbacks callbacks = {0,
// 5
static const
&MyDrawPattern,
NULL};
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
80
パターン
色付きパターンの描画
CGContextSaveGState (myContext);
patternSpace = CGColorSpaceCreatePattern (NULL);
// 6
CGContextSetFillColorSpace (myContext, patternSpace);
// 7
CGColorSpaceRelease (patternSpace);
// 8
pattern = CGPatternCreate (NULL,
// 9
CGRectMake (0, 0, H_PSIZE, V_PSIZE),
// 10
CGAffineTransformMake (1, 0, 0, 1, 0, 0),
// 11
H_PATTERN_SIZE,
// 12
V_PATTERN_SIZE,
// 13
kCGPatternTilingConstantSpacing,
// 14
true,
// 15
&callbacks);
// 16
CGContextSetFillPattern (myContext, pattern, &alpha);
// 17
CGPatternRelease (pattern);
// 18
CGContextFillRect (myContext, rect);
// 19
CGContextRestoreGState (myContext);
}
このコードが実行することを以下に示します。
1.
CGPatternオブジェクトを宣言します(生成はこの後)。
2.
パターン色空間用の記憶域を宣言します(生成はこの後)。
3.
アルファ値を表す変数を宣言し、その値を1とします。これは完全に不透明であることを表しま
す。
4.
ウインドウの幅と高さを表す変数を宣言します。この例では、ウインドウの領域上にパターンを
描画することになります。
5.
コールバック構造体を宣言し、版番号を表す0と、描画コールバック関数を指すポインタを設定
します。この例ではreleaseInfoコールバック関数は不要なので、該当する要素はNULLとしていま
す。
6.
パターン空間オブジェクトを生成し、パターンの基盤色空間としてNULLを設定します。色付きパ
ターンは描画コールバック内で独自の色を設定するので、色空間としてNULLを設定しています。
7.
塗りつぶし色空間として、ここで生成したパターン色空間オブジェクトを設定します。
8.
パターン色空間オブジェクトを解除します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
81
パターン
ステンシルパターンの描画
9.
NULLを渡しているのは、このパターンの場合、描画コールバック関数に渡すべき追加情報がない
からです。
10. CGRectオブジェクトを渡してパターンセルの境界を指定します。
11. CGAffineTransform行列を渡して、パターン空間を、パターンが用いるコンテキストの、既定のユー
ザ空間に変換する方法を指定します。この例では恒等行列を渡しています。
12. パターンの高さを、各セルの起点の垂直変位として指定します。この例では、セルのすぐ隣に次
のセルを描画します。
13. パターンの幅を、各セルの起点の水平変位として指定します。
14. パターンのレンダリング方法として、定数kCGPatternTilingConstantSpacingを渡します。詳
しくは、“タイリング” (74 ページ)を参照してください。
15. 引数trueとしてisColoredを渡し、描画するのが色付きパターンである旨を指定します。
16. 版情報や描画コールバック関数のポインタを収容した、コールバック構造体を指すポインタを渡
します。
17. 塗りつぶしパターンを設定します。コンテキスト、ここで生成したCGPatternオブジェクト、アル
ファ値(パターンの透明度)を指すポインタを渡しています。
18. CGPatternオブジェクトを解除します。
19. MyColoredPatternPaintingルーチンに渡したウインドウの大きさに相当する矩形を塗りつぶし
ます。ここで設定したパターンで、矩形が塗りつぶされます。
ステンシルパターンの描画
ステンシルパターンを描画する5段階の手順を、以下の各節で説明します。
1.
“ステンシルパターンセルを描画するコールバック関数の記述” (83 ページ)
2.
“ステンシルパターンの色空間の設定” (84 ページ)
3.
“ステンシルパターンの構造の設定” (84 ページ)
4.
“ステンシルパターンを塗りつぶしや線つけのパターンとして指定” (85 ページ)
5.
“ステンシルパターンを用いた描画” (85 ページ)
手順は色付きパターンの場合とほとんど同じです。色情報の設定方法が違うだけです。上記の手順全
体を盛り込んだコード例については、“ステンシルパターンを用いる完全な描画関数例” (85 ページ)
を参照してください。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
82
パターン
ステンシルパターンの描画
ステンシルパターンセルを描画するコールバック関数の記述
ステンシルパターンを描画するコールバック関数の書き方は、色付きパターンの場合と同様です。“色
付きパターンセルを描画するコールバック関数の記述” (76 ページ)を参照してください。違いは色
を指定しない点だけです。図 6-10に示すパターンセルは、描画コールバック関数内で色を指定してい
ません。パターン色空間における描画色を、別に指定することになります。
図 6-10
ステンシルパターンセル
リスト 6-5のコードは、図 6-10のようなパターンセルを描画するものです。単にパスを生成し、塗り
つぶしているだけです。色は設定していないことに注意してください。
リスト 6-5
ステンシルパターンセルを描画するコールバック関数
#define PSIZE 16
// size of the pattern cell
static void MyDrawStencilStar (void *info, CGContextRef myContext)
{
int k;
double r, theta;
r = 0.8 * PSIZE / 2;
theta = 2 * M_PI * (2.0 / 5.0); // 144 degrees
CGContextTranslateCTM (myContext, PSIZE/2, PSIZE/2);
CGContextMoveToPoint(myContext, 0, r);
for (k = 1; k < 5; k++) {
CGContextAddLineToPoint (myContext,
r * sin(k * theta),
r * cos(k * theta));
}
CGContextClosePath(myContext);
CGContextFillPath(myContext);
}
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
83
パターン
ステンシルパターンの描画
ステンシルパターンの色空間の設定
ステンシルパターンを描画するためには、リスト 6-6のように、パターン色空間を設定する必要があ
ります。コード例を示した後、番号がついている行について詳しく説明します。
リスト 6-6
ステンシルパターン用のパターン色空間を生成するコード例
CGPatternRef pattern;
CGColorSpaceRef baseSpace;
CGColorSpaceRef patternSpace;
baseSpace = CGColorSpaceCreateWithName (kCGColorSpaceGenericRGB);
// 1
patternSpace = CGColorSpaceCreatePattern (baseSpace);
// 2
CGContextSetFillColorSpace (myContext, patternSpace);
// 3
CGColorSpaceRelease(patternSpace);
// 4
CGColorSpaceRelease(baseSpace);
// 5
このコードが実行することを以下に示します。
1.
この関数は標準RGB空間を生成します。標準色空間を使えば、色合わせの処理をシステムに委ね
ることができます。詳しくは、“標準色空間の生成” (59 ページ)を参照してください。
2.
パターン色空間を生成します。パターンに色を表現する方法を指定する色空間です。これ以降、
パターンの色を設定する際には、このパターン色空間上で指定する必要があります。たとえばRGB
値で指定する、といった具合です。
3.
パターンを塗りつぶす際に用いる色空間を設定します。線つけの色空間は関数
CGContextSetStrokeColorSpaceで設定します。
4.
パターン色空間オブジェクトを解除します。
5.
基盤となる色空間オブジェクトを解除します。
ステンシルパターンの構造の設定
色付きパターンの場合、パターンの構造に関する情報は関数CGPatternCreateで指定しました。これ
との違いは、引数falseにisColoredを指定することだけです。関数“色付きパターンの構造の設
定” (78 ページ)「色付きパターンの構造の設定」CGPatternCreateを参照してください。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
84
パターン
ステンシルパターンの描画
ステンシルパターンを塗りつぶしや線つけのパターンとして指定
パターンを塗りつぶしや線つけに用いるためには、関数CGContextSetFillPatternまたは
CGContextSetStrokePatternを使います。この関数の呼び出し以降、指定したパターンが、塗りつ
ぶしや線つけに使われるようになります。
いずれの関数も、次の3つの引数を取ります。
●
グラフィックスコンテキスト
●
先に生成したCGPatternオブジェクト
●
色成分の配列
ステンレスパターンの場合、描画コールバック関数では色を設定しないので、代わりに塗りつぶしや
線つけの関数に色を渡し、どのような色で描画するかを指定します。リスト 6-7にステンシルパター
ンの色を設定するコード例を示します。配列colorの値は、先に設定した色空間における値と解釈され
ます。この例ではデバイスRGBを使っているので、配列colorの値は、赤、緑、青の各成分を表しま
す。4つめの値は透明度です。
リスト 6-7
ステンシルパターンの色を設定するコード
static const CGFloat color[4] = { 0, 1, 1, 0.5 }; //cyan, 50% transparent
CGContextSetFillPattern (myContext, myPattern, color);
ステンシルパターンを用いた描画
以上の準備が終わると、Quartz 2Dの関数を自由に呼び出して描画ができるようになります。描画の
際、パターンはいわば「塗料」として使われます。CGContextStrokePath、CGContextFillPath、
CGContextFillRectなど、さまざまな描画関数を自由に呼び出して使えます。
ステンシルパターンを用いる完全な描画関数例
リスト 6-8に、ステンシルパターンを使って描画する関数の例を示します。これまでに説明した処理
をすべて組み込んであります。コード例を示した後、番号がついている行について詳しく説明しま
す。
リスト 6-8
ステンシルパターンを使って描画する関数の例
#define PSIZE 16
void MyStencilPatternPainting (CGContextRef myContext,
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
85
パターン
ステンシルパターンの描画
const Rect *windowRect)
{
CGPatternRef pattern;
CGColorSpaceRef baseSpace;
CGColorSpaceRef patternSpace;
static const CGFloat color[4] = { 0, 1, 0, 1 };
// 1
static const CGPatternCallbacks callbacks = {0, &drawStar, NULL};
// 2
baseSpace = CGColorSpaceCreateDeviceRGB ();
// 3
patternSpace = CGColorSpaceCreatePattern (baseSpace);
// 4
CGContextSetFillColorSpace (myContext, patternSpace);
// 5
CGColorSpaceRelease (patternSpace);
CGColorSpaceRelease (baseSpace);
pattern = CGPatternCreate(NULL, CGRectMake(0, 0, PSIZE, PSIZE),
// 6
CGAffineTransformIdentity, PSIZE, PSIZE,
kCGPatternTilingConstantSpacing,
false, &callbacks);
CGContextSetFillPattern (myContext, pattern, color);
// 7
CGPatternRelease (pattern);
// 8
CGContextFillRect (myContext,CGRectMake (0,0,PSIZE*20,PSIZE*20));
// 9
}
このコードが実行することを以下に示します。
1.
色値を表す配列を宣言し、(RGB色空間で)不透明な緑を設定します。
2.
コールバック構造体を宣言し、版番号を表す0と、描画コールバック関数を指すポインタを設定
します。この例ではreleaseInfoコールバック関数は不要なので、該当する要素はNULLとしていま
す。
3.
RGBデバイス色空間を生成します。パターンをディスプレイ上に描画するのであれば、このよう
な色空間が必要です。
4.
RGBデバイス色空間から、パターン色空間オブジェクトを生成します。
5.
塗りつぶし色空間として、ここで生成したパターン色空間オブジェクトを設定します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
86
パターン
ステンシルパターンの描画
6.
パターンオブジェクトを生成します。最後から2番目の引数isColoredがfalseであることに注意
してください。ステンシルパターンには色が設定されていないので、この引数にはfalseを指定
する必要があります。他の引数は色付きパターンの場合と同様です。“色付きパターンを用いる完
全な描画関数例” (80 ページ)を参照してください。
7.
先に宣言した配列colorを渡して塗りつぶしパターンを設定します。
8.
CGPatternオブジェクトを解除します。
9.
矩形を塗りつぶします。ここで設定したパターンで、矩形が塗りつぶされます。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
87
影
影は、グラフィックスオブジェクトの奥に、若干位置をずらして描画する画像で、光を当てた効果を
真似ることができます(図 7-1を参照)。テキストに影をつけることも可能です。また、立体的に見
せることも、浮いているように見せることも可能です。
図 7-1
影
影には3つの特性があります。
●
xオフセット。水平方向の、画像とその影との距離を表します。
●
yオフセット。垂直方向の、画像とその影との距離を表します。
●
ぼかし値。影の画像にくっきりした境界を描く(図 7-2の左)か、境界を散らす(同図の右)か
を指定します。
この章では、影の描画の考え方と、影を生成するQuartz 2DのAPIについて説明します。
図 7-2
ぼかしのない影と、柔らかいぼかしを入れた影
影の描画の考え方
Quartzでは、影の状態をグラフィックス状態として管理します。設定は、グラフィックスコンテキス
ト、オフセット値、ぼかし値を指定して、関数CGContextSetShadowで行います。影の設定をする
と、それ以降に描画するオブジェクトには、(デバイスRBG色空間の)黒でアルファ値(透明度)が
1/3の影が描画されるようになります。すなわち、RGBA値{0, 0, 0, 1.0/3.0}で描画するのです。
色付きの影も描画できます。関数CGContextSetShadowWithColorに、グラフィックスコンテキス
ト、オフセット値、ぼかし値のほか、CGColorオブジェクトを指定して実行します。色の値は描画に
用いる色空間に応じて指定します。
あらかじめグラフィックス状態を保存しておいてから関数CGContextSetShadowや
CGContextSetShadowWithColorを呼び出せば、グラフィックス状態を復元することにより、影を解
除できます。また、影の色をNULLとすることによっても解除は可能です。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
88
影
コンテキストに応じた影のつけ方
コンテキストに応じた影のつけ方
先に述べたオフセット値は、影がつく側の位置を基準として、どこに影を描画するか、を表します。
コンテキストに応じ、次のようにして影の位置を計算します。
●
xオフセットが正であれば、グラフィックスオブジェクトの右側に影ができます。
●
Mac OS Xでは、yオフセットが正であれば上側に影ができます。これはQuartz 2Dの既定の座標系
に合致しています。
●
iOSの場合、Quartz 2D APIを使ってPDFコンテキストまたはビットマップコンテキストを生成した
とすると、yオフセットが正ならば上側に影ができます。
●
●
iOSで、グラフィックスコンテキストをUIKitで生成した場合(UIViewオブジェクトから生成した、
あるいは関数UIGraphicsBeginImageContextWithOptionsで生成したものなど)、yオフセット
が正ならば下側に影ができます。これはUIKit座標系の方式に合致しています。
影の描き方は、現在の変換行列の影響を受けません。
影の描画
影をつけながら描画する手順を以下に示します。
1.
グラフィックス状態を保存します。
2.
適当な値を指定して関数CGContextSetShadowを実行します。
3.
影を与えるオブジェクトを自由に描画します。
4.
グラフィックス状態を元の状態に戻します。
色付きの影をつけながら描画する手順を以下に示します。
1.
グラフィックス状態を保存します。
2.
CGColorSpaceオブジェクトを生成して、影の色値が正しく解釈されるようにします。
3.
影の色を指定するCGColorオブジェクトを生成します。
4.
適当な値を指定して関数CGContextSetShadowWithColorを実行します。
5.
影を与えるオブジェクトを自由に描画します。
6.
グラフィックス状態を元の状態に戻します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
89
影
影の描画
図 7-3に、色なしおよび色付きの影をつけて矩形を描画した様子を示します。
図 7-3
色付きの影、色なしの影
リスト 7-1のような矩形を描画するための影を設定する関数を、図 7-3に示します。コード例を示した
後、番号がついている行について詳しく説明します。
リスト 7-1
影を設定する関数
void MyDrawWithShadows (CGContextRef myContext,
// 1
CGFloat wd, CGFloat ht);
{
CGSize
CGFloat
CGColorRef
myShadowOffset = CGSizeMake (-15,
20);
myColorValues[] = {1, 0, 0, .6};
myColor;
// 2
// 3
// 4
CGColorSpaceRef myColorSpace;
// 5
CGContextSaveGState(myContext);
// 6
CGContextSetShadow (myContext, myShadowOffset, 5);
// 7
// Your drawing code here
// 8
CGContextSetRGBFillColor (myContext, 0, 1, 0, 1);
CGContextFillRect (myContext, CGRectMake (wd/3 + 75, ht/2 , wd/4, ht/4));
myColorSpace = CGColorSpaceCreateDeviceRGB ();
// 9
myColor = CGColorCreate (myColorSpace, myColorValues);
// 10
CGContextSetShadowWithColor (myContext, myShadowOffset, 5, myColor);
// 11
// Your drawing code here
// 12
CGContextSetRGBFillColor (myContext, 0, 0, 1, 1);
CGContextFillRect (myContext, CGRectMake (wd/3-75,ht/2-100,wd/4,ht/4));
CGColorRelease (myColor);
// 13
CGColorSpaceRelease (myColorSpace);
// 14
CGContextRestoreGState(myContext);
// 15
}
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
90
影
影の描画
このコードが実行することを以下に示します。
1.
引数として、矩形を描画する際に使う、グラフィックスコンテキスト、幅、高さの3つを取りま
す。
2.
影のオフセット値を設定する、CGSizeオブジェクトを宣言、生成します。オブジェクトの左に15
単位、上に20単位の位置に、影を描画することを表します。
3.
色値の配列を宣言します。この例ではRGBA色空間を使いますが、その旨をQuartzに設定しない限
り、正しく解釈できないので、値の配列だけがあっても意味はありません。
4.
色値を格納する領域の参照を宣言します。
5.
色空間の参照を格納する領域を宣言します。
6.
現在のグラフィックス状態を保存して、後で復元できるようにしておきます。
7.
影のオフセットとして先に宣言した値、ぼかし値として5(柔らかいぼかし)を設定します。影
の色値はRGBA色空間の{0, 0, 0, 1/3}になります(灰色)。
8.
次の2行で、図 7-3 (90 ページ)の右側のような矩形を描画します。この行を実際の描画コード
で置き換えてください。
9.
デバイスRGB色空間を生成します。CGColorオブジェクトを生成する際に、色空間を指定する必要
があります。
10. 先に生成したデバイスRGB色空間とRGBA値を指定して、CGColorオブジェクトを生成します。この
オブジェクトは影の色(赤、アルファ値は0.6)を表します。
11. ここで生成した赤を渡して、色付きの影を設定します。影の描画には、先に生成したオフセット
値と、ぼかし値として5(柔らかいぼかし)を使います。
12. 次の2行で、図 7-3 (90 ページ)の左側のような矩形を描画します。この行を実際の描画コード
で置き換えてください。
13. 必要なくなったので色オブジェクトを解除します。
14. 必要なくなったので色空間オブジェクトを解除します。
15. グラフィックス状態を、影を設定する前の状態に復元します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
91
グラデーション
グラデーションの生成に関して、Quartzには2つの不透過データ型、すなわちCGShadingRefと
CGGradientRefがあります。どちらを使っても、軸状や放射状のグラデーションを生成できます。グ
ラデーションとは、ある色から別の色へ、徐々に変化するような塗りつぶしのことです。
軸状グラデーション(または線形グラデーション )は、指定した2つの端点を結ぶ軸に沿って色が変
化します。この軸に垂直な直線上の点はすべて、色値が同じになります。
放射状グラデーションは、指定した2つの終端(一般にどちらも円)を結ぶ軸に沿って、放射状に色
が変化します。この軸上の点を中心とする円周上の点はすべて、色値が同じになります。グラデー
ションの円断面の半径は、終端の円の半径として定義されます。その間の各円は、一方の終端から他
方の終端に向かって、半径が線形に変化します。
この章では、Quartzで生成できる各種の軸状/放射状グラデーションの例を示し、グラデーションを描
画する2通りの考え方を比較した後、実際に生成する際に用いる不透過データ型の使い方を示します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
92
グラデーション
軸状/放射状のグラデーションの例
軸状/放射状のグラデーションの例
Quartzにはグラデーション効果を生み出すさまざまな機能が組み込まれています。この節では実際の
描画例をいくつか示します。図 8-1の軸状グラデーションは、橙色と黄色の端点を結ぶ軸に沿って色
が変化しています。軸は原点を通る傾き45°の直線です。
図 8-1
45°の軸に沿った軸状グラデーション
軸に沿っていくつもの点を決め、それぞれ色を指定することにより、図 8-2のように複雑なグラデー
ションも生成できます。開始点は赤、終了点は紫ですが、ほかにも軸上に5つの点を取り、橙、黄、
緑、青、藍をそれぞれ設定しています。同じ軸に沿って6つの軸状グラデーションを連ねた形、と考
えればわかりやすいでしょう。軸は図 8-1と同じ、傾き45°の直線にしていますが、そうでなくても構
いません。軸の傾きは、開始点と終了点の与え方によって決まります。
図 8-2
7つの点と色を指定して生成した軸状グラデーション
図 8-3に、明るい赤の小円と黒い大円を終端とする、放射状グラデーションの例を示します。
図 8-3
2つの円の間で徐々に色が変化する放射状グラデーション
色だけでなく、アルファ値を徐々に変化させる、あるいは色とアルファ値を同時に変化させることも
可能です。図 8-4に、赤、緑、青の成分は一定のままで、アルファ値だけを1.0から0.1まで変化させて
作ったグラデーションの例を示します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
93
グラデーション
CGShadingとCGGradientの違い
注意: アルファ成分を使ってグラデーションを変化させた場合、PDFコンテンツを描画する
際にこのグラデーションを取り込むことはできません。したがって、このようなグラデー
ションは印刷できないことになります。グラデーションをPDFに描画したい場合は、アル
ファ値として1.0を指定してください。
図 8-4
アルファ成分のみを変化させて生成した放射状グラデーション
同じ放射状グラデーションでも、終端円の位置によってさまざまな形状になります。一方の円の一部
または全部を、もう一方の円の外側に置くと、円の半径が同じならば円柱面、違っていれば円錐面に
なります。また、図 8-5のような、陰影がついた球面を描画するためにもよく使われます。これは、
単一の点(半径が0の円)を、もう一方の円の内部に置いて作ります。
図 8-5
1点と円周の間で色が徐々に変化する放射状グラデーション
放射状グラデーションを入れ子にすると、図 8-6のように複雑な効果が得られます環状体面(いわゆ
るドーナツ型)も、同心円を使って描画できます。
図 8-6
入れ子になった放射状グラデーション
CGShadingとCGGradientの違い
グラデーションを生成するためのオブジェクトが2種類あるので、どちらを使うべきか迷うかもしれ
ません。ここではその使い分けについて説明します。
不透過データ型CGShadingRefを使うと、グラデーション軸に沿った各点の色を自由に制御できます。
ただし、CGShadingオブジェクトを生成する前に、各点の色を決める関数を実装し、CGFunctionオブ
ジェクト(CGFunctionRef)を生成しておかなければなりません。独自の関数を用意することによ
り、図 8-1 (93 ページ)や図 8-3 (93 ページ)、図 8-5 (94 ページ)のような滑らかなグラデー
ションだけでなく、図 8-12 (107 ページ)のような奇抜な効果を得ることも可能になります。
CGShadingオブジェクトを生成する際には、軸状(線形)か放射状かを指定する必要があります。さ
らに、グラデーション計算関数(CGFunctionオブジェクトにカプセル化)、色空間、2つの端点(軸
状の場合)または終端円の中心と半径(放射状の場合)も指定してください。実際に描画する時点で
は、このCGShadingオブジェクトと描画コンテキストを関数CGContextDrawShadingに渡すだけです。
グラデーションの軸に沿った各点について、グラデーション計算関数が呼び出されます。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
94
グラデーション
開始点や終了点の先まで塗りつぶしを延長
CGGradientオブジェクトはCGShadingオブジェクトの機能を制限した簡易版です。不透過データ型
CGGradientRefを使えば、グラデーションの各点の色は自動的に計算されるので、計算関数を実装す
る必要はありません。オブジェクト生成時に、端点と色の配列を指定するだけで、軸に沿った各点の
色は自動的に計算されるようになっています。図 8-1 (93 ページ)のように開始点と終了点のみ与
えても、図 8-2 (93 ページ)のように、途中にいくつか端点を与えても構いません。開始点と終了
点以外にも端点を指定できることは、CGShadingオブジェクトにはない特徴です。
CGGradientオブジェクトの生成時に指定するのは、色空間と、開始点を0、終了点を1として相対的に
表した、いくつかの端点における色だけです。実際にコンテキストに描画する段階で、軸状か放射状
かを指定します。また、開始点と終了点(軸状の場合)または終端円の中心と半径(放射状の場合)
も、描画の時点で指定します(CGShadingオブジェクトの場合は、描画時ではなく生成時に指定する
ことになっていました)。
表 8-1に、この2つの不透過データ型の違いを要約して示します。
表 8-1
CGShadingとCGGradientの違い
CGGradient
CGShading
同じオブジェクトで軸状グラデーション
にも放射状グラデーションにも対応可
能。
軸状グラデーションと放射状グラデーションでそ
れぞれにオブジェクトを生成。
グラデーションの配置を描画時に指定。
グラデーションの配置をオブジェクト生成時に指
定。
各点の色はQuartz側で自動計算。
各点の色を計算するコールバック関数が必要。
色を指定する端点を3つ以上設定するこ
とも容易。
3つ以上の端点に色を指定するためには、それに応
じたコールバック関数を記述する必要があり、よ
り多くの開発作業が必要。
開始点や終了点の先まで塗りつぶしを延長
グラデーションで指定した開始点や終了点の先まで、単色で塗りつぶす指定も可能です。開始点や終
了点の色をそのまま、塗りつぶし色として使います。開始点を延長する、終了点を延長する、両方を
延長する、の3つから選べます。また、軸状グラデーションにも放射状グラデーションにも適用可能
です。CGShadingオブジェクト、CGGradientオブジェクトのどちらでも構いません。それぞれについ
て、延長の方法を指定する定数が定義されています(“CGGradientオブジェクトの使い方” (96 ペー
ジ)、“CGShadingオブジェクトの使い方” (99 ページ)を参照)。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
95
グラデーション
CGGradientオブジェクトの使い方
図 8-7に、軸状グラデーションの開始点と終了点を延長した例を示します。図に示した直線はグラデー
ションの軸を表します。開始点と終了点の色をそのまま使って塗りつぶしていることがわかります。
図 8-7
軸状グラデーションの延長
図 8-8に、放射状グラデーションの延長を無効にして描画した場合と、両端ともに延長した場合を並
べて示します。開始円と終了円の色をそのまま使い、単色で塗りつぶすようになっています。図に
は、開始円、終了円、グラデーション軸も示してあります。
図 8-8
放射状グラデーションの延長
CGGradientオブジェクトの使い方
CGGradientオブジェクトは、グラデーションを抽象的に定義したものです。具体的な配置ではなく、
開始点を0、終了点を1として相対的に表した、いくつかの点における色を定義します。同じオブジェ
クトが軸状グラデーションにも放射状グラデーションにも使えます。抽象的に定義したものなので、
CGShadingに比べ、同じオブジェクトを再利用できる可能性が高いことになります。具体的な配置が
固定されていないので、色遣いが同じであれば何度でも繰り返し使え、その都度CGGradientオブジェ
クトを生成する方法に比べてメモリ資源の節約にもなります。
各点の色は自動的に計算されるので、グラデーションを生成、描画する手順は次のように容易です。
1.
CGGradientオブジェクトを生成します。引数として、色空間、2組以上の色値の配列、2つ以上の
端点位置の配列、この配列の項目数を渡します。
2.
関数CGContextDrawLinearGradientまたはCGContextDrawRadialGradientでグラデーション
を描画します。コンテキスト、CGGradientオブジェクト、描画オプション、開始点と終了点(軸
状の場合)または終端円の中心と半径(放射状の場合)を指定します。
3.
不要になったらCGGradientオブジェクトを解除します。
位置は0.0以上1.0以下のCGFloat値として与えます。グラデーション軸に沿った長さを正規化した値
で、0.0は軸の開始点、1.0は軸の終了点に対応します。それ以外の値は、距離に比例した位置に対応
します。たとえば、0.25は開始点から軸長の1/4の長さだけ離れた位置、0.5は開始点と終了点のちょ
うど真ん中の位置になります。位置は少なくとも2つ与えなければなりません。位置を表す配列とし
てNULLを渡すと、第1の点が0、第2の点が1であると看做されます。
色成分の数は、指定した色空間によって決まります。画面に描画する場合、普通はRGB色空間を使う
ことになるでしょう。ほかにアルファ成分も扱うので、赤、緑、青、アルファ値の4つが必要です。
したがって色成分配列の要素数は、位置の個数に4を掛けた値になります。RGBAの色成分は、0.0から
1.0までの値で指定します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
96
グラデーション
CGGradientオブジェクトの使い方
リスト 8-1に、CGGradientオブジェクトを生成するコード例を示します。必要な変数を宣言した後、
位置と、必要な個数(この例では2 x 4 = 8)の色成分を設定しています。続いて標準RGB色空間を生成
します(iOSの場合、標準RGB色空間が使えないので、関数CGColorSpaceCreateDeviceRGBを使う必
要があります)。次に、必要な引数を渡して関数CGGradientCreateWithColorComponentsを実行し
ます。CGColorオブジェクトで色を設定し、関数CGGradientCreateWithColorsを実行しても構いま
せん。
リスト 8-1
CGGradientオブジェクトの生成
CGGradientRef myGradient;
CGColorSpaceRef myColorspace;
size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 1.0, 0.5, 0.4, 1.0,
// Start color
0.8, 0.8, 0.3, 1.0 }; // End color
myColorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
myGradient = CGGradientCreateWithColorComponents (myColorspace, components,
locations, num_locations);
生成したCGGradientオブジェクトを使って、軸状グラデーションまたは放射状グラデーションを描画
します。リスト 8-2に、軸状グラデーションの開始点と終了点を宣言、設定し、実際に描画するコー
ド例を示します。結果は図 8-1 (93 ページ)のようになります。なお、CGContextオブジェクト
(myContext)を取得する手順は省略します。
リスト 8-2
CGGradientオブジェクトを使って軸状グラデーションを描画
CGPoint myStartPoint, myEndPoint;
myStartPoint.x = 0.0;
myStartPoint.y = 0.0;
myEndPoint.x = 1.0;
myEndPoint.y = 1.0;
CGContextDrawLinearGradient (myContext, myGradient, myStartPoint, myEndPoint, 0);
リスト 8-3に、リスト 8-1 (97 ページ)で生成したCGGradientオブジェクトを使って、図 8-9 (98 ペー
ジ)のような放射状グラデーションを描画するコード例を示します。また、グラデーション領域を延
長し、単色で塗りつぶしています。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
97
グラデーション
CGGradientオブジェクトの使い方
リスト 8-3
CGGradientオブジェクトを使って放射状グラデーションを描画
CGPoint myStartPoint, myEndPoint;
CGFloat myStartRadius, myEndRadius;
myStartPoint.x = 0.15;
myStartPoint.y = 0.15;
myEndPoint.x = 0.5;
myEndPoint.y = 0.5;
myStartRadius = 0.1;
myEndRadius = 0.25;
CGContextDrawRadialGradient (myContext, myGradient, myStartPoint,
myStartRadius, myEndPoint, myEndRadius,
kCGGradientDrawsAfterEndLocation);
図 8-9
CGGradientオブジェクトを使って描画した放射状グラデーション
図 8-4 (94 ページ)に示した放射状グラデーションは、変数の値をリスト 8-4のようにして描画した
ものです。
リスト 8-4
アルファ値が徐々に変化する放射状グラデーションを生成する際に用いた変数
CGPoint myStartPoint, myEndPoint;
CGFloat myStartRadius, myEndRadius;
myStartPoint.x = 0.2;
myStartPoint.y = 0.5;
myEndPoint.x = 0.65;
myEndPoint.y = 0.5;
myStartRadius = 0.1;
myEndRadius = 0.25;
size_t num_locations = 2;
CGFloat locations[2] = { 0, 1.0 };
CGFloat components[8] = { 0.95, 0.3, 0.4, 1.0,
0.95, 0.3, 0.4, 0.1 };
リスト 8-5に、図 8-10のようなグレースケールのグラデーションを生成するために用いた変数を示し
ます。端点として3つの位置を設定しています。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
98
グラデーション
CGShadingオブジェクトの使い方
リスト 8-5
グレースケールのグラデーションを生成するために用いた変数
size_t num_locations = 3;
CGFloat locations[3] = { 0.0, 0.5, 1.0};
CGFloat components[12] = {
1.0, 1.0, 1.0, 1.0,
0.5, 0.5, 0.5, 1.0,
1.0, 1.0, 1.0, 1.0 };
図 8-10
3つの位置を指定して描画した軸状グラデーション
CGShadingオブジェクトの使い方
グラデーションの描画には、関数CGShadingCreateAxialまたはCGShadingCreateRadialで、CGShading
オブジェクトを生成する方法もあります。この関数には次の引数を指定します。
●
●
●
●
●
CGColorSpaceオブジェクト(色空間)。コールバック関数で計算した各点の色値が、実際にどの
ような色になるかを表します。
開始点と終了点。軸状グラデーションの場合、軸の開始点と終了点を、ユーザ空間の座標で指定
します。放射状グラデーションの場合は、開始円と終了円の中心を表します。
開始円と終了円の半径(放射状グラデーションの場合のみ)。
CGFunctionオブジェクト。関数CGFunctionCreateで生成します(後述)。指定された点の描画
色を計算して返す、コールバック関数として用います。
開始点と終了点のそれぞれについて、延長して単色で塗りつぶすかどうかを表すブール値。
上記のCGShading生成関数に渡すCGFunctionオブジェクトには、コールバック構造体(後述)と、コー
ルバック関数を呼び出す上でQuartz側が必要とする情報が格納されています。CGShadingオブジェク
トの生成過程で、おそらくもっともわかりにくいところでしょう。CGFunctionオブジェクトを生成す
る関数CGFunctionCreate,は、次のような引数を取ります。
●
コールバック関数に引数として渡すデータを指すポインタ。
●
コールバック関数の引数の個数。これは1とする必要があります。
●
●
浮動小数点数の配列。Quartzはこの配列の第1要素に値を設定し、コールバック関数に渡すように
なっています。値は0~1の範囲で、0はグラデーションの開始位置、1は終了位置を表します。
コールバック関数は、この位置の色値を計算して返さなければなりません。
コールバック関数が返す出力値の個数。コールバック関数は、引数で指定された位置における、
色の成分を表す値と、透明度を表すアルファ値を返さなければなりません。色成分の値は、別途
生成してCGShading生成関数に渡したCGColorSpaceオブジェクト(色空間)に基づいて解釈され
ます。たとえばRGB色空間を使う場合、出力値の個数として4を指定します(R、G、B、A)。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
99
グラデーション
CGShadingオブジェクトの使い方
●
●
浮動小数点数の配列。コールバック関数は、色成分の値とアルファ値をここに格納して返しま
す。
コールバック構造体。構造体の版番号(0)、色成分を計算するコールバック関数、コールバッ
ク関数に引数infoとして渡すデータを用済み後に解除するためのコールバック関数(必要な場
合)を設定します。コールバック関数名をmyCalculateShadingValuesとすれば、その仕様(引
数並び)は次のようになります。
void myCalculateShadingValues (void *info, const CGFloat *in, CGFloat *out)
CGShadingオブジェクトを生成した後、必要ならばクリッピングの設定をします。次に関数
CGContextDrawShadingで、グラデーションを適用しながら、コンテキストのクリッピング領域内を
塗りつぶします。この関数の実行中、開始点と終了点の間の各位置について、色値を計算するコール
バック関数が呼び出されます。
CGShadingオブジェクトを使い終わったら、関数CGShadingReleaseで解除してください。
“CGShadingオブジェクトで軸状グラデーションを描画するコードの書き方” (100 ページ)と“CGShading
オブジェクトで放射状グラデーションを描画するコードの書き方” (107 ページ)で、CGShadingオブ
ジェクトを使ってグラデーションを描画するコードの書き方を示します。
CGShadingオブジェクトで軸状グラデーションを描画するコードの書き方
軸状グラデーションも放射状グラデーションも、描画の手順はよく似ています。ここではCGShading
オブジェクトを使って軸状グラデーションを描画するコード例を示します。実際には、グラフィック
スコンテキストに半円状のクリッピングパスを生成し、この領域内に描画します。最終的な出力は図
8-11のようになります。
図 8-11
軸状グラデーションをクリッピング領域内に描画した様子
図のような軸状グラデーションを描画する手順を、次の各節に分けて説明します。
1.
“色値を計算するCGFunctionオブジェクトの生成” (101 ページ)
2.
“軸状グラデーションを描画するCGShadingオブジェクトの生成” (103 ページ)
3.
“コンテキストのクリッピング” (104 ページ)
4.
“CGShadingオブジェクトで軸状グラデーションを描画” (104 ページ)
5.
“オブジェクトの解除” (104 ページ)
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
100
グラデーション
CGShadingオブジェクトの使い方
色値を計算するCGFunctionオブジェクトの生成
色値の計算方法はどのように決めても構いません。実際に計算する関数は、次の3つの引数を取るも
のとして記述してください。
void *info - NULLか、またはCGShadingオブジェクトの生成関数に渡したデータを指すポインタ
●
が渡されます。
const CGFloat *in - Quartzはこのin配列を介して、コールバック関数に入力データを渡します。
●
実際に渡される値は、CGFunctionオブジェクトに定義した入力値の範囲内であるはずです。この
例の場合は0~1の範囲です(リスト 8-7 (102 ページ)を参照)。
CGFloat *out - コールバック関数の出力値を、このout配列に収容してQuartz側に返します。色
●
空間によって決まる色成分の値とアルファ値のそれぞれが、1つずつの要素を占めます。返す値
は、CGFunctionオブジェクトに定義した出力値の範囲内でなければなりません。この例の場合は
0~1の範囲です(リスト 8-7 (102 ページ)を参照)。
以上の引数について詳しくは、『CGFunctionEvaluateCallback』を参照してください。
リスト 8-6に、成分に応じた定数(配列の形で宣言)を入力値に掛けて、色成分の値を計算する例を
示します。入力値の範囲は0~1なので、出力値はRGB色空間の黒(0, 0, 0)から紫(1, 0, 0.5)の範囲になり
ます。4番目の成分は常に1、すなわち完全に不透明です。
リスト 8-6
色成分の値の計算
static void myCalculateShadingValues (void *info,
const CGFloat *in,
CGFloat *out)
{
CGFloat v;
size_t k, components;
static const CGFloat c[] = {1, 0, .5, 0 };
components = (size_t)info;
v = *in;
for (k = 0; k < components -1; k++)
*out++ = c[k] * v;
*out++ = 1;
}
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
101
グラデーション
CGShadingオブジェクトの使い方
色値を計算するコールバック関数を、CGFunctionオブジェクトに組み込みます。コールバック関数そ
のものではなくこのCGFunctionオブジェクトを、CGShadingオブジェクトの生成時に渡すことになり
ます。リスト 8-7に、リスト 8-6のコールバック関数を組み込んで、CGFunctionオブジェクトを生成す
るコード例を示します。コード例を示した後、番号がついている行について詳しく説明します。
リスト 8-7
CGFunctionオブジェクトの生成
static CGFunctionRef myGetFunction (CGColorSpaceRef colorspace)
// 1
{
size_t numComponents;
static const CGFloat input_value_range [2] = { 0, 1 };
static const CGFloat output_value_ranges [8] = { 0, 1, 0, 1, 0, 1, 0, 1 };
static const CGFunctionCallbacks callbacks = { 0,
// 2
&myCalculateShadingValues,
NULL };
numComponents = 1 + CGColorSpaceGetNumberOfComponents (colorspace);
// 3
return CGFunctionCreate ((void *) numComponents,
// 4
1,
// 5
input_value_range,
// 6
numComponents,
// 7
output_value_ranges,
// 8
&callbacks);
// 9
}
このコードが実行することを以下に示します。
1.
色空間を引数として取ります。
2.
コールバック構造体を宣言し、版番号(0)、色成分計算コールバック関数のポインタ、解除コー
ルバック関数のポインタ(今回は不要なのでNULL)を設定します。
3.
色空間に応じた、色成分の個数を求め、アルファ値の分として1を加えます。
4.
numComponents値を指すポインタを渡します。この値は、コールバック関数
myCalculateShadingValuesが、計算する色成分の数を判断するために使います。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
102
グラデーション
CGShadingオブジェクトの使い方
5.
コールバック関数に渡す入力値の個数として1を指定します。
6.
入力値が取り得る範囲を指定した配列を渡します。この場合、0~1の範囲であることになりま
す。
7.
コールバック関数が返す出力値の個数を指定します。色成分の個数に、アルファ値の分として1
を加えた値です。
8.
出力値が取り得る範囲を指定した配列を渡します。この場合、各成分とも0~1の範囲であること
になります。色成分の個数は(アルファ値の分を加えて)4つなので、配列の要素数は8になって
います。
9.
先に宣言し値を設定した、コールバック構造体のポインタを渡します。
軸状グラデーションを描画するCGShadingオブジェクトの生成
CGShadingオブジェクトの生成には、CGShadingCreateAxial「軸状グラデーションを描画する
CGShadingオブジェクトの生成」リスト 8-8を使います。引数として、色空間、開始点および終了点、
CGFunctionオブジェクト、開始点や終了点から延長して塗りつぶすかどうかを表すブール値を渡しま
す。
リスト 8-8
CGPoint
軸状グラデーションを描画するCGShadingオブジェクトの生成
startPoint,
endPoint;
CGFunctionRef myFunctionObject;
CGShadingRef myShading;
startPoint = CGPointMake(0,0.5);
endPoint = CGPointMake(1,0.5);
colorspace = CGColorSpaceCreateDeviceRGB();
myFunctionObject = myGetFunction (colorspace);
myShading = CGShadingCreateAxial (colorspace,
startPoint, endPoint,
myFunctionObject,
false, false);
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
103
グラデーション
CGShadingオブジェクトの使い方
コンテキストのクリッピング
グラデーションの描画先は、現在のコンテキストです。色やパターンによる線つけや塗りつぶしと違
い、グラデーションを適用しながら描画する領域を、パスで指定することはできません。クリッピン
グ領域として範囲を指定する必要があります。リスト 8-9に、現在のコンテキストに半円形のクリッ
ピング領域を設定し、その範囲内をグラデーションで描画するコード例を示します。結果は図
8-11 (100 ページ)のようになります。
コードを見る限りでは半円形になりそうですが、実際には半楕円になっています。これはなぜでしょ
うか。“CGShadingオブジェクトで軸状グラデーションを描画する完全なルーチン例” (105 ページ)で
ルーチン全体を示すときに説明するように、コンテキストには拡大縮小も施しています。これについ
ては後述します。用途によっては、拡大縮小やクリッピングは必要ないかもしれませんが、Quartz 2D
のさまざまな機能をうまく利用すると、非常に面白い効果を得ることができます。
リスト 8-9
半円形のクリッピング領域をグラフィックスコンテキストに設定
CGContextBeginPath (myContext);
CGContextAddArc (myContext, .5, .5, .3, 0,
my_convert_to_radians (180), 0);
CGContextClosePath (myContext);
CGContextClip (myContext);
CGShadingオブジェクトで軸状グラデーションを描画
関数CGContextDrawShadingで、CGShadingオブジェクトで指定したグラデーションを適用しながら
現在のコンテキストを塗りつぶすことができます。
CGContextDrawShading (myContext, myShading);
オブジェクトの解除
CGShadingオブジェクトを使い終わったら、関数CGShadingReleaseで解除してください。また、
CGColorSpaceオブジェクト、CGFunctionオブジェクトも解除する必要があります(リスト 8-10を参
照)。
リスト 8-10 オブジェクトの解除
CGShadingRelease (myShading);
CGColorSpaceRelease (colorspace);
CGFunctionRelease (myFunctionObject);
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
104
グラデーション
CGShadingオブジェクトの使い方
CGShadingオブジェクトで軸状グラデーションを描画する完全なルーチン例
リスト 8-11に、軸状グラデーションを描画する、完全なコード例を示します。リスト 8-7 (102 ペー
ジ)で設定したCGFunctionオブジェクト、リスト 8-6 (101 ページ)に示したコールバック関数を使っ
ています。コード例を示した後、番号がついている行について詳しく説明します。
リスト 8-11 CGShadingオブジェクトで軸状グラデーションを描画するコードの書き方
void myPaintAxialShading (CGContextRef myContext,
// 1
CGRect bounds)
{
CGPoint
startPoint,
endPoint;
CGAffineTransform myTransform;
CGFloat width = bounds.size.width;
CGFloat height = bounds.size.height;
startPoint = CGPointMake(0,0.5);
// 2
endPoint = CGPointMake(1,0.5);
// 3
colorspace = CGColorSpaceCreateDeviceRGB();
// 4
myShadingFunction = myGetFunction(colorspace);
// 5
shading = CGShadingCreateAxial (colorspace,
// 6
startPoint, endPoint,
myShadingFunction,
false, false);
myTransform = CGAffineTransformMakeScale (width, height);
// 7
CGContextConcatCTM (myContext, myTransform);
// 8
CGContextSaveGState (myContext);
// 9
CGContextClipToRect (myContext, CGRectMake(0, 0, 1, 1));
// 10
CGContextSetRGBFillColor (myContext, 1, 1, 1, 1);
CGContextFillRect (myContext, CGRectMake(0, 0, 1, 1));
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
105
グラデーション
CGShadingオブジェクトの使い方
CGContextBeginPath (myContext);
// 11
CGContextAddArc (myContext, .5, .5, .3, 0,
my_convert_to_radians (180), 0);
CGContextClosePath (myContext);
CGContextClip (myContext);
CGContextDrawShading (myContext, shading);
// 12
CGColorSpaceRelease (colorspace);
// 13
CGShadingRelease (shading);
CGFunctionRelease (myShadingFunction);
CGContextRestoreGState (myContext);
// 14
}
このコードが実行することを以下に示します。
1.
引数として、グラフィックスコンテキストと、描画範囲を表す矩形を取ります。
2.
開始点の値を設定します。このルーチンでは、取り得る座標の範囲を0~1に正規化したユーザ空
間を想定して値を計算します。後で実際に描画するウインドウに合わせて座標値を変換します。
したがってこの値は、x座標が左端、y座標が下辺から高さ50%の位置と考えることができます。
3.
終了点の値を設定します。x座標が右端、y座標が下辺から高さ50%の位置と考えることができま
す。すなわち、グラデーションの軸は水平線です。
4.
このルーチンは画面に描画するので、デバイスRGBの色空間を生成します。
5.
この色空間を引数として渡し、リスト 8-7 (102 ページ)に示したルーチンでCGFunctionオブジェ
クトを生成します。
6.
軸状グラデーションを行うCGShadingオブジェクトを生成します。末尾2つの引数はfalseなので、
開始点や終了点からの延長塗りつぶしはしないことになります。
7.
描画対象ウインドウの幅と高さに合わせて座標値を変換するアフィン変換を設定します。高さと
幅が等しくなくても構わないことに注意してください。この例では高さと幅が等しくないので、
最終的に円ではなく楕円になります。
8.
この変換をルーチンに渡されたグラフィックスコンテキストに結合します。
9.
後で復元できるよう、グラフィックス状態を保存しておきます。
10. クリッピング領域を設定します。これ以降の3行で、コンテキストに矩形のクリッピング領域を
設定し、白で塗りつぶします。その結果、白い背景上にグラデーションが描画されることになり
ます。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
106
グラデーション
CGShadingオブジェクトの使い方
11. パスを生成します。これ以降の4行で、半円を作り、クリッピング領域としてグラフィックスコ
ンテキストに追加します。したがって半円の領域内をグラデーションで描画することになりま
す。もっとも、この半円をウインドウの幅と高さに合わせて変換するので(手順8)、最終的に
半楕円形の領域になります。ウインドウの大きさを変えれば、クリッピング領域の大きさも変わ
ります。
12. グラフィックスコンテキストに対してグラデーションを描画し、変換とクリッピングを施しま
す。
13. オブジェクトを解除します。これ以降の3行で、生成したオブジェクトをすべて解除しています。
14. グラフィックス状態を、塗りつぶした背景や半円形のクリッピング領域を設定する前の状態に戻
します。ただしウインドウの幅と高さに合わせた変換は有効なままです。
CGShadingオブジェクトで放射状グラデーションを描画するコードの書き
方
ここではCGShadingオブジェクトを使って、図 8-12のような放射状グラデーションを描画する例を示
します。
図 8-12
CGShadingオブジェクトで生成した放射状グラデーション
図のような放射状グラデーションを描画する手順を、次の各節に分けて説明します。
1.
“色値を計算するCGFunctionオブジェクトの生成” (107 ページ)
2.
“放射状グラデーションを描画するCGShadingオブジェクトの生成” (108 ページ)
3.
“CGShadingオブジェクトで放射状グラデーションを描画” (109 ページ)
4.
“オブジェクトの解除” (109 ページ)
色値を計算するCGFunctionオブジェクトの生成
色値を計算する関数の書き方は、軸状グラデーションの場合と同様です。“色値を計算するCGFunction
オブジェクトの生成” (101 ページ)に倣って記述してください。リスト 8-12では、色の成分の計算に
正弦関数を使っています(具体的な周波数は関数中に直接記述)。最終的に得られる画像(図
8-12 (107 ページ))は、図 8-11 (100 ページ)の色遣いとはまったく違ったものになっています。
出力される色値は違うものの、リスト 8-12に示した関数の仕様(引数並び)は、リスト 8-6 (101 ペー
ジ)と同じです。どちらも、入力値は1つ、出力値は色空間の成分の個数に1を加えた個数です。
リスト 8-12 色成分の値の計算
static void
myCalculateShadingValues (void *info,
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
107
グラデーション
CGShadingオブジェクトの使い方
const CGFloat *in,
CGFloat *out)
{
size_t k, components;
double frequency[4] = { 55, 220, 110, 0 };
components = (size_t)info;
for (k = 0; k < components - 1; k++)
*out++ = (1 + sin(*in * frequency[k]))/2;
*out++ = 1; // alpha
}
色値を計算する関数を作成した後、軸状グラデーションの場合と同様に、CGFunctionオブジェクトを
生成する必要があります(“色値を計算するCGFunctionオブジェクトの生成” (101 ページ)を参照)。
放射状グラデーションを描画するCGShadingオブジェクトの生成
放射状グラデーション用のCGShadingオブジェクトの生成には、CGShadingCreateRadial「放射状グ
ラデーションを描画するCGShadingオブジェクトの生成」リスト 8-13を使います。引数として、色空
間、開始点および終了点、開始円および終了円の半径、CGFunctionオブジェクト、開始点や終了点か
ら延長して塗りつぶすかどうかを表すブール値を渡します。
リスト 8-13 放射状グラデーションを描画するCGShadingオブジェクトの生成
CGPoint startPoint, endPoint;
CGFloat startRadius, endRadius;
startPoint = CGPointMake(0.25,0.3);
startRadius = .1;
endPoint = CGPointMake(.7,0.7);
endRadius = .25;
colorspace = CGColorSpaceCreateDeviceRGB();
myShadingFunction = myGetFunction (colorspace);
CGShadingCreateRadial (colorspace,
startPoint,
startRadius,
endPoint,
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
108
グラデーション
CGShadingオブジェクトの使い方
endRadius,
myShadingFunction,
false,
false);
CGShadingオブジェクトで放射状グラデーションを描画
関数CGContextDrawShadingで、CGShadingオブジェクトで指定したグラデーションを適用しながら
現在のコンテキストを塗りつぶすことができます。
CGContextDrawShading (myContext, shading);
このように、使っている関数は軸状グラデーションの場合と同じです。
オブジェクトの解除
CGShadingオブジェクトを使い終わったら、関数CGShadingReleaseで解除してください。また、
CGColorSpaceオブジェクト、CGFunctionオブジェクトも解除する必要があります(リスト 8-14を参
照)。
リスト 8-14 オブジェクトの解除
CGShadingRelease (myShading);
CGColorSpaceRelease (colorspace);
CGFunctionRelease (myFunctionObject);
CGShadingオブジェクトで放射状グラデーションを描画する完全なルーチン例
リスト 8-15に、放射状グラデーションを描画する、完全なコード例を示します。リスト 8-7 (102 ペー
ジ)で設定したCGFunctionオブジェクト、リスト 8-12 (107 ページ)に示したコールバック関数を使っ
ています。コード例を示した後、番号がついている行について詳しく説明します。
リスト 8-15 CGShadingオブジェクトで放射状グラデーションを描画するコードの書き方
void myPaintRadialShading (CGContextRef myContext,
CGRect bounds);
{
CGPoint startPoint,
endPoint;
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
109
// 1
グラデーション
CGShadingオブジェクトの使い方
CGFloat startRadius,
endRadius;
CGAffineTransform myTransform;
CGFloat width = bounds.size.width;
CGFloat height = bounds.size.height;
startPoint = CGPointMake(0.25,0.3);
// 2
startRadius = .1;
// 3
endPoint = CGPointMake(.7,0.7);
// 4
endRadius = .25;
// 5
colorspace = CGColorSpaceCreateDeviceRGB();
// 6
myShadingFunction = myGetFunction (colorspace);
// 7
shading = CGShadingCreateRadial (colorspace,
// 8
startPoint, startRadius,
endPoint, endRadius,
myShadingFunction,
false, false);
myTransform = CGAffineTransformMakeScale (width, height);
// 9
CGContextConcatCTM (myContext, myTransform);
// 10
CGContextSaveGState (myContext);
// 11
CGContextClipToRect (myContext, CGRectMake(0, 0, 1, 1));
// 12
CGContextSetRGBFillColor (myContext, 1, 1, 1, 1);
CGContextFillRect (myContext, CGRectMake(0, 0, 1, 1));
CGContextDrawShading (myContext, shading);
// 13
CGColorSpaceRelease (colorspace);
// 14
CGShadingRelease (shading);
CGFunctionRelease (myShadingFunction);
CGContextRestoreGState (myContext);
// 15
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
110
グラデーション
CGShadingオブジェクトの使い方
}
このコードが実行することを以下に示します。
1.
引数として、グラフィックスコンテキストと、描画範囲を表す矩形を取ります。
2.
開始円の中心を設定します。このルーチンでは、取り得る座標の範囲を0~1に正規化したユーザ
空間を想定して値を計算します。後で実際に描画するウインドウに合わせて座標値を変換しま
す。したがってこの位置は、x座標が左辺から25%、y座標が下辺から30%の位置と考えることが
できます。
3.
開始円の半径を設定します。ユーザ空間の幅の10%に当たります。
4.
終了円の中心を設定します。x座標が左辺から70%、y座標が下辺から70%の位置と考えることが
できます。
5.
終了円の半径を設定します。ユーザ空間の幅の25%に当たります。終了円は開始円よりも大きい
ので、左から右に向かって太くなる円錐形になります。
6.
このルーチンは画面に描画するので、デバイスRGBの色空間を生成します。
7.
この色空間を引数として渡し、リスト 8-7 (102 ページ)に示したルーチンでCGFunctionオブジェ
クトを生成します。ただし色の計算にはリスト 8-12 (107 ページ)の関数を使います。
8.
放射状グラデーションを行うCGShadingオブジェクトを生成します。末尾2つの引数はfalseなの
で、開始点や終了点からの延長塗りつぶしはしないことになります。
9.
描画対象ウインドウの幅と高さに合わせて座標値を変換するアフィン変換を設定します。高さと
幅が等しくなくても構わないことに注意してください。ウインドウの大きさを変えれば、変換も
変わります。
10. この変換をルーチンに渡されたグラフィックスコンテキストに結合します。
11. 後で復元できるよう、グラフィックス状態を保存しておきます。
12. クリッピング領域を設定します。これ以降の3行で、コンテキストに矩形のクリッピング領域を
設定し、白で塗りつぶします。その結果、白い背景上にグラデーションが描画されることになり
ます。
13. グラフィックスコンテキストに対してグラデーションを描画し、変換を施します。
14. オブジェクトを解除します。これ以降の3行で、生成したオブジェクトをすべて解除しています。
15. グラフィックス状態を、塗りつぶした背景を設定する前の状態に戻します。ただしウインドウの
幅と高さに合わせた変換は有効なままです。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
111
グラデーション
関連項目
関連項目
●
『CGGradient Reference 』に、CGGradientオブジェクトを生成する関数の説明があります。
●
『CGShading Reference 』に、CGShadingオブジェクトを生成する関数の説明があります。
●
●
『CGFunction Reference 』に、CGShadingオブジェクトでグラデーションの色を計算するために必
要な関数の説明があります。
『CGContext Reference 』に、CGGradientオブジェクト、CGShadingオブジェクトを使ってコンテキ
ストに描画する関数の説明があります。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
112
透明レイヤ
透明レイヤには、複数のオブジェクトをグループ化し、複合グラフィックスを作る働きがあります。
1つのオブジェクトとして扱われるので、その全体に対して何らかの効果を適用する場合に有用です。
たとえば図 9-1では、3つの円全体に影を適用しています。
図 9-1
透明レイヤとしてグループ化した3つの円
図 9-1の3つの円を透明レイヤとして描画せずに影を適用すると、図 9-2のようになってしまいます。
図 9-2
独立したオブジェクトとして描画した3つの円
透明レイヤの動作の仕組み
Quartzの透明レイヤは、多くのグラフィックスアプリケーションに使われているレイヤによく似てい
ます。レイヤは、独立した実体として扱えます。Quartzはこれを、コンテキストごとに、階層化され
た1個のスタックとして管理しており、複数の透明レイヤを入れ子にすることができます。ただし、
レイヤはスタックの一部として扱われるため、あるレイヤだけ取り出して処理するようなことはでき
ません。
透明レイヤを開始する旨の合図をQuartzに対して送るために、関数CGContextBeginTransparencyLayer
を実行します。引数としてグラフィックスコンテキストとCFDictionaryオブジェクトを取ります。辞
書はレイヤに関する追加情報を指定するために使うのですが、現在のところ、Quartz 2D APIでは使え
ないので、NULLを渡すようにしてください。この関数を実行してもグラフィックス状態の大部分はそ
のままですが、アルファ値は1に、影は無効に、ブレンドモードは標準に変わるなど、最終的にでき
あがる複合グラフィックスに影響するパラメータは変化します。
これ以降の描画内容は、すべてこのレイヤに属するものになります。指定されたコンテキストとは別
に、完全に透明な背景を用意し、その上に描画する形です。この背景は、コンテキストとは独立した
描画先バッファとして扱われます。
すべて描画した後、関数CGContextEndTransparencyLayerを実行してください。するとここまでの
描画結果を、大域アルファ値、コンテキストの影の設定やクリッピング領域を適用しながら、コンテ
キストに合成するようになっています。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
113
透明レイヤ
透明レイヤへの描画
透明レイヤへの描画
透明レイヤへの描画は次の3つの手順で行います。
1.
関数CGContextBeginTransparencyLayerを実行します。
2.
グループ化する図形を透明レイヤに描画します。
3.
関数CGContextEndTransparencyLayerを実行します。
図 9-3の3つの矩形は、透明レイヤに描画されています。影を描画する際、全体が1つの単位として扱
われていることがわかります。
透明レイヤに描画した3つの矩形
図 9-3
リスト 9-1に、透明レイヤを使って図 9-3のような矩形群を生成する関数の例を示します。コード例を
示した後、番号がついている行について詳しく説明します。
リスト 9-1
透明レイヤへの描画
void MyDrawTransparencyLayer (CGContext myContext,
// 1
CGFloat wd,
CGFloat ht)
{
CGSize
myShadowOffset = CGSizeMake (10, -20);
// 2
CGContextSetShadow (myContext, myShadowOffset, 10);
// 3
CGContextBeginTransparencyLayer (myContext, NULL);
// 4
// Your drawing code here
// 5
CGContextSetRGBFillColor (myContext, 0, 1, 0, 1);
CGContextFillRect (myContext, CGRectMake (wd/3+ 50,ht/2 ,wd/4,ht/4));
CGContextSetRGBFillColor (myContext, 0, 0, 1, 1);
CGContextFillRect (myContext, CGRectMake (wd/3-50,ht/2-100,wd/4,ht/4));
CGContextSetRGBFillColor (myContext, 1, 0, 0, 1);
CGContextFillRect (myContext, CGRectMake (wd/3,ht/2-50,wd/4,ht/4));
CGContextEndTransparencyLayer (myContext);
}
このコードが実行することを以下に示します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
114
// 6
透明レイヤ
透明レイヤへの描画
1.
引数として、矩形を描画する際に使う、グラフィックスコンテキスト、幅、高さの3つを取りま
す。
2.
CGSize型構造体を用意し、影のxオフセット、yオフセットを設定します。この場合、水平方向に
10単位、垂直方向に-20単位離れた影を描画することになります。
3.
ぼかし値として10を指定して影を設定します(0ならば、ぼかしのない、くっきりとした影にな
ります)。
4.
透明レイヤを開始する旨の合図を送ります。以降の描画は透明レイヤが対象になります。
5.
以下の6行で、図 9-3 (114 ページ)のように、塗りつぶし色を変えながら3つの矩形を描画しま
す。この行を実際の描画コードで置き換えてください。
6.
透明レイヤを終了する旨の合図を送ります。ここまでの描画結果が、コンテキストに合成されま
す。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
115
Quartz 2Dにおけるデータ管理
グラフィックスアプリケーションではデータ管理が必須です。Quartzで言うデータ管理とは、Quartz
2Dのルーチンにデータを渡す、あるいはルーチンからデータを受け取ることです。Quartz 2Dには、
画像やPDFデータをファイルから取り込む、アプリケーション側で生成したデータを取り込むなど、
Quartz内にデータを移動するルーチンがあります。また、画像やPDFデータをファイルに書き出す、
アプリケーション側に渡すなど、Quartz外にデータを移動するルーチンもあります。
Quartzにはデータを管理するさまざまな関数があります。この章を読み、用途に応じて最適な関数を
判断してください。
注意: 画像データの読み書きにはImage I/Oフレームワークを使うようお勧めします。iOS 4
やMac OS X 10.4以降で使えます。不透過データ型Image I/O Programming Guide および
CGImageSourceRefについては、『CGImageDestinationRef』を参照してください。画像
ソースや画像デスティネーションには、画像データだけでなくメタデータのアクセス手段も
あります。
データソース(送り手)やデータデスティネーション(受け手)として、Quartzは次の3種類を認識
します。
●
●
●
URL。URLで場所を指定できるデータは、データの送り手や受け手としても動作します。URLを
Quartzの関数に渡す際には、Core Foundationのデータ型であるCFURLRefを使います。
CFData。Core Foundationのデータ型であるCFDataRefおよびCFMutableDataRefを使えば、メモ
リ空間上に確保したバッファを、Core Foundationのオブジェクトと同じように操作できます。
CFDataはCocoa FoundationのNSDataクラスとの「橋渡し」をするデータ型です。Cocoaフレーム
ワーク上でQuartz 2Dを使っている場合、NSDataオブジェクトをそのまま、CFDataオブジェクトを
引数とするQuartzの関数に渡すことができます。
生データ。任意の型のデータを指すポインタは、基本的なメモリ管理を行うコールバック関数群
を別途用意することにより、データソースやデータデスティネーションとして利用できるように
なります。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
116
Quartz 2Dにおけるデータ管理
データをQuartz 2Dに移動
URL、CFData、生データのバッファのいずれにしても、Quartz 2Dとの間で受け渡しするデータの中身
は、画像データやPDFデータであることが多いでしょう。画像データはどのようなファイル形式であっ
ても構いません。Quartzは標準的な画像ファイル形式の多くを認識できます。Quartzのデータ管理関
数の中には、もっぱら画像データを扱うもの、PDFデータを扱うものもありますが、どちらも扱える
汎用的な関数もあります。
URL、CFData、生データのいずれにしても、データソースやデータデスティネーションの実体は、Mac
OS XやiOSのグラフィックス技術の管理外にあるデータです(図 10-1を参照)。Mac OS XやiOSには、
Quartzと通信する独自のルーチンを用意しているグラフィックス技術もあります。たとえばMac OS X
のアプリケーションは、Quartzの画像をCore Imageに送り、その機能を利用して洗練された効果を与
えることも可能です。
図 10-1
Quartz 2Dとのデータの受け渡し(Mac OS X)
データをQuartz 2Dに移動
データソースからデータを取得する関数を表 10-1 (118 ページ)に示します。
CGPDFDocumentCreateWithURL以外はすべて、画像ソース(CGImageSourceRef)またはデータプロ
バイダ(CGDataProviderRef)を返します。画像ソースやデータプロバイダは、データのアクセス
処理を抽象化しており、アプリケーション側で生のメモリバッファを用いてデータを管理する必要は
ありません。
画像データをQuartzに移動する手段としては、画像ソースを推奨します。画像ソースは、さまざまな
形式の画像データを表します。複数の画像やサムネール画像、および各画像や画像ファイルのプロパ
ティを、一括して収容できます。取得したCGImageSourceRefに対して、次のような処理が可能で
す。
●
●
●
画像(CGImageRef)を生成。関数CGImageSourceCreateImageAtIndex、
CGImageSourceCreateThumbnailAtIndex、CGImageSourceCreateIncrementalのいずれかを
使います。データ型CGImageRefは、Quartzの1枚の画像を表します。
画像を画像ソースに追加。関数CGImageSourceUpdateDataまたは
CGImageSourceUpdateDataProviderを使います。
画像ソースに関する情報を取得。関数CGImageSourceGetCount、
CGImageSourceCopyProperties、CGImageSourceCopyTypeIdentifiersを使います。
関数CGPDFDocumentCreateWithURLは、指定されたURLにあるファイルをもとにPDFドキュメントを
生成する便宜関数です。
データプロバイダは画像ソースよりも古くから使われている機構で、機能も限られています。これを
使って画像やPDFデータを取得できます。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
117
Quartz 2Dにおけるデータ管理
データをQuartz 2Dに移動
データプロバイダを引数とする関数には次のようなものがあります。
●
画像生成関数。CGImageCreate、CGImageCreateWithPNGDataProvider、
CGImageCreateWithJPEGDataProviderなど。
●
PDFドキュメント生成関数CGPDFDocumentCreateWithProvider。
●
関数CGImageSourceUpdateDataProvider。既存の画像ソースを新しいデータで更新。
画像について詳しくは、“ビットマップ画像と画像マスク” (122 ページ)を参照してください。
表 10-1
データをQuartz 2Dに移動する関数
関数
用途
CGImageSourceCreateWithDataProvider
データプロバイダから画像ソースを生成。
CGImageSourceCreateWithData
CFDataオブジェクトから画像ソースを生成。
CGImageSourceCreateWithURL
画像データの場所を指定するURLから画像ソースを生成。
CGPDFDocumentCreateWithURL
指定されたURLの場所にあるデータからPDFドキュメントを
生成。
CGDataProviderCreateSequential
ストリームから画像やPDFデータを読み取り。データを処理
するコールバック関数を別途用意します。
CGDataProviderCreateDirectAccess
ブロックデバイスから画像やPDFデータを読み取り。データ
を処理するコールバック関数を別途用意します。
CGDataProviderCreateWithData
アプリケーション側から供給される、画像やPDFデータの
バッファを読み取り。データ用に確保したメモリを解除す
るコールバック関数を別途用意します。
CGDataProviderCreateWithURL
画像やPDFデータの場所を表すURLから、画像やPDFデータ
のバッファを読み取り。
CGDataProviderCreateWithCFData
CFDataオブジェクトから画像やPDFデータを読み取り。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
118
Quartz 2Dにおけるデータ管理
Quartz 2Dからデータを移動
Quartz 2Dからデータを移動
データをQuartz 2D外に移動する関数を表 10-2 (120 ページ)に示します。CGPDFContextCreateWithURL
以外はすべて、画像デスティネーション(CGImageDestinationRef)またはデータコンシューマ
(CGDataConsumerRef)を返します。画像デスティネーションやデータコンシューマは、データ書
き込み処理を抽象化しており、面倒な処理はQuartz側に任せることができます。
画像データをQuartzから移動する手段としては、画像デスティネーションを推奨します。画像ソース
と同様、さまざまな形式の画像に対応しており、複数の画像やサムネール画像、および各画像や画像
ファイルのプロパティを、一括して処理できます。取得したCGImageDestinationRefに対して、次
のような処理が可能です。
●
●
●
画像(CGImageRef)をデスティネーションに追加。関数CGImageDestinationAddImageまたは
CGImageDestinationAddImageFromSourceを使います。データ型CGImageRefは、Quartzの1枚の
画像を表します。
プロパティを設定。関数CGImageDestinationSetPropertiesを使います。
画像デスティネーションに関する情報を取得。関数CGImageDestinationCopyTypeIdentifiers
またはCGImageDestinationGetTypeIDを使います。
関数CGPDFContextCreateWithURLは、指定されたURLの場所にPDFデータを書き出す便宜関数です。
データコンシューマは画像デスティネーションよりも古くから使われている機構で、機能も限られて
います。画像やPDFデータを書き出すために使います。データコンシューマを引数とする関数には次
のようなものがあります。
●
●
PDFコンテキスト生成関数CGPDFContextCreate。戻り値のグラフィックスコンテキストは、デー
タコンシューマオブジェクトに渡した描画内容を、PDF描画コマンドの形で記録します。
関数CGImageDestinationCreateWithDataConsumer。データコンシューマから画像デスティネー
ションを生成。
注意: 生の画像データを扱う際、良好な処理性能を引き出すためには、vImageフレームワー
クを使うとよいでしょう。画像データをCGImageRefの参照先からvImageにインポートする
ためには、vImageBuffer_InitWithCGImage関数を使います。詳しくは、『Accelerate Release
Notes 』を参照してください。
画像について詳しくは、“ビットマップ画像と画像マスク” (122 ページ)を参照してください。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
119
Quartz 2Dにおけるデータ管理
Quartz 2DとCore Image間でのデータ交換(Mac OS X)
表 10-2
データをQuartz 2Dから移動する関数
関数
用途
CGImageDestinationCreateWithDataConsumer
画像データをデータコンシューマに書き出し。
CGImageDestinationCreateWithData
画像データをCFDataオブジェクトに書き出し。
CGImageDestinationCreateWithURL
画像データを指定したURLの場所に書き出し。
CGPDFContextCreateWithURL
指定したURLの場所にPDFデータとして書き出すためのコ
ンテキストを生成。
CGDataConsumerCreateWithURL
画像データまたはPDFデータを指定したURLの場所に書き
出し。
CGDataConsumerCreateWithCFData
画像データまたはPDFデータをCFDataオブジェクトに書
き出し。
CGDataConsumerCreate
別途用意するコールバック関数を使って画像データまた
はPDFデータを書き出し。
Quartz 2DとCore Image間でのデータ交換(Mac OS X)
Core Imageフレームワークは、画像処理を行うObjective-CのAPI群で、Mac OS X向けに提供されていま
す。Core Imageには、動画用、静止画用の画像フィルタが組み込まれているほか、独自のフィルタを
組み込んで利用する、あるいは準実時間処理をすることも可能です。また、Core Imageのフィルタ
は、Quartz 2Dの画像にも適用できます。色を補正する、歪みを加える、ぼかしを与える、鮮明化す
る、画像間の遷移を生成する、などの処理があります。また、対話的な画像処理、すなわち、フィル
タ処理の結果を入力側にフィードバックすることも可能です。Core Imageの処理能力について詳しく
は、『Core Image Programming Guide 』を参照してください。
Core Imageのメソッドは、Core Image画像(CIImageオブジェクト)としてパッケージ化された画像を
対象とします。Quartzの画像(CGImageRefデータ型)を直接操作することはできません。Core Image
画像に変換してからフィルタを適用する必要があります。
Quartz画像をCore Image画像としてパッケージ化する関数は、Quartz 2D APIではなくCore Imageの側に
あります。Quartzの画像またはレイヤ(CGLayerRef)からCore Image画像を生成する、Core Imageの
メソッドを以下に示します。これを使ってQuartz 2DのデータをCore Imageに送ることができます。
●
imageWithCGImage:
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
120
Quartz 2Dにおけるデータ管理
Quartz 2DとCore Image間でのデータ交換(Mac OS X)
●
imageWithCGImage:options:
●
imageWithCGLayer:
●
imageWithCGLayer:options:
Core Image画像をQuartz画像に変換するCOre Imageのメソッドを以下に示します。これを使って、処
理が済んだ画像をQuartz 2Dに戻すことができます。
●
createCGImage:fromRect:
●
createCGLayerWithSize:info:
Core Imageのメソッドについて詳しくは、『Core Image Reference Collection 』を参照してください。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
121
ビットマップ画像と画像マスク
ビットマップ画像や画像マスクも、Quartzのほかの描画プリミティブと同じように使えます。いずれ
もCGImageRefデータ型で表します。後述のように、画像を生成する関数は何種類もあります。ビッ
トマップデータを渡すために、データプロバイダや画像ソースを使うものもあります。既存の画像を
複製し、あるいは演算を施して生成するものもあります。生成方法にかかわらず、ビットマップ画像
はどのようなグラフィックスコンテキストにでも描画できます。ビットマップ画像は所定の解像度で
並べたビット配列であることに注意してください。解像度に依存しないグラフィックスコンテキスト
(PDFグラフィックスコンテキストなど)に描画するのであっても、ビットマップ画像の生成時に決
めた解像度によって描画結果は制限されます。
Quartzの画像マスクを生成する方法として、関数CGImageMaskCreateがあります。具体的な生成方法
については、“画像マスクの生成” (128 ページ)で説明します。画像マスクを適用することだけが、
マスク描画の方法ではありません。“色に基づく画像のマスク処理” (131 ページ)、“画像マスクを
使って画像の一部をマスク” (129 ページ)、“コンテキストにクリッピング領域を設定することによ
り画像をマスク” (133 ページ)の各節で、マスクを適用する手段を紹介します。
ビットマップ画像と画像マスクについて
ビットマップ画像(標本化された画像)は、ピクセル(標本)の配列になっています。各ピクセル
は、画像のある1点に対応します。JPEG、TIFF、PNGなどの画像ファイルは、いずれもビットマップ画
像を格納しています。アプリケーションアイコンもビットマップ画像です。ビットマップ画像全体の
形状は、矩形でなければなりません。しかしアルファ成分を利用すれば、矩形以外の形状で表示し、
あるいは回転やクリッピングを施すことも可能です(図 11-1を参照)。
図 11-1
ビットマップ画像
ビットマップの各ピクセル(標本)は、色空間で指定されるいくつかの色成分と、透明度を表すアル
ファ値から成ります。各成分が占めるビット数にも、1ビットから32ビットまでの種類があります。
Mac OS Xの場合は、成分を浮動小数点数で表すことも可能です。Mac OS XやiOSで利用できる画像形式
については、“ビットマップグラフィックスコンテキストで扱えるピクセル形式” (36 ページ)を参照してくださ
い。ColorSyncにはビットマップ画像の色空間を扱う機能があります。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
122
ビットマップ画像と画像マスク
ビットマップ画像に関する情報
Quartzでは画像マスクも利用できます。これもビットマップですが、色ではなく、描画する領域を指
定するために使います。すなわち、ページ上のどの位置に色を乗せるか、を指定するステンシル(型
紙)として働きます。Quartzでは、現在の塗りつぶし色を使って画像マスクを描画するようになって
います。画像マスクの深度(各ピクセルのビット数)は、1~8ビットの種類があります。
ビットマップ画像に関する情報
Quartzは広範な画像形式に対応し、広く普及している画像形式の処理機能が組み込まれています。iOS
の場合、JPEG、GIF、PNG、TIF、ICO、GMP、XBM、CURの各画像形式を扱えます。その他のビットマッ
プ画像形式(特定企業が独自に決めている形式を含む)を正しく解釈するためには、その仕様詳細が
わからなければなりません。関数CGImageCreateに渡す画像データは、スキャンライン単位ではなく
ピクセル単位でインターリーブしたものに限ります。また、ビットプレーン形式のデータにも対応し
ていません。
この節ではビットマップ画像に関する情報を説明します。Quartzの画像(CGImageRefデータ型)を生
成、処理する関数には、以下に示す情報をすべて指定しなければならないもの、一部だけでよいもの
があります。これは、ビットマップデータのエンコード方法と、ビットマップで表すのが画像か画像
マスクか、の違いに依存します。
注意: 生の画像データを扱う際、良好な処理性能を引き出すためには、vImageフレームワー
クを使うとよいでしょう。画像データをCGImageRefの参照先からvImageにインポートする
ためには、vImageBuffer_InitWithCGImage関数を使います。詳しくは、『Accelerate Release
Notes 』を参照してください。
ビットマップ画像(CGImageRef)を生成するためには、次のような情報が必要です。
●
●
●
●
●
ビットマップデータソース。Quartzのデータプロバイダまたは画像ソース。これについては“Quartz
2Dにおけるデータ管理” (116 ページ)で、ビットマップデータソースを供給する関数とともに説
明しました。
必要な場合、デコード配列(“デコード配列” (124 ページ)を参照)。
補間の設定。画像の大きさを調整する際、補間アルゴリズムを適用するかどうかを指定するブー
ル値です。
レンダリングインテント。グラフィックスコンテキストの色空間で再現できない色がある場合の
処理方法を指定します。画像マスクの場合は必要ありません。詳しくは、“レンダリングインテン
トの設定” (62 ページ)を参照してください。
画像の寸法。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
123
ビットマップ画像と画像マスク
ビットマップ画像に関する情報
●
●
ピクセル形式。色成分当たりビット数、ピクセル当たりビット数、行当たりバイト数を指定しま
す(“ピクセル形式” (124 ページ)を参照)。
画像については、色空間とビットマップレイアウト(“色空間とビットマップレイアウト” (124 ペー
ジ))。アルファ成分の位置、浮動小数点数で表すかどうか、を指定します。画像マスクの場合
は不要です。
デコード配列
デコード配列には、画像の色値を別の色値に変換する働きがあり、彩度を落とす、色を反転する、な
どの処理に有用です。色成分ごとに2つの数値の組(下限と上限)を収容した配列です。画像を描画
する際、元の成分値が描画先色空間において、2つの数値で表される範囲内に納まるよう、線形変換
を施すようになっています。たとえばRGB色空間の画像に対応するデコード配列には6つの要素があ
り、2つずつがそれぞれ、赤、緑、青の色成分に対応しています。
ピクセル形式
ピクセル形式としては次の情報があります。
●
●
●
成分当たりビット数。ピクセルの各色成分のビット数です。画像マスクの場合は、ソースピクセ
ルにおける有効なマスクビット数を表します。たとえばソース画像が8ビットマスクであれば、
成分当たり8ビットとなります。
ピクセル当たりビット数。ソースピクセルを構成する総ビット数です。成分当たりビット数とピ
クセル当たり成分数の積以上でなければなりません。
行当たりバイト数。画像の水平行当たりバイト数です。
色空間とビットマップレイアウト
各ピクセルのビットを正しく解釈できるよう、次の情報を指定しなければなりません。
●
●
●
アルファ成分の有無。Quartzで処理できる色空間は、RGB、CMYK、グレースケールのいずれかで
す。透明度を表す、アルファ成分にも対応しています。もっとも、アルファ成分を収容できない
ビットマップ画像形式もあります。可能な場合、アルファ成分は、各ピクセルの最上位ビット
列、または最下位ビット列に置きます。
アルファ成分がある場合、色成分の値にアルファ値をあらかじめ掛けておくかどうか。アルファ
値乗算済みとは、色成分の値にあらかじめアルファ値を掛けてあることを表します。色成分ごと
の積演算が不要になるので、描画速度を改善できます。たとえばRGB色空間の場合、アルファ値
乗算済みであればピクセル当たり3回の積演算(赤、緑、青の各成分とアルファ値の積)を省略
できます。
値を整数で表すか浮動小数点数値で表すか。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
124
ビットマップ画像と画像マスク
画像の生成
関数CGImageCreateで画像を生成する際には、bitmapInfo型の引数CGImageBitmapInfoでビット
マップレイアウト情報を指定します。以下の定数で、アルファ成分の位置と、色成分がアルファ値乗
算済みかどうかを指定できます。
●
kCGImageAlphaLast:アルファ成分は各ピクセルの最下位ビット列。RGBAなど。
●
kCGImageAlphaFirst:アルファ成分は各ピクセルの最上位ビット列。ARGBなど。
●
kCGImageAlphaPremultipliedLast:アルファ成分は各ピクセルの最下位ビット列。色成分はア
ルファ値乗算済み。
●
kCGImageAlphaPremultipliedFirst:アルファ成分は各ピクセルの最上位ビット列。色成分は
アルファ値乗算済み。
●
kCGImageAlphaNoneSkipLast:アルファ成分なし。ピクセル当たり総ビット数が、色空間に応
じた数の成分を収容するために必要なビット数よりも大きい場合、最下位ビット列を無視。
●
kCGImageAlphaNoneSkipFirst:アルファ成分なし。ピクセル当たり総ビット数が、色空間に応
じた数の成分を収容するために必要なビット数よりも大きい場合、最上位ビット列を無視。
●
kCGImageAlphaNone:kCGImageAlphaNoneSkipLastと同等。
定数kCGBitmapFloatComponentsで、浮動小数点数で値を表すビットマップ形式であることを表しま
す。先に挙げた定数とのOR(論理和)を取って指定してください。たとえば、浮動小数点数で値を表
す、ピクセル当たり128ビットのビットマップ形式で、色成分はアルファ値乗算済み、アルファ値は
最下位ビット列である場合、次の値を渡すことになります。
kCGImageAlphaPremultipliedLast|kCGBitmapFloatComponents
図 11-2に、CMYKおよびRGB色空間(ピクセル当たり16/32ビットの整数)で、各ピクセルをどのよう
に表すか、を示します。32ビット形式の場合、成分当たり8ビットを占めます。16ビット形式ならば
成分当たり5ビットです。ピクセル当たり128ビットの浮動小数点数(成分当たり32ビット)で表すこ
とも可能です(図は省略)。
図 11-2
32/16ビットのピクセル形式(CMYK/RGB色空間)
画像の生成
表 11-1 (126 ページ)に、CGImageオブジェクトを生成するQuartzの関数を示します。画像データソー
スに応じて使い分けてください。もっともきめ細かな指定ができるのはCGImageCreateです。あらゆ
る種類のビットマップデータから生成できますが、必要な情報をすべて指定しなければならないので
使い方も複雑です。この関数を使うためには、“ビットマップ画像に関する情報” (123 ページ)で説
明した事項を理解しておかなければなりません。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
125
ビットマップ画像と画像マスク
画像の生成
PNG、JPEGなど標準的な画像形式のファイルからCGImageオブジェクトを生成するためには、関数
CGImageSourceCreateWithURLで画像ソースを生成し、関数CGImageSourceCreateImageAtIndex
で、画像ソースの所定のインデックス位置にある画像データから生成する、という方法が便利でしょ
う。元の画像ファイルに画像が1つしかなければ、インデックスとして0を指定します。複数の画像を
収容できる画像ファイル形式の場合、該当する画像の番号を指定しますが、その番号は0から数える
ことに注意してください。
ビットマップグラフィックスコンテキストに何かを描画し、これをもとにCGImageオブジェクトを生
成する場合は、関数CGBitmapContextCreateImageを使います。
複製、サムネール生成、切り抜きなど、既存の画像を操作する関数もあります。CGImageオブジェク
トの生成方法にかかわらず、関数CGContextDrawImageで、画像をグラフィックスコンテキストに描
画できます。CGImageオブジェクトの書き換えはできないことに注意してください。CGImageオブジェ
クトが不要になったら、関数CGImageReleaseで解除します。
表 11-1
画像を生成する関数
関数
解説
CGImageCreate
もっとも自由度の高い画像生成関数。“ビットマップ画像に関
する情報” (123 ページ)で説明した情報をすべて指定しなけれ
ばなりません。
CGImageSourceCreateImageAtIndex
画像ソースから画像を生成。画像ソースに複数の画像があって
も構いません。画像ソースの生成については、“Quartz 2Dにお
けるデータ管理” (116 ページ)を参照してください。
CGImageSourceCreateThumbnailAtIndex
画像ソースから得られる画像をもとにサムネール画像を生成。
画像ソースの生成については、“Quartz 2Dにおけるデータ管
理” (116 ページ)を参照してください。
CGBitmapContextCreateImage
ビットマップグラフィックスコンテキストからビット列を複写
して画像を生成。
CGImageCreateWithImageInRect
既存の画像から指定した矩形範囲内を切り抜いて画像を生成。
CGImageCreateCopy
画像の複製を生成。
CGImageCreateCopyWithColorSpace
画像を複製し、色空間を置換。
以降の各節では、次の事項を説明します。
●
既存の画像の一部を切り抜いて画像を生成
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
126
ビットマップ画像と画像マスク
画像の生成
●
ビットマップグラフィックスコンテキストから画像を生成
詳しくは以下も参照してください。
●
●
“Quartz 2Dにおけるデータ管理” (116 ページ):画像データの読み書きについて。
『CGImage Reference 』、『CGImageSource Reference 』、『CGBitmapContext Reference 』:表 11-1に
示した各関数および引数の詳細。
画像の一部を切り抜いて新しい画像を生成
関数CGImageCreateWithImageInRectで、既存のQuartz画像の一部を切り抜き、新しい画像を生成す
ることができます。図 11-3に、大きな画像から「A」という文字の部分を切り抜く様子を示します。
文字「A」が含まれる範囲を矩形で指定しています。
図 11-3
大きな画像の一部を切り抜いて生成した画像
関数CGImageCreateWithImageInRectの戻り値である画像には、元の画像の参照も保持されている
ので、必要ならば後で元の画像を解除できます。
図 11-4 (127 ページ)に、画像の一部を切り抜いて新しい画像を生成する例を、もうひとつ示しま
す。ここでは、鶏の頭部を切り抜き、これよりも大きな矩形範囲に描画することにより拡大していま
す。
リスト 11-1 (127 ページ)に、画像の一部を切り抜いて描画するコード例を示します。関数
CGContextDrawImageで鶏の頭部を描画する際に指定する矩形は、幅や高さが切り抜いた画像の2倍
になっています。示したコード例は、要点を抜き書きしたものです。別途、必要な変数を宣言し、鶏
の画像を生成し、元の画像や切り抜いた画像を解除しなければなりません。また、画像の描画先であ
るグラフィックスコンテキストの生成処理も省略してあります。必要に応じ、どの種類のグラフィッ
クスコンテキストを使っても構いません。グラフィックスコンテキストを生成するコード例について
は、“グラフィックスコンテキスト” (24 ページ)を参照してください。
図 11-4
画像の一部を切り抜き、拡大して描画した様子
リスト 11-1 画像の一部を切り抜き、拡大して描画するコード例
myImageArea = CGRectMake (rooster_head_x_origin, rooster_head_y_origin,
myWidth, myHeight);
mySubimage = CGImageCreateWithImageInRect (myRoosterImage, myImageArea);
myRect = CGRectMake(0, 0, myWidth*2, myHeight*2);
CGContextDrawImage(context, myRect, mySubimage);
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
127
ビットマップ画像と画像マスク
画像マスクの生成
ビットマップグラフィックスコンテキストから画像を生成
既存のビットマップグラフィックスコンテキストから画像を生成するためには、次のように関数
CGBitmapContextCreateImageを使います。
CGImageRef myImage;
myImage = CGBitmapContextCreateImage (myBitmapContext);
戻り値であるCGImageオブジェクトは、複製を施して生成したものです。したがって、この後ビット
マップグラフィックスコンテキストに変更を施しても、CGImageオブジェクトには影響が及びませ
ん。実際には複製を書き換え時コピー(copy on write)方式で行う場合もあります。物理的にビット
列を複製する処理を、ビットマップグラフィックスコンテキスト側の該当するデータが変更される時
点まで遅らせる方式です。得られた画像を使った後すぐに解除し、それからビットマップグラフィッ
クスコンテキストに変更を施すようにすれば、物理的に複製する処理は不要です。
ビットマップグラフィックスコンテキストを生成するコード例については、“ビットマップグラフィッ
クスコンテキストの生成” (31 ページ)を参照してください。
画像マスクの生成
ビットマップ画像マスクには、画家が使うシルクスクリーンのような効果があります。どの色を使う
かではなく、色をどのように転写するか、を表すのです。画像マスクの各標本値は、該当する位置に
おいて、現在の塗りつぶし色をマスクする度合いを指定します。標本値はマスクの不透明度を表しま
す。値が大きいほど不透明度が高く、したがって新たに乗せる色の量が少なくなります。アルファ値
を反転したものと考えてもよいでしょう。値が1ならば完全に透明、0ならば完全に不透明になりま
す。
画像マスクの成分当たりビット数は、1、2、4、8のいずれかです。1ビットマスクの場合、標本値が
1であれば、その部分は現在の塗りつぶし色がまったく見えないことを表します。0ならば、グラフィッ
クス状態の現在の塗りつぶし色が完全に見えるようになります。1ビットマスクは、黒と白の対立の
ように、まったく色が見えないか、完全に見えるか、の2値で制御します。
成分当たりビット数が2、4、8の画像マスクは、グレースケール値を表します。~01の範囲の値を、
次の式で求められる量ごとに刻みます。
たとえば4ビットマスクの場合、0~1の範囲で、1/15刻みの値を取ります。値が0や1であれば、まっ
たく描画しない、あるいは完全に描画することを表します。0と1の間の値であれば、1 –
MaskSampleValueに相当する量だけ描画します。たとえば、8ビットマスクの該当する位置の値が0.7
であれば、アルファ値が(1 – 0.7)、すなわち0.3であるように描画されます。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
128
ビットマップ画像と画像マスク
画像のマスク処理
関数CGImageMaskCreateは、Quartzの画像マスクを、指定したビットマップ画像情報(“ビットマッ
プ画像に関する情報” (123 ページ)を参照)をもとに生成します。これは画像を生成する場合と同様
ですが、色空間、ビットマップ情報定数、レンダリングインテントの指定は必要ありません(リスト
11-2の関数仕様を参照)。
リスト 11-2 関数CGImageMaskCreateの引数並び
CGImageRef CGImageMaskCreate (
size_t width,
size_t height,
size_t bitsPerComponent,
size_t bitsPerPixel,
size_t bytesPerRow,
CGDataProviderRef provider,
const CGFloat decode[],
bool shouldInterpolate
);
画像のマスク処理
マスク技法を使いこなせば、画像の各部分の描画を制御し、次のような面白い効果を生み出すことが
できます。
●
●
●
画像マスクを画像に適用。また、画像をそのままマスクとして使うことにより、画像マスクを適
用するのとは反対の効果が得られます。
所定の色の部分をマスクとして適用。クロマキーの技法もそのひとつです。
グラフィックスコンテキストに、画像や画像マスクを使ってクリッピング領域を設定。ここに描
画すればクリッピングが適用されます。
画像マスクを使って画像の一部をマスク
関数CGImageCreateWithMaskで、画像マスクを画像に適用できます。この関数は2つの引数を取りま
す。
●
マスクを適用する画像。画像マスクそのものや、マスク色が使われているもの(“色に基づく画像
のマスク処理” (131 ページ)を参照)は使えません。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
129
ビットマップ画像と画像マスク
画像のマスク処理
●
関数CGImageMaskCreateで生成した画像マスク。画像マスクの代わりに、マスクを適用する画像
とは別の画像を与えることもできますが、適用した結果は異なります。“別の画像を使って画像を
マスク” (130 ページ)を参照してください。
画像マスクの各ピクセルの標本値は、アルファ値を反転したものと考えることができます。すなわ
ち、標本値(S)に応じて次のような効果があります。
●
1の場合:対応する位置は描画されません。
●
0の場合:対応する位置は完全に描画されます。
●
と0の間である場合:アルファ値が1であるように、対応する位置が描画されます。(1 – S).
図 11-5をQuartzの画像生成関数で生成した画像とします。これに、関数図 11-6「画像マスク」
CGImageMaskCreateのような画像マスクを適用してみましょう。関数図 11-7 (130 ページ)「元の画
像に画像マスクを適用して得られた画像」CGImageCreateWithMaskのようになります。
図 11-5
元の画像
図 11-6
画像マスク
元の画像のうち、マスクの黒い領域に対応する部分は、そのまま描画されていることがわかります
(図 11-7を参照)。一方、白い領域はまったく描画されていません。灰色の領域は、1からマスクの
標本値を引いた値に等しいアルファ値を適用して描画されています。
図 11-7
元の画像に画像マスクを適用して得られた画像
別の画像を使って画像をマスク
関数CGImageCreateWithMaskを使うと、画像マスクではなく別の画像を使って、マスクを適用する
ことができます。すると、画像マスクを適用するのとは反対の効果が得られます。関数
CGImageMaskCreateで生成した画像マスクの代わりに、Quartzの画像生成関数で生成した画像を渡し
ます。
マスクとして使う側の画像(画像マスクではない)の標本値が、アルファ値として適用されます。す
なわち、画像の標本値(S)に応じて次のような効果があります。
●
1の場合:対応する位置は完全に描画されます。
●
0の場合:対応する位置は描画されません。
●
0と1の間である場合:アルファ値がSであるように、対応する位置が描画されます。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
130
ビットマップ画像と画像マスク
画像のマスク処理
図 11-8 (131 ページ)に、関数CGImageCreateWithMaskを使って、図 11-6 (130 ページ)の画像を図
11-5 (130 ページ)の画像に適用した結果を示します。この場合図 11-6は、同じ画像でもCGImageCreate
などの画像生成関数で生成したものです。図 11-8と図 11-7 (130 ページ)を比べてみれば、同じ標本
値でも、画像マスクを適用した場合とは効果が反対であることがわかるでしょう。
元の画像のうち、画像の黒い部分に対応する部分は、まったく描画されていません(図 11-8を参照)。
一方、白い領域はそのまま描画されています。灰色の領域は、画像の標本値に等しいアルファ値を適
用して描画されています。
図 11-8
元の画像に別の画像をマスクとして適用して得られた画像
色に基づく画像のマスク処理
関数CGImageCreateWithMaskingColorsを使うと、ある画像のうち所定の色(または色の範囲)の
部分に対応する領域をマスクして、新しい画像を生成することができます。この関数で、図
11-9 (131 ページ)の所定の色の部分をマスクする、クロマキ処理ができます。あるいは、図
11-11 (132 ページ)、図 11-12 (132 ページ)、図 11-13 (133 ページ)のように、ある色の範囲の部
分をマスクとして使うことも可能です。
関数CGImageCreateWithMaskingColorsは次の2つの引数を取ります。
●
画像。画像マスクでも、画像マスクやマスク色を他の画像に適用した結果でもないもの。
●
色成分配列。画像のマスクに用いる色(または色範囲)を指定します。
図 11-9
クロマキーによるマスク処理
色成分配列の要素数は、画像の色空間における色成分の数の2倍とします。色成分ごとに、マスクと
して適用する範囲の最小値と最大値を設定します。単一の色だけを設定する場合は、最小値と最大値
を等しくしてください。値を次のような順序で設定します。
{min[1], max[1], ... min[N], max[N]}。ここでNは色成分の番号。
ピクセル値を整数で表している場合、色成分配列の各値は0 .. 2^bitsPerComponent - 1]の範囲
でなければなりません。浮動小数点数で表している場合は、色成分の値として有効な範囲とします。
色値が次の範囲に収まる場合、対応する位置は描画されません。
{c[1], ... c[N]}
ここで min[i] <= c[i] <= max[i] for 1 <= i <= N
描画しない領域は、背景としてあらかじめ描画されていた塗りつぶし色その他が、そのまま見えるよ
うになります。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
131
ビットマップ画像と画像マスク
画像のマスク処理
2頭の虎の画像(図 11-10)は、成分当たり8ビットのRGB色空間を使っています。ある色範囲の部分
をマスクする場合、該当する各色成分の最小値と最大値を、0~255の範囲で指定することになりま
す。
図 11-10
元の画像
リスト 11-3に、色成分配列を設定して関数CGImageCreateWithMaskingColorsに渡し、図 11-11のよ
うな画像を得るコード例を示します。
リスト 11-3 明るい茶色の部分をマスクするコード例
CGImageRef myColorMaskedImage;
const CGFloat myMaskingColors[6] = {124, 255,
68, 222, 0, 165};
myColorMaskedImage = CGImageCreateWithMaskingColors (image,
myMaskingColors);
CGContextDrawImage (context, myContextRect, myColorMaskedImage);
図 11-11
明るい茶色の部分をマスクして作った画像
リスト 11-4に、図 11-10 (132 ページ)の画像から図 11-12のような画像を作るコード例を示します。
この例では暗い色の部分をマスクしています。
リスト 11-4 濃茶から黒の部分をマスクするコード例
CGImageRef myMaskedImage;
const CGFloat myMaskingColors[6] = { 0, 124, 0, 68, 0, 0 };
myColorMaskedImage = CGImageCreateWithMaskingColors (image,
myMaskingColors);
CGContextDrawImage (context, myContextRect, myColorMaskedImage);
図 11-12
濃茶から黒の部分をマスクして作った画像
ある色範囲の部分をマスクし、所定の色で塗りつぶすことにより、図 11-13のような効果を得ること
も可能です。リスト 11-5に、図 11-13のような画像を生成するコード例を示します。
リスト 11-5 所定の色範囲の部分をマスクし、塗りつぶし色を設定するコード例
CGImageRef myMaskedImage;
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
132
ビットマップ画像と画像マスク
画像のマスク処理
const CGFloat myMaskingColors[6] = { 0, 124, 0, 68, 0, 0 };
myColorMaskedImage = CGImageCreateWithMaskingColors (image,
myMaskingColors);
CGContextSetRGBFillColor (myContext, 0.6373,0.6373, 0, 1);
CGContextFillRect(context, rect);
CGContextDrawImage(context, rect, myColorMaskedImage);
図 11-13
所定の色範囲の部分をマスクし、塗りつぶし色を設定して作った画像
コンテキストにクリッピング領域を設定することにより画像をマスク
関数CGContextClipToMaskは、マスクを所定の矩形にマップし、グラフィックスコンテキストの現
在のクリッピング領域との共通部分を取ったものを、改めてクリッピング領域として設定します。次
の引数を指定してください。
●
クリッピング領域を設定するグラフィックスコンテキスト。
●
マスクの適用範囲を表す矩形。
●
関数CGImageMaskCreateで生成した画像マスク。画像マスクの代わりに画像を渡すと、これとは
反対の効果が得られます。Quartzの画像生成関数で生成したものを与えますが、マスクやマスク
色が適用済みの画像は使えません。
結果として得られるクリッピング領域は、関数CGContextClipToMaskに渡したのが画像か画像マス
クかによっても異なります。画像マスクを渡した場合、クリッピングの対象がグラフィックスコンテ
キストであることを除き、“画像マスクを使って画像の一部をマスク” (129 ページ)で説明したよう
な結果が得られます。画像を渡した場合は、“別の画像を使って画像をマスク” (130 ページ)と同じ
ようにクリッピング領域が決まります。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
133
ビットマップ画像と画像マスク
画像にブレンドモードを適用
図 11-14を見てみましょう。これは関数CGImageMaskCreateで生成した画像マスクであるとし、引数
として関数CGContextClipToMaskに渡します。その結果得られるコンテキストは、黒の領域を描画
し、白の領域は描画しないものになります。グレー領域は、アルファ値が1–Sであるように描画され
ます(Sは画像マスクの標本値)。このコンテキストに、関数CGContextDrawImageで画像を描画す
ると、図 11-15のような結果が得られます。
図 11-14
マスクに用いる画像
図 11-15
画像マスクでクリッピング領域を設定したコンテキストに画像を描画した様子
マスク画像ではなく画像として処理すると、図 11-16のように、反対の結果が得られます。
図 11-16
画像でクリッピング領域を設定したコンテキストに画像を描画した様子
画像にブレンドモードを適用
Quartz 2Dのブレンドモード(“ブレンドモードの設定” (49 ページ)を参照)を使って、2つの画像を
合成する、あるいはグラフィックスコンテキストに別の図形を描画した上に画像を合成する、という
処理が可能です。この節では背景を描画した上に画像を合成する手法について説明します。
背景を描画した上に画像を合成する、一般的な手順を以下に示します。
1.
背景を描画します。
2.
関数CGContextSetBlendModeに適当な定数を指定して、ブレンドモードを設定します(ブレン
ドモードは『PDF Reference, Fourth Edition 』(Version 1.5, Adobe Systems, Inc.)の定義に基づいてい
ます)。
3.
合成しようとする画像を、関数CGContextDrawImageで描画します。
背景の上に比較(暗)ブレンドモードで画像を合成するコード例を示します。
CGContextSetBlendMode (myContext, kCGBlendModeDarken);
CGContextDrawImage (myContext, myRect, myImage2);
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
134
ビットマップ画像と画像マスク
画像にブレンドモードを適用
以下、Quartzに組み込まれたブレンドモードをそれぞれ適用し、図 11-17の左のように矩形を重ねた
背景の上に、右に示した画像を合成した結果を示します。いずれの場合も、まず矩形をグラフィック
スコンテキストに描画します。次に、適当な定数を渡して関数CGContextSetBlendModeを実行し、
ブレンドモードを設定します。最後に陸上選手の画像をグラフィックスコンテキストに描画します。
図 11-17
背景(左)とその上に合成する画像(右)
標準ブレンドモード
標準ブレンドモードの場合、背景の上に画像を完全に上書きする形で描画します。これは既定のブレ
ンドモードなので、明示的に設定する必要があるのは、別のモードに切り替えた後、標準モードに戻
したい場合に限ります。定数kCGBlendModeNormalを関数CGContextSetBlendModeに渡して実行す
るか、グラフィックス状態を関数CGContextRestoreGStateで復元します(切り替え前は標準ブレン
ドモードであったと仮定)。
図 11-18に、標準ブレンドモードで、図 11-17 (135 ページ)の背景の上に画像を合成した結果を示し
ます。アルファ値を1.0としたので、背景はまったく見えなくなっています。
図 11-18
標準ブレンドモードで画像を描画した結果
乗算ブレンドモード
乗算ブレンドモードは、背景画像の色値に前面画像の色値を掛け合わせます。その結果得られる色
は、背景と前面のどちらよりも暗くなります。
乗算ブレンドモードへの切り替えは、定数kCGBlendModeMultiplyを渡して、関数
CGContextSetBlendModeを実行することにより行います。図 11-19に、乗算ブレンドモードで、図
11-17 (135 ページ)の背景の上に画像を合成した結果を示します。
図 11-19
乗算ブレンドモードで画像を描画した結果
スクリーンブレンドモード
スクリーンブレンドモードは、背景画像の色値を反転し、前面画像の色値を反転して掛け合わせま
す。その結果得られる色は、背景と前面のどちらよりも明るくなります。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
135
ビットマップ画像と画像マスク
画像にブレンドモードを適用
スクリーンブレンドモードへの切り替えは、定数kCGBlendModeScreenを渡して、関数
CGContextSetBlendModeを実行することにより行います。図 11-20に、スクリーンブレンドモード
で、図 11-17 (135 ページ)の背景の上に画像を合成した結果を示します。
図 11-20
スクリーンブレンドモードで画像を描画した結果
オーバーレイブレンドモード
背景色に応じて、乗算ブレンドモードとスクリーンブレンドモードのいずれか適用します。背景の光
や影を残しつつ前景画像をオーバーレイするので、背景の明るさまたは暗さを反映した色になりま
す。
オーバーレイブレンドモードへの切り替えは、定数kCGBlendModeOverlayを渡して、関数
CGContextSetBlendModeを実行することにより行います。図 11-21に、オーバーレイブレンドモード
で、図 11-17 (135 ページ)の背景の上に画像を合成した結果を示します。
図 11-21
オーバーレイブレンドモードで画像を描画した結果
比較(暗)ブレンドモード
背景と前面画像の色のうち、暗い方を選びます。背景よりも前面画像の方が暗い箇所は、前面画像の
色になります。
比較(暗)ブレンドモードへの切り替えは、定数kCGBlendModeDarkenを渡して、関数
CGContextSetBlendModeを実行することにより行います。図 11-22に、比較(暗)ブレンドモード
で、図 11-17 (135 ページ)の背景の上に画像を合成した結果を示します。
図 11-22
比較(暗)ブレンドモードで画像を描画した結果
比較(明)ブレンドモード
背景と前面画像の色のうち、明るい方を選びます。背景よりも前面画像の方が明るい箇所は、前面画
像の色になります。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
136
ビットマップ画像と画像マスク
画像にブレンドモードを適用
比較(明)ブレンドモードへの切り替えは、定数kCGBlendModeLightenを渡して、関数
CGContextSetBlendModeを実行することにより行います。図 11-23に、比較(明)ブレンドモード
で、図 11-17 (135 ページ)の背景の上に画像を合成した結果を示します。
図 11-23
比較(明)ブレンドモードで画像を描画した結果
覆い焼きブレンドモード
背景の色を明るくして、前面画像の色に反映します。前面画像の色が黒である箇所は、背景のまま変
化しません。
覆い焼きブレンドモードへの切り替えは、定数kCGBlendModeColorDodgeを渡して、関数
CGContextSetBlendModeを実行することにより行います。図 11-24に、覆い焼きブレンドモードで、
図 11-17 (135 ページ)の背景の上に画像を合成した結果を示します。
図 11-24
覆い焼きブレンドモードで画像を描画した結果
焼き込みブレンドモード
背景の色を暗くして、前面画像の色に反映します。前面画像の色が白である箇所は、背景のまま変化
しません。
焼き込みブレンドモードへの切り替えは、定数kCGBlendModeColorBurnを渡して、関数
CGContextSetBlendModeを実行することにより行います。図 11-25に、焼き込みブレンドモードで、
図 11-17 (135 ページ)の背景の上に画像を合成した結果を示します。
図 11-25
焼き込みブレンドモードで画像を描画した結果
ソフトライトブレンドモード
前面画像の色に応じて、暗く、または明るくします。前面画像の色が50%グレーよりも明るい箇所
は、覆い焼きと同様に背景色を明るくします。そうでない箇所は、焼き込みと同様に背景色を暗くし
ます。50%グレーと等しければ、背景はそのままです。
前景画像が純粋な黒や白の箇所は暗く/明るくなりますが、純粋な黒や白にはなりません。背景上に
乱反射するスポットライトを照らしたような効果が生まれます。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
137
ビットマップ画像と画像マスク
画像にブレンドモードを適用
ソフトライトブレンドモードへの切り替えは、定数kCGBlendModeSoftLightを渡して、関数
CGContextSetBlendModeを実行することにより行います。図 11-26に、ソフトライトブレンドモード
で、図 11-17 (135 ページ)の背景の上に画像を合成した結果を示します。
図 11-26
ソフトライトブレンドモードで画像を描画した結果
ハードライトブレンドモード
前面画像の色に応じて、乗算ブレンドモードまたはスクリーンブレンドモードを適用します。前面画
像の色が50%グレーよりも明るい箇所は、スクリーンと同様に背景色を明るくします。そうでない箇
所は、乗算と同様に背景色を暗くします。50%グレーと等しければ、背景はそのままです。前景画像
が純粋な黒や白の箇所は、結果も純粋な黒や白になります。背景上にどぎつい色のスポットライトを
照らしたような効果が生まれます。
ハードライトブレンドモードへの切り替えは、定数kCGBlendModeHardLightを渡して、関数
CGContextSetBlendModeを実行することにより行います。図 11-27に、ハードライトブレンドモード
で、図 11-17 (135 ページ)の背景の上に画像を合成した結果を示します。
図 11-27
ハードライトブレンドモードで画像を描画した結果
差の絶対値ブレンドモード
背景と前面のどちらの輝度が大きいかに応じて、背景の色値から前面画像の色値を引くか、またはそ
の逆を行います。前面画像が黒である箇所は背景色のままです。白であれば背景色が反転します。
差の絶対値ブレンドモードへの切り替えは、定数kCGBlendModeDifferenceを渡して、関数
CGContextSetBlendModeを実行することにより行います。図 11-28に、差の絶対値ブレンドモード
で、図 11-17 (135 ページ)の背景の上に画像を合成した結果を示します。
図 11-28
差の絶対値ブレンドモードで画像を描画した結果
除外ブレンドモード
差の絶対値ブレンドモードとよく似た効果ですが、コントラストは低くなります。前面画像が黒であ
る箇所は背景色のままです。白であれば背景色が反転します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
138
ビットマップ画像と画像マスク
画像にブレンドモードを適用
除外ブレンドモードへの切り替えは、定数kCGBlendModeExclusionを渡して、関数
CGContextSetBlendModeを実行することにより行います。図 11-29に、除外ブレンドモードで、図
11-17 (135 ページ)の背景の上に画像を合成した結果を示します。
図 11-29
除外ブレンドモードで画像を描画した結果
色相ブレンドモード
背景の輝度と彩度、前面画像の色相を持つ色になります。色相ブレンドモードへの切り替えは、定数
kCGBlendModeHueを渡して、関数CGContextSetBlendModeを実行することにより行います。図 11-30
に、色相ブレンドモードで、図 11-17 (135 ページ)の背景の上に画像を合成した結果を示します。
図 11-30
色相ブレンドモードで画像を描画した結果
彩度ブレンドモード
背景の輝度と色相、前面画像の彩度を持つ色になります。彩度が0の領域(純粋なグレー領域)は背
景色のままです。彩度ブレンドモードへの切り替えは、定数kCGBlendModeSaturationを渡して、関
数CGContextSetBlendModeを実行することにより行います。図 11-31に、彩度ブレンドモードで、図
11-17 (135 ページ)の背景の上に画像を合成した結果を示します。
図 11-31
彩度ブレンドモードで画像を描画した結果
カラーブレンドモード
背景の輝度、前面画像の色相と彩度を持つ色になります。画像のグレーレベルはそのまま維持されま
す。カラーブレンドモードへの切り替えは、定数kCGBlendModeColorを渡して、関数
CGContextSetBlendModeを実行することにより行います。図 11-32に、カラーブレンドモードで、図
11-17 (135 ページ)の背景の上に画像を合成した結果を示します。
図 11-32
カラーブレンドモードで画像を描画した結果
輝度ブレンドモード
背景の色相と彩度、前面画像の輝度を持つ色になります。カラーブレンドモードとは正反対の効果が
あります。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
139
ビットマップ画像と画像マスク
画像にブレンドモードを適用
輝度ブレンドモードへの切り替えは、定数kCGBlendModeLuminosityを渡して、関数
CGContextSetBlendModeを実行することにより行います。図 11-33に、輝度ブレンドモードで、図
11-17 (135 ページ)の背景の上に画像を合成した結果を示します。
図 11-33
輝度ブレンドモードで画像を描画した結果
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
140
Core Graphicsのレイヤ描画
CGLayerオブジェクト(CGLayerRefデータ型)を使って、レイヤを利用した描画ができます。
レイヤは次のような状況に向いています。
●
●
●
高画質のオフスクリーン描画を行い、その結果を繰り返し利用する場合。たとえばアニメーショ
ン制作では、何枚もの絵に同じ背景を使うことになるでしょう。レイヤに背景を描画して保存し
ておけば、いつでもこれを描画できます。レイヤを描画する際、色空間やデバイス依存の情報を
意識する必要がない、という利点もあります。
反復描画。たとえば、同じ図形を何度も重ねて描画したパターンを生成する、という場合です。
図形をレイヤに描画しておき、これを繰り返し描画すればよいことになります(図 12-1を参照)。
CGPath、CGShading、CGPDFPageなど、Quartzのオブジェクトは何でも、CGLayerに描画して繰り
返し利用すれば、性能を改善できます。レイヤはオンスクリーン描画のためだけのものではあり
ません。PDFグラフィックスコンテキストなど、画面以外のグラフィックスコンテキストにも利
用できます。
バッファリング。この目的にレイヤを使うことも可能ですが、Quartz Compositorが代わりにこの
処理をするので、通常は必要ありません。バッファに描画しなければならない場合は、ビット
マップグラフィックスコンテキストではなくレイヤを使ってください。
図 12-1
同じ蝶の画像を繰り返し描画した様子
CGLayerオブジェクトと透明レイヤとの関係は、CGPathオブジェクトと、CGContext関連の関数群で生
成したパスとの関係に対応します。CGLayerやCGPathの場合、仮想的な描画先に描画しておき、最終
的に、ディスプレイやPDFなど他の描画先にこれを描画することになります。一方、透明レイヤに描
画したり、CGContextの関数群でパスを描画したりする場合、グラフィックスコンテキストで表され
る描画先に直接描画します。中間にはさまる仮想的な描画先はありません。
レイヤ描画の動作
レイヤ(CGLayerRefデータ型)には性能向上の目的があります。可能であれば、対応するグラフィッ
クスコンテキストの種類に応じた適当な機構により、CGLayerオブジェクトをキャッシュするように
なっています。たとえばビデオカードに対応するグラフィックスコンテキストの場合、レイヤはビデ
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
141
Core Graphicsのレイヤ描画
レイヤ描画の動作
オカードにキャッシュされます。したがって同じ画像であっても、レイヤを使う方が、ビットマップ
グラフィックスコンテキストの画像を描画するよりも高速です。そのためオフスクリーン描画には、
ビットマップグラフィックスコンテキストを使うよりもよい選択肢であると言えます。
Quartzの描画関数が描画する対象はいずれもグラフィックスコンテキストです。これには描画先を抽
象化する働きがあるので、解像度など描画先の詳細を意識する必要はありません。ユーザ空間で描画
すれば、Quartz側が必要な変換を施して、描画先に正しく描画します。CGLayerオブジェクトを使う場
合も、最終的にグラフィックスコンテキストに描画することになります。図 12-1に、レイヤ描画に必
要な手順を示します。
図 12-2
レイヤ描画
レイヤ描画においては、まずグラフィックスコンテキストを用意し、ここから関数
CGLayerCreateWithContextでCGLayerオブジェクトを生成します。通常、CGLayerオブジェクトの生
成には、ウインドウグラフィックスコンテキストを使います。生成されたレイヤは、解像度、色空
間、グラフィックス状態など、グラフィックスコンテキストの特性をすべて設定した状態になってい
ます。レイヤの大きさが、グラフィックスコンテキストから受け継いだ設定のままでは不都合な場
合、設定し直すことも可能です。図 12-2の左側は、レイヤの生成に用いるグラフィックスコンテキス
トです。右側の箱の見出し「CGLayerオブジェクト」は、新たに生成したレイヤであることを示して
います。
レイヤに描画するためには、これに対応するグラフィックスコンテキストを、関数CGLayerGetContext
で取得しておかなければなりません。このグラフィックスコンテキストは、レイヤの生成に使ったの
と同じ種類です。ウインドウグラフィックスコンテキストからレイヤを生成した場合、CGLayerグラ
フィックスコンテキストは可能な限りGPUにキャッシュされます。図 12-2の右側、箱の白い部分は、
新たに生成したレイヤグラフィックスコンテキストを表します。
描画の際には、グラフィックスコンテキストとして、このレイヤグラフィックスコンテキストを描画
関数に渡します。図 12-2には、レイヤコンテキストに葉の図形を描画した様子が示されています。
レイヤに描画した後、関数CGContextDrawLayerInRectまたはCGContextDrawLayerAtPointで、レ
イヤをグラフィックスコンテキストに描画します。通常はレイヤオブジェクトの生成に用いたのと同
じグラフィックスコンテキストに描画しますが、そうでなくても構いません。どのグラフィックスコ
ンテキストにでも描画できます。ただし、レイヤオブジェクトの生成に用いたグラフィックスコンテ
キストの特性を受け継いでいるので、処理性能や解像度などに制限が生じる場合があります。たとえ
ば画面に関連づけられたレイヤは、キャッシュ先がビデオハードウェアになります。実際に描画する
のがプリンタやPDFコンテキストであれば、このハードウェアからメモリに転送しなければならず、
性能劣化の原因となります。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
142
Core Graphicsのレイヤ描画
レイヤを用いた描画
図 12-2 (142 ページ)に、レイヤの中身(葉)を、レイヤオブジェクトの生成に用いたのと同じグラ
フィックスコンテキストに、反復描画した様子を示します。必要なだけ繰り返して描画した後、使い
終わったCGLayerオブジェクトを解除してください。
ヒント: 描画したオブジェクトをグループ化し、全体に影をつけるなどの処理をしたい場合
は、透明レイヤを使います(“透明レイヤ” (113 ページ)を参照)。CGLayerオブジェクト
は、オフスクリーン描画する、あるいは同じものを反復描画する場合に利用してください。
レイヤを用いた描画
CGLayerオブジェクトを使って描画する手順を、次の各節に分けて説明します。
1.
“CGLayerオブジェクトの生成(既存のグラフィックスコンテキストで初期化)” (143 ページ)
2.
“レイヤのグラフィックスコンテキストを取得” (144 ページ)
3.
“CGLayerグラフィックスコンテキストへの描画” (144 ページ)
4.
“レイヤを描画先グラフィックスコンテキストに描画” (144 ページ)
詳しいコード例は“例:複数のCGLayerオブジェクトを組み合わせて旗を描画” (145 ページ)を参照し
てください。
CGLayerオブジェクトの生成(既存のグラフィックスコンテキストで初期
化)
関数CGLayerCreateWithContextを使って、既存のグラフィックスコンテキストで初期化したレイヤ
オブジェクトを取得できます。このレイヤはグラフィックスコンテキストの特性(色空間、大きさ、
解像度、ピクセル形式など)を受け継いでいます。後で最終的な描画先にレイヤを描画する際、自動
的に描画先コンテキストに合わせて色などが変換されます。
関数CGLayerCreateWithContextは3つの引数を取ります。
●
●
●
レイヤの生成に用いるグラフィックスコンテキスト。通常はウインドウグラフィックスコンテキ
ストを渡します。後でオンスクリーンでレイヤを描画できるようにするためです。
レイヤの大きさ(グラフィックスコンテキストを基準とした相対値)。グラフィックスコンテキ
ストと同じ大きさでも、これより小さくても構いません。後でレイヤの大きさを知る必要が生じ
た場合は、関数CGLayerGetSizeで調べます。
補助の辞書。現在は未使用なので、NULLを渡してください。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
143
Core Graphicsのレイヤ描画
レイヤを用いた描画
レイヤのグラフィックスコンテキストを取得
Quartzが描画する対象は、常にグラフィックスコンテキストです。レイヤに描画する場合も、これに
対応するグラフィックスコンテキストを生成しなければなりません。レイヤグラフィックスコンテキ
ストに描画すると、その内容はすべてレイヤに取り込まれます。
関数CGLayerGetContextは、レイヤを引数として取り、これに対応するグラフィックスコンテキス
トを返します。
CGLayerグラフィックスコンテキストへの描画
レイヤに対応するグラフィックスコンテキストを取得すると、ここに何でも描画できるようになりま
す。PDFファイルや画像ファイルを開き、その内容をレイヤに描画することも可能です。Quartz 2Dの
関数を自由に使って、矩形や線などのプリミティブを描画できます。図 12-3に、レイヤに矩形と線を
描画した例を示します。
図 12-3
2つの矩形とひと続きの線を描画したレイヤ
たとえば塗りつぶした矩形をCGLayerグラフィックスコンテキストに描画するためには、関数
CGContextFillRectで取得したグラフィックスコンテキストを引数として、関数CGLayerGetContext
を実行します。グラフィックスコンテキストの名前をmyLayerContextとすれば、関数を呼び出す記
述は次のようになります。
CGContextFillRect (myLayerContext, myRect)
レイヤを描画先グラフィックスコンテキストに描画
以上でレイヤを描画先グラフィックスコンテキストに描画する準備が整ったので、次のいずれかの関
数を実行します。
●
CGContextDrawLayerInRect:グラフィックスコンテキストの、指定した矩形内に描画。
●
CGContextDrawLayerAtPoint:グラフィックスコンテキストの、指定した点の位置に描画。
通常、この関数に渡す描画先はウインドウグラフィックスコンテキストであり、レイヤ生成時に使っ
たのと同じものです。図 12-4に、図 12-3 (144 ページ)で描画したレイヤを、繰り返し描画した結果
を示します。パターン効果を生み出すため、オフセットを変えながら、関数
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
144
Core Graphicsのレイヤ描画
例:複数のCGLayerオブジェクトを組み合わせて旗を描画
CGContextDrawLayerAtPointまたはCGContextDrawLayerInRectを繰り返し実行しています。たと
えば関数CGContextTranslateCTMで、座標系の原点を動かしながらレイヤを描画するとよいでしょ
う。
図 12-4
レイヤを反復描画した様子
注意: レイヤを描画するグラフィックスコンテキストは、レイヤ生成時に用いたのと同じで
なくても構いません。しかしその場合、元のグラフィックスコンテキストにあった制約がそ
のまま引き継がれます。
例:複数のCGLayerオブジェクトを組み合わせて旗を描画
この節では、CGLayerオブジェクトを2つ利用して、図 12-5のような旗を画面に描画します。まず、こ
の旗を単純な描画プリミティブに分割する方法を説明し、それから実際に描画するコードを見ていき
ます。
図 12-5
レイヤを利用してアメリカ国旗を描画した結果
画面に描画する手順を考慮すると、この旗を次の3つの部分に分割できます。
●
●
●
赤と白の縞模様のパターン。実際には単なる赤い縞と考えて構いません。オンスクリーン描画で
は、背景が白いと想定してよいからです。赤の矩形を1つ生成し、オフセットを変えながら反復
描画することにより、アメリカ国旗に必要な7本の縞を生成します。レイヤはこのような反復描
画に向いています。したがって、赤い矩形をレイヤに描画しておき、これを7回繰り返して描画
することにします。
青地の矩形(カントン)。これは1回描画するだけなので、レイヤを使う利点はありません。直
接オンスクリーンで描画します。
50個の白い星のパターン。赤の縞と同様、星の描画にもレイヤが向いています。星の輪郭を表す
パスを生成し、内側を白で塗りつぶします。これをレイヤに1個描画し、適当な間隔になるよう
オフセットを調整しながら50回描画します。
図 12-2 (142 ページ)のコードを実行すると、図 12-5のような出力が得られます。コード例を示した
後、番号がついている行について詳しく説明します。コードはかなり長いので、説明の部分を印刷し
ておき、コードと対比しながら読むとよいでしょう。ルーチンmyDrawFlagはCocoaアプリケーション
側から呼び出されます。その際、引数として、ウインドウグラフィックスコンテキストと、これに対
応するビューの大きさを表す矩形が渡されます。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
145
Core Graphicsのレイヤ描画
例:複数のCGLayerオブジェクトを組み合わせて旗を描画
注意: CGLayerオブジェクトを使うルーチンを呼び出す前に、稼動環境がMac OS X v10.4以降
であること、CGLayerオブジェクトに対応したグラフィックスカードを搭載していることを
確認しなければなりません。
リスト 12-1 レイヤを利用して旗を描画するコード
void myDrawFlag (CGContextRef context, CGRect* contextRect)
{
int
i, j,
num_six_star_rows = 5,
num_five_star_rows = 4;
CGFloat
start_x = 5.0,
// 1
start_y = 108.0,
// 2
red_stripe_spacing = 34.0,
// 3
h_spacing = 26.0,
// 4
v_spacing = 22.0;
// 5
CGContextRef myLayerContext1,
myLayerContext2;
CGLayerRef
stripeLayer,
starLayer;
CGRect
myBoundingBox,
// 6
stripeRect,
starField;
// ***** Setting up the primitives *****
const CGPoint myStarPoints[] = {{ 5, 5},
{10, 15},
{10, 15},
{15, 5},
{15, 5},
{2.5, 11},
// 7
{2.5, 11}, {16.5, 11},
{16.5, 11},{5, 5}};
stripeRect
starField
= CGRectMake (0, 0, 400, 17); // stripe
=
CGRectMake (0, 102, 160, 119); // star field
myBoundingBox = CGRectMake (0, 0, contextRect->size.width,
contextRect->size.height);
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
146
// 8
// 9
// 10
Core Graphicsのレイヤ描画
例:複数のCGLayerオブジェクトを組み合わせて旗を描画
// ***** Creating layers and drawing to them *****
stripeLayer = CGLayerCreateWithContext (context,
// 11
stripeRect.size, NULL);
myLayerContext1 = CGLayerGetContext (stripeLayer);
// 12
CGContextSetRGBFillColor (myLayerContext1, 1, 0 , 0, 1);
// 13
CGContextFillRect (myLayerContext1, stripeRect);
// 14
starLayer = CGLayerCreateWithContext (context,
starField.size, NULL);
// 15
myLayerContext2 = CGLayerGetContext (starLayer);
// 16
CGContextSetRGBFillColor (myLayerContext2, 1.0, 1.0, 1.0, 1);
// 17
CGContextAddLines (myLayerContext2, myStarPoints, 10);
// 18
CGContextFillPath (myLayerContext2);
// 19
// ***** Drawing to the window graphics context *****
CGContextSaveGState(context);
// 20
for (i=0; i< 7;
// 21
i++)
{
CGContextDrawLayerAtPoint (context, CGPointZero, stripeLayer);
// 22
CGContextTranslateCTM (context, 0.0, red_stripe_spacing);
// 23
}
CGContextRestoreGState(context);
// 24
CGContextSetRGBFillColor (context, 0, 0, 0.329, 1.0);
// 25
CGContextFillRect (context, starField);
// 26
CGContextSaveGState (context);
// 27
CGContextTranslateCTM (context, start_x, start_y);
// 28
for (j=0; j< num_six_star_rows;
// 29
j++)
{
for (i=0; i< 6;
i++)
{
CGContextDrawLayerAtPoint (context,CGPointZero,
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
147
Core Graphicsのレイヤ描画
例:複数のCGLayerオブジェクトを組み合わせて旗を描画
starLayer);
CGContextTranslateCTM (context, h_spacing, 0);
// 30
// 31
}
CGContextTranslateCTM (context, (-i*h_spacing), v_spacing);
// 32
}
CGContextRestoreGState(context);
CGContextSaveGState(context);
CGContextTranslateCTM (context, start_x + h_spacing/2,
// 33
start_y + v_spacing/2);
for (j=0; j< num_five_star_rows;
j++)
// 34
{
for (i=0; i< 5;
i++)
{
CGContextDrawLayerAtPoint (context, CGPointZero,
starLayer);
// 35
CGContextTranslateCTM (context, h_spacing, 0);
// 36
}
CGContextTranslateCTM (context, (-i*h_spacing), v_spacing);
// 37
}
CGContextRestoreGState(context);
CGLayerRelease(stripeLayer);
// 38
CGLayerRelease(starLayer);
// 39
}
このコードが実行することを以下に示します。
1.
最初に描画する星のx座標を表す変数を宣言します。
2.
最初に描画する星のy座標を表す変数を宣言します。
3.
赤い縞の間隔を表す変数を宣言します。
4.
星と星との間隔(横方向)を表す変数を宣言します。
5.
星と星との間隔(縦方向)を表す変数を宣言します。
6.
旗を描画する範囲を表す矩形(境界ボックス)、縞のレイヤを表す矩形、カントン(星が並んで
いる領域)の位置を表す矩形を宣言します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
148
Core Graphicsのレイヤ描画
例:複数のCGLayerオブジェクトを組み合わせて旗を描画
7.
1個の星を形作るパスの頂点を並べた配列を宣言します。
8.
1本の縞の形状を表す矩形を生成します。
9.
カントンの形状を表す矩形を生成します。
10. 境界ボックスを生成します。myDrawFlagに渡されたウインドウグラフィックスコンテキストの
大きさと同じです。
11. レイヤを生成し、myDrawFlagに渡されたウインドウグラフィックスコンテキストを使って初期
化します。
12. このレイヤに対応するグラフィックスコンテキストを取得します。このレイヤは赤の縞を描画す
るために使います。
13. 縞を描画するレイヤに対応するグラフィックスコンテキストに、塗りつぶし色として不透明な赤
を設定します。
14. 1本の赤い縞を表す矩形を塗りつぶします。
15. もうひとつレイヤを生成し、myDrawFlagに渡されたウインドウグラフィックスコンテキストを
使って初期化します。
16. このレイヤに対応するグラフィックスコンテキストを取得します。このレイヤは星を描画するた
めに使います。
17. 星を描画するレイヤに対応するグラフィックスコンテキストに、塗りつぶし色として不透明な白
を設定します。
18. 配列myStarPointsで定義された10本の線を、このレイヤに対応するコンテキストに追加します。
19. 10本の線から成るパスの内側を塗りつぶします。
20. ウインドウグラフィックスコンテキストのグラフィックス状態を保存します。これが必要なの
は、位置を変えながら同じ縞を繰り返し描画するためです。
21. 赤い縞を7回反復して描画するためのループです。
22. 縞のレイヤ(赤い縞)を描画します。
23. 現在の変換行列を平行移動して、次の縞の描画位置に原点を動かします。
24. 縞を描画する前の状態に、グラフィックス状態を復元します。
25. カントンの塗りつぶし色として、適度に暗めの青を設定します。不透明度が1.0であることに注意
してください。この例では色をすべて不透明にしていますが、目的によっては、そうでなくても
構いません。半透明をうまく活用すれば、さまざまな効果を得ることができます。アルファ値を
0.0にすれば完全に透明になります。
26. カントンを青で塗りつぶします。これはウインドウグラフィックスコンテキストに直接描画しま
す。1回しか描画しないので、レイヤを使う必要はありません。
27. ウインドウグラフィックスコンテキストのグラフィックス状態を保存します。これが必要なの
は、星の位置に合わせてCTMを変換(平行移動)することになるからです。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
149
Core Graphicsのレイヤ描画
例:複数のCGLayerオブジェクトを組み合わせて旗を描画
28. CTMを変換して、左下の星の位置が原点になるようにします。
29. 以下の2つのループで、6つの星が並ぶ奇数番目の行について、反復処理を行います。
30. 星のレイヤをウインドウグラフィックスコンテキストに描画します。先にも述べたように、この
レイヤには白い星が1つ描画されています。
31. 原点を右に移動して、隣の星を描画できるようにします。
32. 原点のx座標を左に戻し、y座標を上に移動して、次の行の星を描画できるようにします。
33. CTMを変換して、下から2行目の一番左にある星の位置が原点になるようにします。偶数番目の行
は、星の位置が、奇数番目の行とはずれていることに注意してください。
34. 以下の2つのループで、5つの星が並ぶ偶数番目の行について、反復処理を行います。
35. 星のレイヤをウインドウグラフィックスコンテキストに描画します。
36. 原点を右に移動して、隣の星を描画できるようにします。
37. 原点のx座標を左に戻し、y座標を上に移動して、次の行の星を描画できるようにします。
38. 縞のレイヤを解除します。
39. 星のレイヤを解除します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
150
PDFドキュメントの生成、表示、変換
PDFドキュメントには、解像度に非依存のベクトルグラフィックス、テキスト、画像が、記述密度の
高い(冗長性が小さい)プログラミング言語で記述したコマンド列の形で記録されています。画像や
テキストから成る、複数のページを収容できるのも特徴です。プラットフォームに依存しない読み取
り専用のドキュメント、解像度非依存のグラフィックスに向いています。
Quartzには描画処理結果を忠実に記録したPDFドキュメントを作成する機能があり、どのようなアプ
リケーションからも利用できます(図 13-1を参照)。できあがったPDFは、システムのほかの機能、
あるいは他社製品を使って、(特定のプリンタ出力用、ウェブ表示用など)特定の目的に最適化でき
ることがあります。Quartzで生成したPDFドキュメントは、PreviewやAcrobatで正しく表示できます。
図 13-1
Quartzで高品質のPDFドキュメントを生成
QuartzはPDFを単なる「ディジタルペーパ」として使うだけでなく、PDFファイルを表示、生成するな
ど、さまざまな処理を行うAPIを多数備えています。
PDFの記述言語やその構文など詳しくは、『PDF Reference 』(Fourth Edition, Version 1.5)を参照して
ください。
PDFのオープン/表示
QuartzにはPDFドキュメントを表すデータ型CGPDFDocumentRefがあります。CGPDFDocumentオブジェ
クトの生成には、関数CGPDFDocumentCreateWithProviderまたはCGPDFDocumentCreateWithURLを
使います。生成したCGPDFDocumentオブジェクトは、グラフィックスコンテキストに描画できます。
図 13-2に、ウインドウ内にPDFドキュメントを表示している様子を示します。
図 13-2
PDFドキュメント
リスト 13-1に、CGPDFDocumentオブジェクトを生成し、ドキュメントのページ数を取得するコード
例を示します。コード例を示した後、番号がついている行について詳しく説明します。
リスト 13-1 既存のPDFファイルをもとにCGPDFDocumentオブジェクトを生成
CGPDFDocumentRef MyGetPDFDocumentRef (const char *filename)
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
151
PDFドキュメントの生成、表示、変換
PDFのオープン/表示
{
CFStringRef path;
CFURLRef url;
CGPDFDocumentRef document;
size_t count;
path = CFStringCreateWithCString (NULL, filename,
kCFStringEncodingUTF8);
url = CFURLCreateWithFileSystemPath (NULL, path,
// 1
kCFURLPOSIXPathStyle, 0);
CFRelease (path);
document = CGPDFDocumentCreateWithURL (url);
// 2
CFRelease(url);
count = CGPDFDocumentGetNumberOfPages (document);
// 3
if (count == 0) {
printf("`%s' needs at least one page!", filename);
return NULL;
}
return document;
}
このコードが実行することを以下に示します。
1.
Core Foundationの関数でCFURLオブジェクトを生成します。表示するPDFファイルの名前を格納し
たCFStringオブジェクトを引数とします。
2.
CFURLオブジェクトからCGPDFDocumentオブジェクトを生成します。
3.
PDFのページ数を取得し、次の文で、少なくとも1ページはあることを確認します。
PDFページをグラフィックスコンテキストに描画するコード例をリスト 13-2に示します。コード例を
示した後、番号がついている行について詳しく説明します。
リスト 13-2 PDFページの描画
void MyDisplayPDFPage (CGContextRef myContext,
size_t pageNumber,
const char *filename)
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
152
PDFドキュメントの生成、表示、変換
PDFページを対象とする座標変換の生成
{
CGPDFDocumentRef document;
CGPDFPageRef page;
document = MyGetPDFDocumentRef (filename);
// 1
page = CGPDFDocumentGetPage (document, pageNumber);
// 2
CGContextDrawPDFPage (myContext, page);
// 3
CGPDFDocumentRelease (document);
// 4
}
このコードが実行することを以下に示します。
1.
先に示した関数(リスト 13-1 (151 ページ)を参照)で、指定したファイル名をもとに
CGPDFDocumentオブジェクトを生成します。
2.
PDFドキュメントの、指定した番号のページを取得します。
3.
関数CGContextDrawPDFPageでこのページを描画します。グラフィックスコンテキストと、描画
するページを、引数として渡します。
4.
CGPDFDocumentオブジェクトを解除します。
PDFページを対象とする座標変換の生成
関数CGPDFPageGetDrawingTransformは、PDFページ内のボックスを指定した矩形に変換する、ア
フィン変換を生成します。仕様(引数並び)は次の通りです。
CGAffineTransform CGPDFPageGetDrawingTransform (
CGPPageRef page,
CGPDFBox box,
CGRect rect,
int rotate,
bool preserveAspectRatio
);
この関数の戻り値はアフィン変換で、次のようなアルゴリズムを使います。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
153
PDFドキュメントの生成、表示、変換
PDFページを対象とする座標変換の生成
引数boxで指定したページボックス(メディア、クロップ、ブリード、トリム、アート)に対応
する矩形と、PDFページの/MediaBoxエントリとの共通部分を取り、その結果を実効矩形としま
す。
●
●
実効矩形に、PDFページの/Rotateエントリで表される角度の回転を施します。
●
この矩形を、引数rectで指定された矩形の中央に配置します。
引数rotateの値が90の倍数(0を除く)であれば、実効矩形をこの角度だけ回転します。正の値
であれば右回り、負ならば左回りです。ラジアン単位ではなく度単位であることに注意してくだ
さい。PDFページの/Rotateエントリにも角度が設定されているので、引数rotateと/Rotateエ
ントリの効果が重なります。
●
必要ならば実効矩形に拡大縮小を施して、指定した矩形にちょうど納まるようにします。
●
引数true(縦横比の保存)としてpreserveAspectRatioを渡した場合、最終的な矩形は、引数
rectで指定した矩形内に納まる最大の大きさになります。
●
この関数は、たとえば図 13-3 (154 ページ)のようなPDF表示アプリケーションを開発する際に有用
です。左回転/右回転の機能を組み込む場合、関数CGPDFPageGetDrawingTransformで、現在のウイ
ンドウの大きさと回転角に応じた変換を求めればよいことになります。
図 13-3
右に90°回転したPDFページ
リスト 13-3に、PDFページに対するアフィン変換を生成し、実際に変換を施して表示するコード例を
示します。コード例を示した後、番号がついている行について詳しく説明します。
リスト 13-3 PDFページを対象とするアフィン変換の生成
void MyDrawPDFPageInRect (CGContextRef context,
CGPDFPageRef page,
CGPDFBox box,
CGRect rect,
int rotation,
bool preserveAspectRatio)
{
CGAffineTransform m;
m = CGPDFPageGetDrawingTransform (page, box, rect, rotation,
// 1
preserveAspectRato);
CGContextSaveGState (context);
// 2
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
154
PDFドキュメントの生成、表示、変換
PDFファイルの生成
CGContextConcatCTM (context, m);
// 3
CGContextClipToRect (context,CGPDFPageGetBoxRect (page, box));
// 4
CGContextDrawPDFPage (context, page);
// 5
CGContextRestoreGState (context);
// 6
}
このコードが実行することを以下に示します。
1.
引数として指定された値に基づき、アフィン変換を生成します。
2.
グラフィックス状態を保存します。
3.
CTMにアフィン変換を結合します。
4.
グラフィックスコンテキストに、引数boxで指定された矩形をクリッピング領域として設定しま
す。関数CGPDFPageGetBoxRectは、指定された定数(kCGPDFMediaBox、kCGPDFCropBox、
kCGPDFBleedBox、kCGPDFTrimBox、kCGPDFArtBox)に応じ、ページボックス(メディア、ク
ロップ、ブリード、トリム、アート)を返します。
5.
変換とクリッピングの設定をしたコンテキストに、PDFページを描画します。
6.
グラフィックス状態を元の状態に復元します。
PDFファイルの生成
Quartz 2Dを使うと、グラフィックスコンテキストに描画するだけで簡単にPDFファイルを生成できま
す。PDFファイルの場所を指定し、PDFグラフィックスコンテキストを用意すれば、他のグラフィッ
クスコンテキストを対象とする場合と同じルーチンで描画できます。MyCreatePDFFile「PDFファイ
ルの生成」リスト 13-4に、PDFファイルの生成に必要な処理を示します。コード例を示した後、番号
がついている行について詳しく説明します。
PDFページの境界を定めるために、関数CGPDFContextBeginPageおよびCGPDFContextEndPageを実
行していることに注意してください。CFDictionaryオブジェクトを引数として渡して、ページボック
ス(メディア、クロップ、ブリード、トリム、アート)の大きさなど、ページプロパティを指定でき
ます。辞書のキーとして使える定数およびその詳細については、『CGPDFContextReference 』を参照し
てください。
リスト 13-4 PDFファイルの生成
void MyCreatePDFFile (CGRect pageRect, const char *filename)
{
CGContextRef pdfContext;
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
155
// 1
PDFドキュメントの生成、表示、変換
PDFファイルの生成
CFStringRef path;
CFURLRef url;
CFDataRef boxData = NULL;
CFMutableDictionaryRef myDictionary = NULL;
CFMutableDictionaryRef pageDictionary = NULL;
path = CFStringCreateWithCString (NULL, filename,
// 2
kCFStringEncodingUTF8);
url = CFURLCreateWithFileSystemPath (NULL, path,
// 3
kCFURLPOSIXPathStyle, 0);
CFRelease (path);
myDictionary = CFDictionaryCreateMutable(NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
// 4
CFDictionarySetValue(myDictionary, kCGPDFContextTitle, CFSTR("My PDF File"));
CFDictionarySetValue(myDictionary, kCGPDFContextCreator, CFSTR("My Name"));
pdfContext = CGPDFContextCreateWithURL (url, &pageRect, myDictionary);
// 5
CFRelease(myDictionary);
CFRelease(url);
pageDictionary = CFDictionaryCreateMutable(NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
// 6
boxData = CFDataCreate(NULL,(const UInt8 *)&pageRect, sizeof (CGRect));
CFDictionarySetValue(pageDictionary, kCGPDFContextMediaBox, boxData);
CGPDFContextBeginPage (pdfContext, pageDictionary);
// 7
myDrawContent (pdfContext);
// 8
CGPDFContextEndPage (pdfContext);
// 9
CGContextRelease (pdfContext);
// 10
CFRelease(pageDictionary);
// 11
CFRelease(boxData);
}
このコードが実行することを以下に示します。
1.
引数として、PDFページの大きさを表す矩形と、ファイル名を表す文字列を取ります。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
156
PDFドキュメントの生成、表示、変換
リンクの追加
2.
関数MyCreatePDFFileに渡されたファイル名をもとに、CFStringオブジェクトを生成します。
3.
このCFStringオブジェクトからCFURLオブジェクトを生成します。
4.
メタデータを保持する空のCFDictionaryオブジェクトを生成します。以下の2行で、題名と作成者
の情報を追加します。必要に応じていくつでも、関数CFDictionarySetValueでキーと値の組を
追加できます。辞書の生成について詳しくは、『CFDictionary Reference 』を参照してください。
5.
次の3つの引数を指定して、PDFグラフィックスコンテキストを生成します。
●
CFURLオブジェクト。PDFデータの場所を表します。
●
PDFページの規定の大きさと位置を表す矩形を指すポインタ。原点は通常(0, 0)とします。こ
れがメディアボックスの既定の境界になります。NULLを指定すれば、Quartzの既定の大きさ
である、8.5 x 11インチ(612 x 792ポイント)となります。
●
PDFメタデータを収容したCFDictionaryオブジェクト。メタデータを追加する必要がなければ
NULLを指定してください。
CFDictionaryオブジェクトで設定できる事項としては、出力インテントに関する設定(インテ
ントのサブタイプ、条件、条件識別子、レジストリ名、描画先の出力プロファイル)や、意
図するターゲットデバイスや生成条件に関する追加情報や注釈(人が読める形式の文字列)
があります。出力インテントに関する設定事項については、『CGPDFContext Reference 』を参
照してください。
6.
PDFページのページボックスを保持するCFDictionaryオブジェクトを生成します。この例ではメ
ディアボックスを設定しています。
7.
ページを開始する旨の合図を送ります。複数のページを保持できるグラフィックスコンテキスト
(PDFなど)を使う場合、関数CGPDFContextBeginPageとCGPDFContextEndPageで、出力のペー
ジ境界を示す必要があります。各ページを描画する最初と最後に、CGPDFContextBeginPageと
CGPDFContextEndPageを呼び出します。この2つの関数ではさまれた範囲以外で描画しても無視
されます。
8.
PDFコンテキストに描画する、アプリケーション定義の関数を呼び出します。描画ルーチンはこ
こに記述してください。
9.
PDFページを終了する旨の合図を送ります。
10. PDFコンテキストを解除します。
11. ページ辞書を解除します。
リンクの追加
PDFコンテキストにはリンクやアンカを追加することができます。そのための関数は3種類あり、いず
れも引数として、PDFグラフィックスコンテキストと、リンクに関する情報を渡します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
157
PDFドキュメントの生成、表示、変換
PDFの中身の保護
●
CGPDFContextSetURLForRect:現在のPDFページ内の矩形をクリックしたときに開かれるURLを
指定します。
●
CGPDFContextSetDestinationForRect:現在のPDFページ内の矩形をクリックしたときに開か
れるジャンプ先を指定します。ジャンプ先の名前を引数として渡します。
●
CGPDFContextAddDestinationAtPoint:現在のPDFページ内の点をクリックしたときに開かれ
るジャンプ先を指定します。ジャンプ先の名前を引数として渡します。
PDFの中身の保護
PDFの中身を保護するためのセキュリティオプションがいくつかあり、いずれも関数
CGPDFContextCreateに渡す補助辞書で指定できます。所有者のパスワード、ユーザのパスワード、
印刷の可否、複写の可否を、次のキーを使って補助辞書に設定できます。
●
kCGPDFContextOwnerPassword:PDFドキュメントの所有者のパスワードを設定。このキーが指
定された場合、パスワードとして指定された値を使ってドキュメントを暗号化します。指定がな
ければ暗号化を施しません。値はCFStringオブジェクトで、ASCIIエンコーディングで表した文字
列とします。パスワードとして有効なのは先頭32バイトだけです。既定値はありません。ASCIIで
表現できる文字以外が使われていた場合、生成関数はドキュメントを生成せず、NULLを返しま
す。Quartzでは40ビットの暗号化を施すようになっています。
●
kCGPDFContextUserPassword:PDFドキュメントのユーザのパスワードを設定。ドキュメントを
暗号化する場合に、この値をユーザのパスワードとして使います。指定がなければ、パスワード
は空文字列であるとします。値はCFStringオブジェクトで、ASCIIエンコーディングで表した文字
列とします。パスワードとして有効なのは先頭32バイトだけです。ASCIIで表現できる文字以外が
使われていた場合、生成関数はドキュメントを生成せず、NULLを返します。
●
kCGPDFContextAllowsPrinting:ユーザパスワードでロックを解除したとき、ドキュメントを
印刷できるかどうかを表します。値はCFBooleanオブジェクトで指定します。既定値は
kCFBooleanTrueです。
●
kCGPDFContextAllowsCopying:ユーザパスワードでロックを解除したとき、ドキュメントを複
写できるかどうかを表します。値はCFBooleanオブジェクトで指定します。既定値はkCFBooleanTrue
です。
リスト 14-4 (163 ページ)(次の章)に、PDFドキュメントがロックされているか調べ、ロックされ
ていればパスワードを要求するコード例を示します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
158
PDFドキュメントの解析
QuartzにはPDFドキュメントの構造やコンテンツストリームを調べるための関数があります。ドキュ
メントカタログのエントリや、それぞれに対応する内容を読み取ることができます。また、カタログ
を再帰的にたどることにより、ドキュメント全体を調査できます。
PDFコンテンツストリームは、名前の通り、'BT 12 /F71 Tf (draw this text) Tj . . . 'のよ
うな連続するストリームで、PDFの演算子や記述子と実際の中身が混在した恰好になっています。コ
ンテンツストリームを調査するためには、これに順次アクセスする必要があります。
この章では、PDFドキュメントの構造を調べ、内容を解析する方法を説明します。
PDFドキュメントの構造の調査
PDFファイルは、画像やテキストで構成される、複数のページから成ります。Quartzには、ドキュメ
ントレベル、ページレベルのメタデータや、PDFページ上のオブジェクトにアクセスする手段が備わっ
ています。この節では、アクセス可能なメタデータを大雑把に紹介します。
PDFドキュメントオブジェクト(CGPDFDocument)には、カタログやコンテンツなど、PDFドキュメ
ントに関する情報がすべて収容されています。カタログのエントリは、PDFドキュメントの内容を再
帰的に記述しています。PDFドキュメントカタログには関数CGPDFDocumentGetCatalogでアクセスし
ます。
PDFページオブジェクト(CGPDFPage)は、PDFドキュメント内の各ページを表し、辞書や内容など、
該当するページに関する情報が収容されています。ページ辞書は関数CGPDFPageGetDictionaryで取
得できます。
図 14-1に、図 13-2 (151 ページ)のPDFに含まれる、2つの画像(テキストと鶏)を記述するメタデー
タの一部を示します。
図 14-1
PDFファイル中の2つの画像を記述するメタデータ
PDFメタデータにアクセスすると、より有用な情報が得られます。図 14-1に示したのはその例に過ぎ
ません。たとえばサムネール画像(図 14-2 (160 ページ)を参照)の有無は、リスト 14-1のコードで
調べることができます。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
159
PDFドキュメントの解析
PDFコンテンツの解析
リスト 14-1 PDFのサムネールビューの取得
CGPDFDictionaryRef d;
CGPDFStreamRef stream; // represents a sequence of bytes
d = CGPDFPageGetDictionary(page);
// check for thumbnail data
if (CGPDFDictionaryGetStream (d, "Thumb", &stream)){
// get the data if it exists
data = CGPDFStreamCopyData (stream, &format);
データストリームの復号とデコードはQuartz側が行います。
図 14-2
サムネール画像
Quartzには各種のPDFメタデータの値を取得する関数がいくつかあります。関数CGPDFObjectGetValue
に、CGPDFObjectRef、PDFオブジェクトの型(kCGPDFObjectTypeBoolean、
kCGPDFObjectTypeIntegerなど)、値を収容して返すストレージを渡して呼び出すと、そのストレー
ジに値を収容した状態で返されます。
PDFファイルの階層をたどってノードやその子孫にアクセスする関数もあります。たとえば、関数
CGPDFArray(あるいはCGPDFArrayGetBoolean、CGPDFArrayGetDictionary、CGPDFArrayGetInteger
など)で、所定の型の値を検索し、配列の形で取得することができます。各関数の使い方について詳
しくは、PDFの仕様も参照してください。
PDFコンテンツの解析
PDFコンテンツストリームには、アプリケーションが必要とするデータを見つけるための目印となる、
「演算子」と呼ばれる記号があります。ストリーム中のある一点を指す演算子と、シーケンスを指す
演算子があります。演算子はタグの形で指定され、プロパティリストまたはオブジェクトが付随しま
す。タグは、その一点やシーケンスが何を表すか、を示すものです。プロパティリストは、PDF作成
者が指定したキーと値の組を収容する辞書です。PDFコンテンツストリームを解析するアプリケーショ
ンは、必要とするマーカを見つけ、対応するタグやプロパティリスト、オブジェクトを調べて、それ
ぞれに応じた処理を行います。PDFの演算子について詳しくは、『PDF Reference 』を参照してくださ
い。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
160
PDFドキュメントの解析
PDFコンテンツの解析
PDFコンテンツストリームの解析には、CGPDFScannerオブジェクト(CGPDFScannerRefデータ型)を
使います。このオブジェクトに、演算子とコールバック関数の組をあらかじめ登録しておきます。ス
トリームを走査して、登録された演算子が見つかると、対応するコールバック関数を起動するように
なっています。
コンテンツストリームを解析する手順を、次の各節に分けて説明します。
1.
“演算子を処理するコールバック関数の記述” (162 ページ)。コールバック関数は、必要とする
演算子について記述するだけで構いません。
2.
“演算子表の生成と設定” (162 ページ)。
3.
“PDFドキュメントのオープン” (163 ページ)。
4.
“各ページのコンテンツストリームの走査” (164 ページ)。
コードの書き方にもよりますが、用済み後は、スキャナ、コンテンツストリーム、演算子表を解除す
る必要があります。
以下の各節では、コンテンツストリームを解析し、マーク付きコンテンツ演算子(表 14-1を参照)を
見つける方法を説明します。マーク付きコンテンツ演算子は、PDFコンテンツ内に含まれるPDF演算
子の一部に過ぎません。用途によっては、それ以外のPDF演算子も必要になるでしょう。
表 14-1
マーク付きコンテンツ演算子(PDF演算子のうち解析可能なもの)
演算子
解説
MP
マーク付きポイントで、タグが関連づけられているもの。
DP
マーク付きポイントで、タグとプロパティリストまたはオブジェクトが関連づけら
れているもの。
BMC
マーク付きコンテンツシーケンスの開始点(Begin Marked Content)。終了点を表す
EMCマーカと対にして使います。タグが関連づけられています。
BDC
マーク付きコンテンツシーケンスの開始点。終了点を表すEMCマーカと対にして使い
ます。タグと、プロパティリストまたはオブジェクトが関連づけられています。
EMC
マーク付きコンテンツシーケンスの終了点(End Marked Content)。開始点を表すBMC
またはBDCと対にして使います。この演算子には、関連づけられたタグがありませ
ん。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
161
PDFドキュメントの解析
PDFコンテンツの解析
演算子を処理するコールバック関数の記述
Quartzは、所定のPDF演算子が見つかると、対応するコールバック関数を起動します。CGPDFScanner
オブジェクトと、コールバック関数の処理に必要なデータを指すポインタを、引数として渡すように
なっています。コールバック関数は通常、演算子に関連する情報を検索し、必要な処理を行います。
例として、MP演算子を処理するコールバック関数をリスト 14-2に示します。関数CGPDFScannerPopName
で、演算子に関連づけられた文字列をスタックから取り出し、印字するようになっています。
Quartzには、オブジェクト、ブール値、名前、数値、文字列、配列、辞書、ストリームのそれぞれに
ついて、値を検索する一連のCGPDFScannerPop関数群があります。いずれも、見つかったかどうかを
ブール値で返すようになっています。
リスト 14-2 MP演算子を処理するコールバック関数
static void
op_MP (CGPDFScannerRef s, void *info)
{
const char *name;
if (!CGPDFScannerPopName(s, &name))
return;
printf("MP /%s\n", name);
}
演算子表の生成と設定
PDF演算子を処理するコールバック関数は、あらかじめ演算子表(CGPDFOperatorTableオブジェク
ト)に登録しておきます。演算子表の生成には関数CGPDFOperatorTableCreateを使います(リスト
14-3を参照)。この演算子表に、関数CGPDFOperatorTableSetCallbackで、演算子とコールバック
関数の組を登録します。引数として、演算子表、PDF演算子を指定する文字列、対応するコールバッ
ク関数のポインタを渡します。コールバック関数の名前はどのように決めても構いません。関数
CGPDFOperatorTableSetCallbackに間違った関数名を渡さないことだけ注意してください。
リスト 14-3に、表 14-1 (161 ページ)のマーク付きコンテンツ演算子それぞれについて、コールバッ
ク関数を登録するコード例を示します。用途に応じて、実際に必要な演算子のみ登録してください。
PDF演算子の定義は、Adobeが公開している『PDF Reference 』に載っています。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
162
PDFドキュメントの解析
PDFコンテンツの解析
リスト 14-3 演算子表にコールバック関数を設定
CGPDFOperatorTableRef myTable;
myTable = CGPDFOperatorTableCreate();
CGPDFOperatorTableSetCallback (myTable, "MP", &op_MP);
CGPDFOperatorTableSetCallback (myTable, "DP", &op_DP);
CGPDFOperatorTableSetCallback (myTable, "BMC", &op_BMC);
CGPDFOperatorTableSetCallback (myTable, "BDC", &op_BDC);
CGPDFOperatorTableSetCallback (myTable, "EMC", &op_EMC);
PDFドキュメントのオープン
PDFドキュメントの内容を走査するためには、まずこれをオープンする必要があります。リスト 14-4
に、別途指定されたURLに基づき、CGPDFDocumentオブジェクトを生成するコード例を示します。要
点を抜き書きしたものなので、変数宣言は一部しか示してありません。コード例を示した後、番号が
ついている行について詳しく説明します。
リスト 14-4 URLに基づいてPDFドキュメントをオープン
CGPDFDocumentRef myDocument;
myDocument = CGPDFDocumentCreateWithURL(url);
// 1
if (myDocument == NULL) {
// 2
error ("can't open `%s'.", filename);
CFRelease (url);
return EXIT_FAILURE;
}
CFRelease (url);
if (CGPDFDocumentIsEncrypted (myDocument)) {
if (!CGPDFDocumentUnlockWithPassword (myDocument, "")) {
printf ("Enter password: ");
fflush (stdout);
password = fgets(buffer, sizeof(buffer), stdin);
if (password != NULL) {
buffer[strlen(buffer) - 1] = '\0';
if (!CGPDFDocumentUnlockWithPassword (myDocument, password))
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
163
// 3
PDFドキュメントの解析
PDFコンテンツの解析
error("invalid password.");
}
}
}
if (!CGPDFDocumentIsUnlocked (myDocument)) {
// 4
error("can't unlock `%s'.", filename);
CGPDFDocumentRelease(myDocument);
return EXIT_FAILURE;
}
}
if (CGPDFDocumentGetNumberOfPages(myDocument) == 0) {
// 5
CGPDFDocumentRelease(myDocument);
return EXIT_FAILURE;
}
このコードが実行することを以下に示します。
1.
指定されたURLに基づき、CGPDFDocumentオブジェクトを生成します。
2.
CGPDFDocumentオブジェクトが正常に生成されたかどうか確認します。失敗の場合、処理を続け
る意味はないので終了します。
3.
ドキュメントが暗号化されているかどうか調べます。暗号化されていれば、空文字列のパスワー
ドで開けないか試みます。それにも失敗した場合、パスワードを入力するようユーザに求め、
ロック解除を試みます。
4.
ロック解除済みかどうか調べます。ロックがかかっている場合は処理を終了します。
5.
ドキュメントが少なくとも1ページあるかどうか調べます。ない場合は処理を終了します。
各ページのコンテンツストリームの走査
リスト 14-5に、ドキュメントの各ページを走査するコード例を示します。演算子表に登録されている
PDF演算子が見つかる都度、対応するコールバック関数を起動するようになっています。コード例を
示した後、番号がついている行について詳しく説明します。
リスト 14-5 ドキュメントの各ページの走査
int k;
CGPDFPageRef myPage;
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
164
PDFドキュメントの解析
PDFコンテンツの解析
CGPDFScannerRef myScanner;
CGPDFContentStreamRef myContentStream;
numOfPages = CGPDFDocumentGetNumberOfPages (myDocument);
// 1
for (k = 0; k < numOfPages; k++) {
myPage = CGPDFDocumentGetPage (myDocument, k + 1 );
// 2
myContentStream = CGPDFContentStreamCreateWithPage (myPage);
// 3
myScanner = CGPDFScannerCreate (myContentStream, myTable, NULL);
// 4
CGPDFScannerScan (myScanner);
// 5
CGPDFPageRelease (myPage);
// 6
CGPDFScannerRelease (myScanner);
// 7
CGPDFContentStreamRelease (myContentStream);
// 8
}
CGPDFOperatorTableRelease(myTable);
// 9
このコードが実行することを以下に示します。
1.
オープンしたドキュメントのページ数を調べます。“PDFドキュメントのオープン” (163 ページ)
を参照してください。
2.
走査するページを探します。ページ番号は1から数えます。
3.
当該ページのコンテンツストリームを生成します。
4.
コンテンツストリームを走査するスキャナを生成します。コンテンツストリームと演算子表(先
に生成し、コールバック関数を登録したもの)を渡します。“演算子表の生成と設定” (162 ペー
ジ)を参照してください。コールバック関数との受け渡しが必要なデータがあればここで渡しま
す。
5.
スキャナでコンテンツストリームを解析します。登録済みの演算子が見つかる都度、対応する
コールバック関数が起動されます。
6.
ページを解除します。
7.
スキャナを解除します。
8.
コンテンツストリームを解除します。
9.
PDFの全ページの処理が終わったら、演算子表を解除します。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
165
PostScript変換
Previewアプリケーションは自動的にPostScriptファイルをPDFに変換します。Quartz 2D APIにも、これ
と同じように、PostScriptの変換機能をアプリケーションに組み込むための関数が用意されています。
ただしiOSでは利用できません。
PostScriptドキュメントをPDFドキュメントに変換する手順を以下に示します。
1.
コールバック関数を記述します。Quartzはページの処理状況を、コールバック関数で通知するよ
うになっています。
2.
コールバック構造体に、必要な情報を設定します。
3.
PostScript変換器オブジェクトを生成します。
4.
変換元PostScriptファイルに対応した、データプロバイダオブジェクトを生成します。
5.
変換先PDFに対応した、データコンシューマオブジェクトを生成します。
6.
変換を実行します。
以上の各手順について、以下の各節で説明します。
コールバック関数の記述
変換処理の進捗状況をアプリケーション側に伝えるために、Quartzはコールバック関数を使うように
なっています。何らかのユーザインターフェイスを備えたアプリケーションの場合、これを利用して
ユーザに状況を伝えることができます(図 15-1を参照)。
図 15-1
PostScript変換アプリケーションの進捗状況表示
次の状況で呼び出されるコールバック関数を登録できます。
●
●
変換処理の開始(CGPSConverterBeginDocumentCallback)。コールバック関数には、データ
受け渡し用の汎用ポインタが渡されます。
変換処理の終了(CGPSConverterEndDocumentCallback)。コールバック関数には、データ受
け渡し用の汎用ポインタと、処理成功(true)または失敗(false)を表すブール値が渡されま
す。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
166
PostScript変換
コールバック構造体の値設定
●
●
●
●
ページの開始(CGPSConverterBeginPageCallback)。コールバック関数には、データ受け渡し
用の汎用ポインタと、ページ番号、CFDictionaryオブジェクト(現在は未使用)が渡されます。
ページの終了(CGPSConverterEndPageCallback)。コールバック関数には、データ受け渡し用
の汎用ポインタと、処理成功(true)または失敗(false)を表すブール値が渡されます。
変換処理の進捗(CGPSConverterProgressCallback)。これは変換処理中、定期的に起動され
ます。コールバック関数には、データ受け渡し用の汎用ポインタが渡されます。
処理に関するメッセージの送信(CGPSConverterMessageCallback)。変換処理中に送信できる
メッセージにはいくつか種類があります。よく使われるものとして、フォント代替メッセージ
や、PostScriptのコード自身が生成するメッセージがあります。stdoutに書き出されるPostScript
メッセージを、このコールバック関数に回送するようになっており、デバッグ用や状態メッセー
ジとして使えます。ドキュメントの構文が正しくない旨のエラーメッセージも同様です。
コールバック関数には、データ受け渡し用の汎用ポインタと、メッセージを収容するCFStringオ
ブジェクトが渡されます。
●
PostScript変換器オブジェクトの割り当て解除(CGPSConverterReleaseInfoCallback)。この
コールバック関数を利用して、データ受け渡し用の汎用ポインタを解放するなど、後始末を行う
ことができます。コールバック関数には、データ受け渡し用の汎用ポインタが渡されます。
各コールバック関数の仕様(引数並び)については、『CGPSConverter Reference 』を参照してくださ
い。
コールバック構造体の値設定
版番号と、先に実装したコールバック関数を、CGPSConverterCallbacksデータ構造体の該当する
フィールドに設定します(リスト 15-1を参照)。版番号は0とします。コールバック関数が必要ない
フィールドにはNULLを設定してください。
リスト 15-1 PostScript変換器のコールバック構造体
struct CGPSConverterCallbacks {
unsigned int version;
CGPSConverterBeginDocumentCallback beginDocument;
CGPSConverterEndDocumentCallback endDocument;
CGPSConverterBeginPageCallback beginPage;
CGPSConverterEndPageCallback endPage;
CGPSConverterProgressCallback noteProgress;
CGPSConverterMessageCallback noteMessage;
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
167
PostScript変換
PostScript変換器オブジェクトの生成
CGPSConverterReleaseInfoCallback releaseInfo;
};
PostScript変換器オブジェクトの生成
関数CGPSConverterCreateで、PostScript変換器オブジェクトを生成します。この関数は次の3つの引
数を取ります。
●
データ受け渡し用の汎用ポインタ。必要なければNULLを指定してください。
●
必要な設定をしたCGPSConverterCallbacksデータ構造体を指すポインタ。
●
NULL - この引数は将来のために予約されています。
Important: 関数CGPSConverterConvertはスレッドセーフ(ロック機構を用いて、同じプロセス
で同時に複数の変換処理が動作することを防止)ですが、Resource Managerとの関係ではスレッド
セーフになっていません。アプリケーションが別スレッドでResource Managerを使う場合、その動
作中はCGPSConverterConvertを実行しないようロックするか、PostScript変換器による変換処理
を別プロセスで実行するようにしてください。
データプロバイダおよびデータコンシューマの生成
データプロバイダオブジェクトは、関数CGDataProviderCreateWithURLで生成します。引数とし
て、変換元PostScriptファイルを指すCFURLオブジェクトを指定します。
同様に、データコンシューマオブジェクトは、関数CGDataConsumerCreateWithURLで生成します。
引数として、変換先PDFドキュメントを表すCFURLオブジェクトを渡します。
変換の実行
実際の変換(PostScriptからPDF)は、関数CGPSConverterConvertで実行します。この関数は次の引
数と取ります。
●
PostScript変換器オブジェクト。
●
PostScriptデータを供給するデータプロバイダオブジェクト。
●
変換後のデータを受け取るデータコンシューマオブジェクト。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
168
PostScript変換
変換の実行
●
NULL - この引数は将来のために予約されています。
変換に成功すれば、戻り値はtrueとなります。
関数CGPSConverterIsConvertingで、変換処理中であるかどうかを調べることができます。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
169
テキスト
旧版ではこの章で、Quartzが提供する基本的なテキスト描画機能を説明していました。しかしQuartz
では、この機能が非推奨になりました。代わりにCore Textに、より洗練された形で、テキスト配置や
フォント処理の技術が組み込まれています。Core Textは性能と使いやすさを目標として設計されてお
り、Unicodeテキストを直接グラフィックスコンテキストに描画できます。開発するアプリケーショ
ンが、テキストの表示方法を精密に制御しなければならない場合は、『CoreTextProgrammingGuide 』
を参照してください。
テキスト処理を行うiOS用アプリケーションを開発する際は、テキスト処理機能について説明した
『Text Programming Guide for iOS 』をまず読むとよいでしょう。特にUIKitには、一般的な処理を実装し
た次のようなクラスが組み込まれているので、テキスト処理をアプリケーションに容易に実装できま
す。
テキスト処理を行うMac OS X用アプリケーションを開発する際は、Cocoaのテキスト処理について説
明した『Cocoa Text Architecture Guide 』をまず読むとよいでしょう。Cocoaには、Unicodeの処理、テ
キスト入力および編集、精密なテキスト配置や印字、フォント管理など、高度なテキスト処理機能が
完備しています。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
170
用語解説
アルファ値(alpha value) グラフィックス状
態として管理するパラメータのひとつで、既存
のページに、新たに描画するオブジェクトを、
どのように合成するかを表します。強度が最大
(アルファ値 = 1.0)ならば、新たに描画する
オブジェクトは不透明です。強度が0(アルファ
値 = 0.0)ならば、新たに描画するオブジェク
トは不可視です。
現在のグラフィックス状態(current graphics
state) Quartzによる描画方法を決めるパラメー
タ値。
現在点(current point) パスを描画して現在到
達した位置。
現在の変換行列(current transformation
matrix) ある座標系から別の座標系に、点を
写像するために用いるアフィン変換。
軸状グラデーション(axial gradient) 指定し
た2つの端点を結ぶ軸に沿って徐々に色が変化
する塗りつぶし。この軸に垂直な直線上の点は
すべて、色値が同じになります。線形グラデー
ション とも言います。
デバイス色空間(device color space) 色空間
のうち、特定のデバイスの色表現に結びついた
もの。デバイス間で色データをやりとりする目
的には向いていません。
デバイス非依存の色空間(device-independent
color space) どのデバイスにも通用するやり
方で色を表現する色空間。あるデバイスに固有
の色空間から、別のデバイスのそれに、色デー
タを変換するためにも使えます。この色空間で
表した色は、各デバイスの能力の範囲内で、ど
のデバイスにも同じように再現できます。
ビットマップ(bitmap) ピクセルを矩形に並
べた配列(あるいはラスタ)のことで、各ピク
セルは、画像のある特定の点を表します。標本
化(サンプリング)された画像 とも言います。
ブレンドモード(blend mode) 背景色の上に、
新しい色をどのように混ぜ合わせるか、を表し
ます。
「偶奇」巻数規則(even-odd rule) あるピク
セルを塗りつぶすかどうか決める規則のひと
つ。パスの向きは結果に影響を与えません。
「非ゼロ」巻数規則(nonzero winding number
rule)と比較してください。
クリッピング領域(clipping area) 他のオブ
ジェクトを描画する際、所定の範囲内に制限す
るために用いるパス。
色空間(color space) 各成分(チャネル)が
強度を表す1~4次元の環境。たとえばRGB空間
は3次元の色空間で、各成分は、色を構成する
赤、緑、青の強度を表します。
塗りつぶし(fill) パスで囲まれた領域に色を
塗る操作。
標準色空間(generic color space) Mac OS Xが
描画先に合わせて自動的に選択するデバイス非
依存色空間。
結合(concatenation) 2つの行列を掛け合わせ
る演算。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
171
用語解説
グラデーション(gradient) ある色から別の色
に、徐々に変化するように塗りつぶすこと。軸
状グラデーション(axial gradient)、放射状グ
ラデーションも参照。
線形グラデーション 「軸状グラデーション
(axial gradient)」を参照。
「非ゼロ」巻数規則(nonzero winding number
rule) あるピクセルを塗りつぶすかどうか決め
る規則のひとつ。パスの向きが結果に影響を与
えます。「偶奇」巻数規則(even-odd rule)と
比較してください。
グラフィックスコンテキスト(graphics
context) 不透過データ型のひとつ
(CGContextRef)で、画像を出力デバイス
(PDFファイル、ビットマップ、ディスプレイ
上のウインドウなど)に描画するために必要な
情報をカプセル化するものです。グラフィック
ス描画パラメータと、ページ上に描画した内容
をデバイス特有の形で表現したデータを保持し
ています。
ページ(page) Quartzが描画の対象とする仮
想的なキャンバス。
ペインターモデル(painter's model) 一連の
描画操作は、描画したいもの(ペイント)のレ
イヤをページ(page)に重ねていく処理に対応
する、という描画モデル。
恒等変換(identity transform) アフィン変換
のうち、常に入力座標と同じ値を返すもの。
パス(path) Quartzがひとつの単位として描
画する図形を定めるもの。図形はいくつかの部
分(サブパス)に分かれていても構いません。
サブパスは、直線や曲線、あるいはその両方を
組み合わせて作ることができます。また、開い
たパス、閉じたパスという区別もあります。
画像マスク(image mask) (色そのものでは
なく)色を塗る領域を指定するために使うビッ
トマップ。ステンシル(型紙)のように、色を
乗せる場所を指定する働きがあります。
逆行列(inversion) 変換後の座標から元の座
標を求める演算。
パターン(pattern) グラフィックスコンテキ
ストに反復して描画できる、一連の描画操作。
レイヤコンテキスト(layer context) 描画性能
を向上するために用いる、オフスクリーンの描
画先(CGLayerRef)。オフスクリーン描画には
ビットマップグラフィックスコンテキストより
も向いています。
パターン空間 パターンを生成する際に指定し
た変換行列(パターン行列)によって既定の
ユーザ空間を変換した、抽象的な座標空間。パ
ターン空間は、ユーザ空間とは独立です。変換
を施す前のパターン空間が、現在の変換行列の
状態にかかわらず、基盤となる(変換を施す前
の)ユーザ空間にマップされます。
線端形状(line cap) 線の端点を描画する方
法。先太型、丸型、突出型があります。
アルファ値乗算済み(premultiplied alpha) 色
成分の値にあらかじめアルファ値を掛けてある
こと。色成分ごとの積演算が不要になるので、
描画速度を改善できます。「アルファ値(alpha
value)」も参照。
線種(line dash pattern) 線分と空間を交互に
並べて作る破線のパターン。
角の形状(line join) 線分のつなぎ目の接続方
法。尖頭型、角丸型、平頭型があります。
線幅(line width) 線の幅(太さ)をユーザ空
間の単位で表したもの。
放射状グラデーション 指定した2つの終端(一
般にどちらも円)を結ぶ軸に沿って、放射状に
色が変化する塗りつぶし。この軸上の点を中心
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
172
用語解説
とする円周上の点はすべて、色値が同じになり
ます。グラデーションの円断面の半径は、終端
の円の半径として定義されます。その間の各円
は、一方の終端から他方の終端に向かって、半
径が線形に変化します。
レンダリングインテント(rendering intent)
色空間を写像する際、写像先の色空間で再現で
きない色の処理方法。
回転 座標空間を所定の角度だけ回転する演算。
拡大縮小 x座標とy座標にそれぞれ、指定した
値を掛けることにより、画像を拡大または縮小
する演算。掛け合わせる値が1より大きいか小
さいかによって、画像が拡大されるか縮小され
るかが決まります。負の値を掛ければ、軸に
沿って座標が反転します。
影(shadow) グラフィックスオブジェクトの
奥に、若干位置をずらして描画する画像。光を
当てた効果を真似ることができます。
線つけ パスに沿った線を描画する操作。
タイリング ページのある部分にパターンセル
を描画する処理。タイリングの方法として、歪
みなし方式、一定間隔(最小限の歪み)方式、
一定間隔方式の3つがあります。
平行移動(translation) x軸方向とy軸方向の移
動量を指定し、座標空間の原点を移動する演
算。
透明レイヤ(transparency layer) 複数のオブ
ジェクトを合成し、1つのオブジェクトとして
扱えるようにしたもの。影などの効果を適用す
る場合に有用です。
ユーザ空間(user space) Quartz 2Dで描画する
際に使う、デバイス非依存の座標空間。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
173
書類の改訂履歴
この表は「Quartz 2Dプログラミングガイド 」の改訂履歴です。
日付
メモ
2014-09-17
vImageを使って生のピクセルデータを操作できる旨の情報を追加し
ました。
2013-12-16
テキストに関する章を削除しました。代わりにCore Textを使うよう
になっています。
2012-09-19
誤字や細かい技術的問題を修正しました。
2010-11-19
OS X v10.6およびiOS 4.2に合わせて更新しました。
2010-06-25
わかりにくい箇所を明確にし、細かい編集を行いました。
2009-05-18
例に出てくるフォント名を、iOSと OS Xのどちらでも使えるものに
しました。
2008-06-04
iOS SDKに合わせて更新しました。
画像形式に関する情報を“ビットマップ画像に関する情報” (123 ペー
ジ) に加筆しました。
誤字を訂正しました。
2007-12-11
「テキスト」の章を改訂し、用語解説を追加しました。
辞書を生成しメタデータを追加するコードを追加しました。リスト
13-4 (155 ページ) を参照してください。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
174
書類の改訂履歴
日付
メモ
2007-07-02
OS X 10.5用に更新しました。
「シェーディング」の章を「グラデーション」と改め、不透過デー
タ型CGGradientRef の使い方を加筆しました。
“Quartz 2Dにおけるデータ管理” (116 ページ) に『Image I/O
Programming Guide 』に関するリンクと情報を追加しました。
最新の関係ドキュメントを載せ、加筆した“グラデーショ
ン” (92 ページ) の内容に合わせて「はじめに」も書き直しまし
た。
“Quartz 2Dの不透過データ型” (18 ページ) にCGGradientRef の説
明を加筆し、Image I/Oフレームワークの一部である不透過データ型
CGImageSourceRef およびCGImageDestinationRef に関する説明
のリンクを載せました。
表 2-1 (36 ページ) にピクセル形式を追加して改訂しました。
2007-01-08
技術的な細かい問題点を修正しました。
“グラデーション” (92 ページ) の第1段落の言い回しを改善しま
した。
表 2-1 (36 ページ) で、浮動小数点数で表すグレースケール色空
間の説明を修正しました。
リスト 14-5 (164 ページ) の宣言を修正しました。
2006-10-03
技術的な細かい改善を行いました。
表 2-1 (36 ページ) に示した定数のリファレンスドキュメントに、
クロスリファレンスを追加しました。
CGGLContextRef オブジェクトの使い方の説明を削除しました。
OpenGLのレンダリングにグラフィックスコンテキストを使う方法
は、信頼性が低く、お勧めできないからです。
“PostScript変換器オブジェクトの生成” (168 ページ) にスレッド
セーフに関する説明を加筆しました。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
175
書類の改訂履歴
日付
メモ
2006-07-24
技術的な細かい改善を行いました。
リスト 2-6 (35 ページ) を改訂し、ビットマップデータを正しく
解放するようにしました。
“画像の一部を切り抜いて新しい画像を生成” (127 ページ) および
“ビットマップグラフィックスコンテキストから画像を生
成” (128 ページ) から、グラフィックスコンテキストを生成する
コード例を参照できるようにしました。
2006-06-28
概念を明確に説明するため、細かい変更を行いました。
図 12-2 (142 ページ) およびこれを説明する記述を改訂しました。
図 1-2 (17 ページ) およびこれを説明する記述を改訂しました。
「Quartz 2Dの機能を呼び出すPythonのバインディング」の内容を改
訂しました。
“Quartz 2Dにおけるデータ管理” (116 ページ) の関数やメソッドに
ハイパーリンクを追加しました。
リスト 2-2 (27 ページ) の誤字を訂正しました。
2006-02-07
誤字を訂正しました。
2006-01-10
誤字を訂正し、技術的な細かい修正を行いました。
2005-11-09
技術的な誤り、誤字、不適切な書式をいくつか修正しました。
リスト 12-1 (146 ページ) のコードを変更しました。
“座標変換” (63 ページ) の導入部分を書き直しました。
“Quartz 2Dのテキスト描画方式” (? ページ) のいくつかの段落を
改訂しました。
2005-07-07
Quartz OpenGLグラフィックスコンテキストに関する誤字を訂正し、
わかりにくい箇所を明確にしました。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
176
書類の改訂履歴
日付
メモ
2005-06-04
誤字を訂正し、Pythonのスクリプト名を追加しました。
2005-04-29
OS X 10.4用に更新しました。
同様のドキュメント名に合わせて『Drawing With Quartz 2D 』から
ドキュメント名を変更しました。
新たに加わった内容に合わせて「はじめに」を書き直しました。
図 3-1 (39 ページ) のコードを簡潔にしました。
“色と色空間” (56 ページ) 、“座標変換” (63 ページ) 、“ビット
マップ画像と画像マスク” (122 ページ) 、“PDFドキュメントの解
析” (159 ページ) の導入部分を書き直しました。
“レイヤを利用して旗を描画するコード” (146 ページ) のコードを
変更して、より適切な大きさのレイヤを使うようにしました。ま
た、関数CGContextDrawLayerInRect の代わりに、
CGContextDrawLayerAtPoint を使うようにしました。
“ブレンドモードの設定” (49 ページ) の節を改訂し、各ブレンド
モードによる実際の出力を載せました。
“画像にブレンドモードを適用” (134 ページ) の節を改訂し、各ブ
レンドモードで描画した画像を、より適切な例に変更しました。
“Quartz 2Dの概要” (16 ページ) の冒頭に、Core ImageおよびCore
Videoに関する情報を加筆しました。
“描画先:グラフィックスコンテキスト” (17 ページ) にCGLayerオ
ブジェクトの説明を追加しました。
“Quartz 2Dの不透過データ型” (18 ページ) に虎の不透明オブジェ
クトを追加しました。
ブレンドモードの説明を“グラフィックス状態” (20 ページ) に追
加しました。ブレンドモードの使い方に関する説明を、“パ
ス” (39 ページ) および“ビットマップ画像と画像マスク” (122 ペー
ジ) に追加しました。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
177
書類の改訂履歴
日付
メモ
“グラフィックスコンテキスト” (24 ページ) をHIViewの使い方を
追加して書き直しました。また、多くの節に図を追加し、HIViewの
座標系について、Quartzの座標系と比較する形で説明を加えまし
た。
表 2-1 (36 ページ) を追加して、取り扱い可能な色空間やピクセ
ル形式を示しました。
ぎざぎざの有無がわかりやすいよう、図 2-4 (38 ページ) を大き
な図に差し替えました。
“楕円” (43 ページ) を追加し、虎の図を追加したのに合わせて、
“パスの描画” (45 ページ) 、“パスを用いたクリッピング処
理” (54 ページ) の説明を書き直しました。
全体を通して「クリッピング領域」の表記を変えました(英語版の
場合)。
虎の図に合わせて“色空間の生成” (58 ページ) の記述を書き直し
ました。
“アフィン変換の評価” (68 ページ) 、“ユーザ空間からデバイス空
間への変換の取得” (68 ページ) を加筆しました。
『Data Providers and Data Consumers 』となっていた章見出しを変更
し、画像ソースと画像デスティネーションの説明、Quartz 2DとCore
Imageの間のデータ移動に関する説明を追加しました。内容の改訂
に合わせて、章の見出しを“Quartz 2Dにおけるデータ管理” (116 ペー
ジ) と変更しました。
「ビットマップ画像」となっていた章見出しを“ビットマップ画像
と画像マスク” (122 ページ) と変更し、画像ソース、新しい画像
生成関数、画像マスク関数、ブレンドモードを利用した画像合成に
関する説明を追加し、大幅に改訂しました。
新しい章“Core Graphicsのレイヤ描画” (141 ページ) を加えました。
新しい章“PDFドキュメントの解析” (159 ページ) を加え、以前PDF
ドキュメントに関する章に記載していた事項と、スキャナやコンテ
ンツストリームに関する説明を載せました。
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
178
書類の改訂履歴
日付
メモ
“フォントバリエーションの複製” (? ページ) 、“PostScriptフォ
ント” (? ページ) の節を「テキスト」の章に追加しました。
2004-06-28
Mac OS X 10.3用に更新しました。
2001-07-01
初版
2014-09-17 | Copyright © 2001, 2014 Apple Inc. All Rights Reserved.
179
Apple Inc.
Copyright © 2001, 2014 Apple Inc.
All rights reserved.
本書の一部あるいは全部を Apple Inc. から書
面による事前の許諾を得ることなく複写複製
(コピー)することを禁じます。また、製品
に付属のソフトウェアは同梱のソフトウェア
使用許諾契約書に記載の条件のもとでお使い
ください。書類を個人で使用する場合に限り
1 台のコンピュータに保管すること、またそ
の書類にアップルの著作権表示が含まれる限
り、個人的な利用を目的に書類を複製するこ
とを認めます。
Apple ロゴは、米国その他の国で登録された
Apple Inc. の商標です。
キーボードから入力可能な Apple ロゴについ
ても、これを Apple Inc. からの書面による事
前の許諾なしに商業的な目的で使用すると、
連邦および州の商標法および不正競争防止法
違反となる場合があります。
本書に記載されているテクノロジーに関して
は、明示または黙示を問わず、使用を許諾し
ません。 本書に記載されているテクノロジー
に関するすべての知的財産権は、Apple Inc.
が保有しています。 本書は、Apple ブランド
のコンピュータ用のアプリケーション開発に
使用を限定します。
本書には正確な情報を記載するように努めま
した。 ただし、誤植や制作上の誤記がないこ
とを保証するものではありません。
Apple Inc.
1 Infinite Loop
Cupertino, CA 95014
U.S.A.
Apple Japan
〒106-6140 東京都港区六本木
6丁目10番1号 六本木ヒルズ
http://www.apple.com/jp
Offline copy. Trademarks go here.
Apple Inc. は本書の内容を確認しておりますが、本
書に関して、明示的であるか黙示的であるかを問わ
ず、その品質、正確さ、市場性、または特定の目的
に対する適合性に関して何らかの保証または表明を
行うものではありません。その結果、本書は「現状
有姿のまま」提供され、本書の品質または正確さに
関連して発生するすべての損害は、購入者であるお
客様が負うものとします。
いかなる場合も、Apple Inc. は、本書の内容に含ま
れる瑕疵または不正確さによって生じる直接的、間
接的、特殊的、偶発的、または結果的損害に対する
賠償請求には一切応じません。そのような損害の可
能性があらかじめ指摘されている場合においても同
様です。
上記の損害に対する保証および救済は、口頭や書面
によるか、または明示的や黙示的であるかを問わ
ず、唯一のものであり、その他一切の保証にかわる
ものです。 Apple Inc. の販売店、代理店、または従
業員には、この保証に関する規定に何らかの変更、
拡張、または追加を加える権限は与えられていませ
ん。
一部の国や地域では、黙示あるいは偶発的または結
果的損害に対する賠償の免責または制限が認められ
ていないため、上記の制限や免責がお客様に適用さ
れない場合があります。 この保証はお客様に特定
の法的権利を与え、地域によってはその他の権利が
お客様に与えられる場合もあります。