2

これUIImageを黒線で2分割する方法。の上部輪郭セットUIBezierPath

結果の 2 つの s を取得する必要がありますUIImage。それで、それは可能ですか?

4

3 に答える 3

7

次の一連のルーチンは、パス内のコンテンツのみ、またはそのパスのコンテンツのみを持つ UIImage のバージョンを作成します。

どちらもcompositeImageCGBlendMode を使用するメソッドを使用します。CGBlendMode は、描画できる他のものに対して描画できるものをマスクするのに非常に強力です。他のブレンド モードで compositeImage: を呼び出すと、(常に役立つとは限りませんが) 興味深い効果が得られます。すべてのモードについては、CGContext リファレンスを参照してください。

OPへのコメントで説明したクリッピング方法は機能し、おそらくより高速ですが、クリッピングするすべての領域を定義する UIBezierPaths がある場合に限ります。

- (UIImage*) compositeImage:(UIImage*) sourceImage onPath:(UIBezierPath*) path usingBlendMode:(CGBlendMode) blend;
{
    // Create a new image of the same size as the source.
    UIGraphicsBeginImageContext([sourceImage size]);

    // First draw an opaque path...
    [path fill];
    // ...then composite with the image.
    [sourceImage drawAtPoint:CGPointZero blendMode:blend alpha:1.0];

    // With drawing complete, store the composited image for later use.
    UIImage *maskedImage = UIGraphicsGetImageFromCurrentImageContext();

    // Graphics contexts must be ended manually.
    UIGraphicsEndImageContext();

    return maskedImage;
}

- (UIImage*) maskImage:(UIImage*) sourceImage toAreaInsidePath:(UIBezierPath*) maskPath;
{
    return [self compositeImage:sourceImage onPath:maskPath usingBlendMode:kCGBlendModeSourceIn];
}

- (UIImage*) maskImage:(UIImage*) sourceImage toAreaOutsidePath:(UIBezierPath*) maskPath;
{
    return [self compositeImage:sourceImage onPath:maskPath usingBlendMode:kCGBlendModeSourceOut];
}
于 2012-04-10T13:28:15.050 に答える
2

クリッピングをテストしましたが、いくつかの異なるテストでは、マスキングよりも25% 遅く[maskImage: toAreaInsidePath:]、他の回答の方法と同じ結果が得られました。完全を期すためにここに含めますが、正当な理由なしに使用しないでください。

- (UIImage*) clipImage:(UIImage*) sourceImage toPath:(UIBezierPath*) path;
{
    // Create a new image of the same size as the source.
    UIGraphicsBeginImageContext([sourceImage size]);

    // Clipping means drawing only happens within the path.
    [path addClip];

    // Draw the image to the context.
    [sourceImage drawAtPoint:CGPointZero];

    // With drawing complete, store the composited image for later use.
    UIImage *clippedImage = UIGraphicsGetImageFromCurrentImageContext();

    // Graphics contexts must be ended manually.
    UIGraphicsEndImageContext();

    return clippedImage;
}
于 2012-04-10T22:24:41.780 に答える
2

これは実行できますが、三角法が必要です。上の画像の場合を考えてみましょう。最初に、 の最下部の終点を決定し、UIBezierPathを使用UIGraphicsBeginImageContextして線より上のイメージの上部を取得します。これは次のようになります。

上部

ここで、線が直線であると仮定して、垂直線を描く線に沿ってピクセルごとに移動します(上部のループ。下部の同様の線に進みます) strokeclearColor

for(int currentPixel_x=0;currentPixel_x<your_ui_image_top.size.width)
    UIGraphicsBeginImageContext(your_ui_image_top.size);
    [your_ui_image_top drawInRect:CGRectMake(0, 0, your_ui_image_top.size.width, your_ui_image_top.size.height)];
    CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
    CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 1.0);
    CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeClear); 
    CGContextSetStrokeColorWithColor(UIGraphicsGetCurrentContext(),[UIColor clearColor].CGColor);
    CGContextBeginPath(UIGraphicsGetCurrentContext());
    CGContextMoveToPoint(UIGraphicsGetCurrentContext(), currentPixel_x, m*currentPixel_x + c);
    CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPixel_x, your_ui_image_top.size.height);
    CGContextStrokePath(UIGraphicsGetCurrentContext());
    your_ui_image_top = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
}

フォームUIBezierPathの直線に変換する必要がありますy = m*x + c。このx式の はcurrentPixel_x上記になります。イメージの幅をcurrentPixel_x1 ずつ増やしながら繰り返します。next_y_point_on_your_line次のように計算されます。

next_y_point_on_your_line = m*currentPixel_x + c

各垂直線strokeは 1 ピクセル幅で、高さは縦線をどのように通過するかによって異なります。何度か繰り返した後、画像は大まかに次のようになります (写真編集のスキルが低いことをお許しください!)。

ここに画像の説明を入力

明確なストロークを描く方法は複数ありますが、これは 1 つの方法にすぎません。より良い結果が得られる場合は、指定されたパスに平行な明確なストロークを作成することもできます。

もう 1 つの方法は、線の下のピクセルのアルファを 0 に設定することです。

于 2012-04-10T12:53:10.050 に答える