Xamarin.iOS のワイド カラー
この記事では、ワイド カラーと、Xamarin.iOS または Xamarin.Mac アプリでの使用方法について説明します。
iOS 10 と macOS Sierra では、Core Graphics、Core Image、Metal、AVFoundation などのフレームワークを含め、システム全体で、拡張範囲のピクセル形式と広色域の色空間のサポートを強化しました。 グラフィックス スタック全体にこの動作が提供されているので、ワイド カラー ディスプレイを備えたデバイスのサポートがさらに容易になります。
資産カタログ
Asset Catalog でのワイド カラーのサポート
iOS 10 と macOS Sierra で、Apple は、アプリのバンドルに静的な画像コンテンツを含めて分類するために使用される Asset Catalog を拡張し、ワイド カラーをサポートしています。
Asset Catalog を使用すると、アプリに次の利点があります。
- 静的画像アセットに最適なデプロイ オプションを提供します。
- 自動色補正をサポートします。
- ピクセル形式の自動最適化をサポートします。
- App Slicing と App Thinning がサポートされています。これにより、関連するコンテンツのみがエンド ユーザーのデバイスに配布されます。
Apple は、ワイド カラーのサポートのために、Asset Catalog に対して次の機能強化を行いました。
- 16 ビット (カラー チャネルごと) のソース コンテンツをサポートします。
- 表示色域によるコンテンツのカタログ化をサポートします。 コンテンツには、sRGB または Display P3 の色域のタグを付けることができます。
開発者には、アプリでワイド カラーのコンテンツをサポートするための 3 つのオプションがあります。
- なにもしない - ワイド カラーのコンテンツは、アプリで鮮やかな色を表示する必要がある場合 (ユーザーのエクスペリエンスを強化する場合) にのみ使用する必要があるため、この要件以外のコンテンツはそのままにしておく必要があります。 これは、すべてのハードウェア状況で引き続き正しくレンダリングされます。
- 既存のコンテンツを Display P3 にアップグレードする - 開発者は Asset Catalog 内の既存の画像コンテンツを P3 形式の新しいアップグレードされたファイルに置き換え、アセット エディターでそのようにタグ付けする必要があります。 ビルド時に、これらのアセットから sRGB 派生画像が生成されます。
- 最適化されたアセット コンテンツを提供する - この状況では、開発者は Asset Catalog 内の各画像の 8 ビット sRGB と 16 ビット Display P3 ビジョンの両方を提供します (アセット エディターで適切にタグ付けされます)。
Asset Catalog の展開
ワイド カラーの画像コンテンツが含まれる Asset Catalog を使用して、開発者が App Store にアプリを提出すると、次のことが発生します。
- アプリがエンド ユーザーに展開されると、App Slicing によって、適切なコンテンツ バリアントのみがユーザーのデバイスに配信されるようになります。
- ワイド カラーをサポートしていないデバイスでは、ワイド カラー コンテンツを含めるペイロード コストは発生しません。これはデバイスに配布されないためです。
- macOS Sierra (以降) の
NSImage
では、ハードウェアの表示に最適なコンテンツ表現が自動的に選択されます。 - 表示されるコンテンツは、デバイスのハードウェア表示特性が変更された場合、自動的に更新されます。
Asset Catalog ストレージ
Asset Catalog ストレージには、アプリに対して次の特性と影響があります。
- ビルド時に、Apple は高品質の画像変換を使用して画像コンテンツのストレージの最適化を試みます。
- ワイド カラー コンテンツでは、カラー チャネルごとに 16 ビットが使用されます。
- コンテンツ依存の画像圧縮は、成果物のコンテンツ サイズを小さくするために使用されます。 コンテンツ サイズをさらに最適化するために、新しい "非可逆" 圧縮が追加されました。
アプリでのオフスクリーン画像のレンダリング
作成するアプリの種類に基づいて、ユーザーがインターネットから収集した画像コンテンツを含めたり、アプリ内に直接画像コンテンツを作成したりすることができます (たとえば、ベクター描画アプリなど)。
どちらの場合も、アプリは iOS と macOS の両方に追加された強化機能を使用して、必要なオフスクリーン画像をワイド カラーでレンダリングできます。
iOS でのワイド カラーの描画
iOS 10 でワイド カラー画像を正しく描画する方法について説明する前に、次の一般的な iOS 描画コードを見てください。
public UIImage DrawWideColorImage ()
{
var size = new CGSize (250, 250);
UIGraphics.BeginImageContext (size);
...
UIGraphics.EndImageContext ();
return image = UIGraphics.GetImageFromCurrentImageContext ();
}
標準コードには、ワイド カラー画像を描画するために使用する前に対処する必要のある問題があります。 iOS 画像描画の開始に使用される UIGraphics.BeginImageContext (size)
メソッドには、次の制限があります。
- カラー チャネルあたり 8 ビットを超える画像コンテキストを作成することはできません。
- 拡張範囲 sRGB 色空間の色を表すことはできません。
- 低レベルの C ルーチンがバックグラウンドで呼び出されるため、sRGB 以外の色空間にコンテキストを作成するインターフェイスを提供する機能はありません。
これらの制限に対処し、iOS 10 でワイド カラー画像を描画するには、代わりに次のコードを使用します。
public UIImage DrawWideColorImage ()
{
var size = new CGSize (250, 250);
var render = new UIGraphicsImageRenderer (size);
var image = render.CreateImage ((UIGraphicsImageRendererContext context) => {
var bounds = context.Format.Bounds;
CGRect slice;
CGRect remainder;
bounds.Divide (bounds.Width / 2, CGRectEdge.MinXEdge, out slice, out remainder);
var redP3 = UIColor.FromDisplayP3 (1.0F, 0.0F, 0.0F, 1.0F);
redP3.SetColor ();
context.FillRect (slice);
var redRGB = UIColor.Red;
redRGB.SetColor ();
context.FillRect (remainder);
});
// Return results
return image;
}
新しい UIGraphicsImageRenderer
クラスは、拡張範囲 sRGB 色空間を処理できる新しい画像コンテキストを作成し、次の機能を備えています。
- 既定ではフル カラーで管理されています。
- 既定では、拡張範囲 sRGB 色空間がサポートされています。
- アプリが実行されている iOS デバイスの機能に基づいて、sRGB または拡張範囲 sRGB 色空間のどちらでレンダリングする必要があるかどうかをインテリジェントに決定します。
- 画像コンテキスト (
CGContext
) の有効期間が完全かつ自動的に管理されるため、開発者は開始および終了のコンテキスト コマンドの呼び出しについて心配する必要はありません。 UIGraphics.GetCurrentContext()
メソッドと互換性があります。
ワイド カラー画像を作成するために UIGraphicsImageRenderer
クラスの CreateImage
メソッドが呼び出され、描画先の画像コンテキストを含む完了ハンドラーが渡されます。 描画はすべて、この完了ハンドラー内で次のように行われます。
- この
UIColor.FromDisplayP3
メソッドによって、広色域 Display P3 色空間に完全に飽和した赤の新色が作成され、四角形の前半を描画するために使用されます。 - 四角形の後半は、比較のために通常の sRGB の完全に飽和した赤の色で描画されます。
macOS でのワイド カラーの描画
この NSImage
クラスは、ワイド カラー画像の描画をサポートするために macOS Sierra で拡張されています。 次に例を示します。
var size = CGSize(250,250);
var wideColorImage = new NSImage(size, false, (drawRect) =>{
var rects = drawRect.Divide(drawRect.Size.Width/2,CGRect.MinXEdge);
var color = new NSColor(1.0, 0.0, 0.0, 1.0).Set();
var path = new NSBezierPath(rects.Slice).Fill();
color = new NSColor(1.0, 0.0, 0.0, 1.0).Set();
path = new NSBezierPath(rects.Remainder).Fill();
// Return modified
return true;
});
アプリでのオンスクリーン画像のレンダリング
オンスクリーンにワイド カラー画像をレンダリングするプロセスは、上記の macOS および iOS 用のオフスクリーンのワイド カラー画像を描画するのと同様に動作します。
iOS でのオンスクリーンのレンダリング
アプリが iOS でオンスクリーンにワイド カラーで画像をレンダリングする必要がある場合は、問題の UIView
の Draw
メソッドを通常どおりにオーバーライドします。 次に例を示します。
using System;
using UIKit;
using CoreGraphics;
namespace MonkeyTalk
{
public class MonkeyView : UIView
{
public MonkeyView ()
{
}
public override void Draw (CGRect rect)
{
base.Draw (rect);
// Draw the image to screen
...
}
}
}
iOS 10 が上記の UIGraphicsImageRenderer
クラスを使用して実行するのと同様に、Draw
メソッドの呼び出し時にアプリが実行されている iOS デバイスの機能に基づいて、sRGB または拡張範囲 sRGB 色空間のどちらででレンダリングする必要があるかどうかをインテリジェントに決定します。 また、UIImageView
は、iOS 9.3 以降もカラー管理されています。
UIView
または UIViewController
でレンダリングがどのように行われているかをアプリで知る必要がある場合は、UITraitCollection
クラスの新しい DisplayGamut
プロパティをチェックできます。 この値は、次の UIDisplayGamut
列挙型になります。
- P3
- Srgb
- 指定されていません。
アプリが画像の描画に使用する色空間を制御する場合は、CALayer
の新しい ContentsFormat
プロパティを使用して目的の色空間を指定できます。 この値は、次の CAContentsFormat
列挙型になります。
- Gray8Uint
- Rgba16Float
- Rgba8Uint
macOS でのオンスクリーンのレンダリング
アプリが macOS でオンスクリーンにワイド カラーで画像をレンダリングする必要がある場合は、問題の NSView
の DrawRect
メソッドを通常どおりにオーバーライドします。 次に例を示します。
using System;
using AppKit;
using CoreGraphics;
using CoreAnimation;
namespace MonkeyTalkMac
{
public class MonkeyView : NSView
{
public MonkeyView ()
{
}
public override void DrawRect (CGRect dirtyRect)
{
base.DrawRect (dirtyRect);
// Draw graphics into the view
...
}
}
}
ここでも、DrawRect
メソッドの呼び出し時にアプリが実行されている Mac ハードウェアの機能に基づいて、sRGB または拡張範囲 sRGB 色空間のどちらででレンダリングする必要があるかどうかをインテリジェントに決定します。
アプリが画像の描画に使用する色空間を制御する場合は、NSWindow
クラスの新しい DepthLimit
プロパティを使用して目的の色空間を指定できます。 この値は、次の NSWindowDepth
列挙型になります。
- OneHundredTwentyEightBitRgb
- SixtyfourBitRgb
- TwentyfourBitRgb