15

も含めてUIKitにあればdrawRect、RetinaディスプレイのHD面を自動で扱うというのは本当ですか?ではdrawRect、1024 x 768 ビューの現在のグラフィックス コンテキストは、実際には 2048 x 1536 ピクセルのビットマップ コンテキストであるということですか?

更新:現在のコンテキストを使用して画像を作成し、drawRectそのサイズを印刷すると:

CGContextRef context = UIGraphicsGetCurrentContext();
CGImageRef image = CGBitmapContextCreateImage(context);
NSLog(@"width of context %i", (int) CGImageGetWidth(image));
NSLog(@"height of context %i", (int) CGImageGetHeight(image));

新しい iPad では、ステータス バーを無効にすると、2048 と 1536 が出力され、iPad 2 では 1024 と 768 が表示されます)

1ポイント=4ピクセルを自動で処理してくれる贅沢を、私たちは実際に楽しんでいます。

ただし、を使用するCGBitmapContextCreateと、それらは実際にはポイントではなくピクセルになりますか? (少なくともそのビットマップにデータバッファを提供する場合、バッファのサイズ(バイト数)は明らかに高解像度用ではなく、標準解像度用です。バッファとして渡しNULLたとしても、それがCGBitmapContextCreateバッファを処理します、サイズはおそらくデータ バッファーを渡す場合と同じであり、Retina の解像度ではなく、単なる標準解像度です)。

2048 x 1536 は、iPad 1 と iPad 2、および新しい iPad でいつでも作成できますが、新しい iPad にのみ必要なため、メモリとプロセッサと GPU の電力が浪費されます。

では、そのようなビットマップ コンテキストを作成するために a を使用する必要がif () { } else { }ありますか?また、実際にどのように作成するのでしょうか? そして、CGContextMoveToPointRetina ディスプレイを使用するには、すべてのコードを調整する必要があります。これは、コードにとって非常に厄介な場合があります。(または、ローカル変数を定義して、標準解像度の場合は 1 に設定し、網膜の場合は 2 に設定することもできます。そのため、andは、を使用して描画するときだけではなく、常に になります。)x * 2y * 2x, yscaleFactor[[UIScreen mainScreen] scale]xyx * scaleFactory * scaleFactorxyCGContextMoveToPoint

0.0 のスケールが渡された場合、Retina 用に自動的に作成できるようですUIGraphicsBeginImageContextWithOptionsが、コンテキストを作成して保持する必要がある場合 (および UIViewController の ivar またはプロパティを使用して保持する必要がある場合) は使用できないと思います。 . を使用してリリースしないとUIGraphicsEndImageContext、グラフィックス コンテキスト スタックに残るので、CGBitmapContextCreate代わりに使用する必要があるようです。(それとも、スタックの一番下にとどめて、気にしないようにしますか?)

4

4 に答える 4

41

さらに調査を行った後、次の解決策を見つけました。

を使用する必要がある場合はCGBitmapContextCreate、標準ディスプレイまたは Retina ディスプレイに合わせたサイズと座標系でコンテキストを作成できる 2 つの手順があります。

float scaleFactor = [[UIScreen mainScreen] scale];

CGSize size = CGSizeMake(768, 768);

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

CGContextRef context = CGBitmapContextCreate(NULL, 
                           size.width * scaleFactor, size.height * scaleFactor, 
                           8, size.width * scaleFactor * 4, colorSpace, 
                           kCGImageAlphaPremultipliedFirst);

CGContextScaleCTM(context, scaleFactor, scaleFactor);

サンプルは 768 x 768 のポイント領域を作成するもので、新しい iPad では 1536 x 1536ピクセルになります。iPad 2 では、768 x 768ピクセルです。

重要な要因は、CGContextScaleCTM(context, scaleFactor, scaleFactor);が座標系を調整するために使用されるため、CGContextMoveToPoint標準解像度または Retina 解像度に関係なく、 などの Core Graphics による描画が自動的に機能することです。


もう 1 つの注意点は、Retina ディスプレイでUIGraphicsBeginImageContext(CGSizeMake(300, 300));は 300 x 300ピクセルUIGraphicsBeginImageContextWithOptions(CGSizeMake(300, 300), NO, 0.0);を作成し、Retina ディスプレイでは 600 x 600ピクセルを作成することです。は0.0、標準ディスプレイまたは Retina ディスプレイに適切なサイズを自動的に与えるメソッド呼び出し用です。

于 2012-06-03T12:07:48.197 に答える
4

これも試してください:

- (UIImage *)maskImageWithColor:(UIColor *)color
{
    CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
    UIGraphicsBeginImageContextWithOptions(rect.size, NO, self.scale);
    CGContextRef c = UIGraphicsGetCurrentContext();
    [self drawInRect:rect];
    CGContextSetFillColorWithColor(c, [color CGColor]);
    CGContextSetBlendMode(c, kCGBlendModeSourceAtop);
    CGContextFillRect(c, rect);
    UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return result;
}
于 2013-02-10T21:26:09.457 に答える
1

新しいイメージ コンテキストを開始したら、 を使用して取得できますUIGraphicsGetCurrentContext。その後、それを保持し、その後再利用する場合は、他の CF オブジェクトと同じように保持します (使用が終了したら、ルールに従って解放することを忘れないでください)。UIKit のコンテキスト スタックからポップするために呼び出すUIGraphicsEndImageContext必要がありますが、コンテキストを保持していれば、コンテキストはその後も存続し、解放するまで引き続き使用できるはずです。

後でコンテキストを再度使用したい場合 (まだ解放していない場合)、1 つの方法は を呼び出すことUIGraphicsPushContextです。これにより、コンテキストがコンテキスト スタックにプッシュされます。

コンテキストを使用するもう 1 つの方法は、それが CGBitmapContext であると想定し (UIKit のドキュメントでは「ビットマップ ベースのコンテキスト」と呼ばれていますが、名前で CGBitmapContext とは言いません)、CGBitmapContextCreateImage描画後にコンテキストから新しい画像をキャプチャするために使用します。

主な違いは、 でコンテキストを作成した場合、コンテキストを作成した値と一致する必要がある UIImage を返すUIGraphicsCreateImageContextWithOptionsことです。(コンテキストをポップして後でプッシュバックした場合、そのスケール値が保持されるかどうかはわかりません。)CGImageを返し、CGImageはピクセルのみを認識します。UIGraphicsGetImageFromCurrentImageContextscaleCGBitmapContextCreateImage

もう 1 つの違いは、UIBezierPath などの UIKit 描画 API が、UIKit のコンテキスト スタック内の現在のコンテキストで動作することです。したがって、コンテキストをプッシュしない場合、Quartz API を使用してコンテキストに描画することしかできません。

上記のいずれもテストしていないため、ユーザーに提供するコードでこれを行う前に、自分で徹底的にテストする必要があります。

于 2012-06-03T05:44:21.427 に答える
-1

メイン画面を取得するために、スケーリング0.0でコンテキストを作成するだけです:

UIGraphicsBeginImageContextWithOptions(size,NO,0.0);
CGContextRef context = UIGraphicsGetCurrentContext();

3 番目のステップはありません。

于 2013-02-11T14:50:33.500 に答える