4

これが私がやろうとしていることです:左側は、オフスクリーンで作成し、速度を上げるためにキャッシュした、一般的な色付けされていない RGBA 画像です (最初に作成するのは非常に遅いですが、後で任意の色で色付けするのは非常に高速です。必要)。円形の渦巻きのある正方形の画像です。円の内側では、画像のアルファ/不透明度は 1 です。円の外側では、アルファ/不透明度は 0 です。ここでは、背景色が の UIView 内に表示しました[UIColor scrollViewTexturedBackgroundColor]右側は、設定後に赤い実線の長方形を上に塗りつぶして画像を色付けしようとするとどうなるかですCGContextSetBlendMode(context, kCGBlendModeColor)

無着色 間違って色付けされた

それは私が望んでいることでも、私が期待したことでもありません。明らかに、完全に透明なピクセル (たとえば、アルファ値 0) に色を付けると、予想どおりに透明なままではなく、奇妙な理由で完全な塗りつぶしの色になります。

私が欲しいのは、実際にはこれです:

正しく着色

さて、この特定のケースでは、クリッピング領域を円に設定して、円の外側の領域がそのまま残るようにすることができます。これは、回避策としてここで行ったことです。

しかし、私のアプリでは、クリッピング/アウトライン パスがわからない任意の形状を色付けできる必要もあります。一例として、グラデーションを重ねて白いテキストに色を付けます。これはどのように行われますか?画像マスクを使用して、一般的に、奇妙なパス/クリッピングのトリックなしで、効率的に行う方法があるに違いないと思います...しかし、これに関するチュートリアルをまだ見つけていません。他のゲームで色付きのグラデーション テキストを見たことがあるので、明らかに可能です。

ちなみに、私ができないことは、グラデーションから始めて、必要のない部分を切り取り/消去することです。これは、(上記の例に示すように) 色付けされていないソース画像は、通常、純粋な白ではなくグレースケールであるためです。したがって、色付けされていない画像から始めて、色付けする必要があります。

ps —kCGBlendModeMultiply部分的に透明な画像の色付けに関しても、同じ欠陥/欠点/特異性があります。Appleがなぜそのようにすることにしたのか、誰か知っていますか? これは、Quartz のカラー化コードが RGBA(0,0,0,0) を RGBA(0,0,0,1) として扱うかのようです。つまり、アルファ チャネルを完全に無視して破棄します。

4

1 に答える 1

1

有効な方法の 1 つは、元の画像からマスクを作成し、乗算ブレンド モード セットで画像をレンダリングする前に CGContextClipToMask() メソッドを呼び出すことです。イメージを色付きで描画する前にマスクを設定する CoreGraphics コードを次に示します。

  CGContextRef context = [frameBuffer createBitmapContext];
  CGRect bounds = CGRectMake( 0.0f, 0.0f, width, height );
  CGContextClipToMask(context, bounds, maskImage.CGImage);
  CGContextDrawImage(context, bounds, greyImage.CGImage);

もう少しトリッキーな部分は、元の画像を取得して maskImage を生成することです。そのためにできることは、各ピクセルを調べて黒または白のピクセルをマスク値として書き込むループを作成することです。画像内の元のピクセルが完全に透明な場合は黒のピクセルを書き込み、それ以外の場合は白のピクセルを書き込みます。マスク値は 24BPP イメージになることに注意してください。正しいアイデアを提供するためのコードを次に示します。

  uint32_t *inPixels = (uint32_t*) MEMORY_ADDR_OF_ORIGINAL_IMAGE;
  uint32_t *maskPixels = malloc(numPixels * sizeof(uint32_t));
  uint32_t *maskPixelsPtr = maskPixels;

  for (int rowi = 0; rowi < height; rowi++) {
    for (int coli = 0; coli < width; coli++) {
      uint32_t inPixel = *inPixels++;
      uint32_t inAlpha = (inPixel >> 24) & 0xFF;
      uint32_t cval = 0;
      if (inAlpha != 0) {
        cval = 0xFF;
      }
      uint32_t outPixel = (0xFF << 24) | (cval << 16) | (cval << 8) | cval;
      *maskPixelsPtr++ = outPixel;
    }
  }

もちろん、すべての詳細を入力し、グラフィック コンテキストなどを作成する必要があります。しかし、一般的な考え方は、独自のマスクを作成して、円の外側の赤い部分の描画を除外することです。

于 2013-03-21T06:52:06.647 に答える