UIImageViewをマスクするにはどうすればよいですか?


100

私はこのようなもので画像をマスクしようとしています:

マスクする画像

手伝ってくれませんか?

私はこのコードを使用しています:

- (void) viewDidLoad {
    UIImage *OrigImage = [UIImage imageNamed:@"dogs.png"];
    UIImage *mask = [UIImage imageNamed:@"mask.png"];
    UIImage *maskedImage = [self maskImage:OrigImage withMask:mask];
    myUIIMage.image = maskedImage;
}

27
私はオリジナルのチュートリアルを書いた人です。マスク画像は、フォトショップで作成した単純なグレースケール画像です。それについて特別なことは何もありません。黒い領域がマスクの「透明な」部分になります。灰色の陰影は不透明度として解釈されることに注意してください。このようにして、マスクをグラデーションにすることもできます。これは、マスクの周囲に柔らかい境界線を作成するのに役立ちます。
ra9r

これは同じサイズでなければなりませんよね?
KarenAnne 2013年

ハイパーエレガントなコード、ありがとう。誰もがマスキング...前の画像をトリミングする必要がある場合にだけ有用なリンクstackoverflow.com/questions/17712797/...
Fattie


1
選択された回答を、約3倍の投票数を持つ回答に変更してください。私の意見では、ほぼすべての点で優れています。
アルバートレンショー

回答:


163

もっと簡単な方法があります。

#import <QuartzCore/QuartzCore.h>
// remember to include Framework as well

CALayer *mask = [CALayer layer];
mask.contents = (id)[[UIImage imageNamed:@"mask.png"] CGImage];
mask.frame = CGRectMake(0, 0, <img_width>, <img_height>);
yourImageView.layer.mask = mask;
yourImageView.layer.masksToBounds = YES;

Swift 4以降の場合、以下のコードに従ってください

let mask = CALayer()
mask.contents =  [ UIImage(named: "right_challenge_bg")?.cgImage] as Any
mask.frame = CGRect(x: 0, y: 0, width: leftBGImage.frame.size.width, height: leftBGImage.frame.size.height)
leftBGImage.layer.mask = mask
leftBGImage.layer.masksToBounds = true

1
ありがとう、でも私はこのコードを付けましたviewDidLoadが何も起こりませんでした!
Mc.Lover、2011

6
レイヤープロパティを設定してマスクを使用する必要があります。つまり、[yourImageView.layer setMasksToBounds:YES];
Wolfgang Schreurs

3
これは、このソリューションのUIImageViewである必要があることに注意してください。他のソリューションは、UIImageでのみ機能します。
adriendenat

1
私はこのアプローチを試しましたが、これはiOS 8では機能しないようです
bdv

2
Swiftコードの場合、mask.contentsに配置すると、CGImageになります。[CGImage]ではありません。ブラケット[]を使用する場合は、配列を意味します。
イチゴ

59

チュートリアルでは、このメソッドを2つのパラメーターとともに使用します。imageおよびmaskImage、これらは、メソッドを呼び出すときに設定する必要があります。メソッドが同じクラスにあり、画像がバンドルにあると想定すると、呼び出しの例は次のようになります。

注-驚くことに、画像は同じサイズである必要はありません。

...
UIImage *image = [UIImage imageNamed:@"dogs.png"];
UIImage *mask = [UIImage imageNamed:@"mask.png"];

// result of the masking method
UIImage *maskedImage = [self maskImage:image withMask:mask];

...

- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage {

    CGImageRef maskRef = maskImage.CGImage; 

    CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
        CGImageGetHeight(maskRef),
        CGImageGetBitsPerComponent(maskRef),
        CGImageGetBitsPerPixel(maskRef),
        CGImageGetBytesPerRow(maskRef),
        CGImageGetDataProvider(maskRef), NULL, false);

    CGImageRef maskedImageRef = CGImageCreateWithMask([image CGImage], mask);
    UIImage *maskedImage = [UIImage imageWithCGImage:maskedImageRef];

    CGImageRelease(mask);
    CGImageRelease(maskedImageRef);

    // returns new image with mask applied
    return maskedImage;
}

コードを提供した後、参照用にコメントとしていくつかの番号を追加しました。まだ2つのオプションがあります。この全体は、どこかで呼び出すメソッドです。内部に画像を作成する必要はありません。これにより、メソッドの再利用性がゼロになります。

コードを機能させるため。メソッドのヘッド(1.)を

- (UIImage *)maskImageMyImages {

次に、2。の変数の名前を

UIImage *maskImage = [UIImage imageNamed:@"mask.png"];

このメソッドはマスクされた画像を返すので、どこかでこのメソッドを呼び出す必要があります。メソッドを呼び出すコードを教えていただけますか?


ごめんなさい !どこにUIImage *imageコードを書くべきですか?!!! 上の理由-(UIimage *) maskeImageコンパイラ再定義エラーを与えます!
Mc.Lover、2011

申し訳ありませんが、サンプルコードをアップロードしてください。Iamは混乱しています:-s
Mc.Lover

1
不可能です。すべてあります。このメソッドの呼び出し方法、または少なくとも画像をマスクして結果を表示したい部分を示す必要があります。
Nick Weaver

私の問題はそれを呼び出すことです、それはこのようなものでなければなりませんか?(viewDidLoad):編集したコードを参照
Mc.Lover

リバースマスキングに関するアイデア(上記のプロセスの逆)。塗りつぶし領域(透明にする)および塗りつぶしのある透明領域を削除することを意味します。
ミラノパテル

16

Swift 3-私が見つけた最も簡単なソリューション

@IBDesignableストーリーボードですぐに効果を確認できるように、これを作成しました。

import UIKit

@IBDesignable
class UIImageViewWithMask: UIImageView {
    var maskImageView = UIImageView()

    @IBInspectable
    var maskImage: UIImage? {
        didSet {
            maskImageView.image = maskImage
            updateView()
        }
    }

    // This updates mask size when changing device orientation (portrait/landscape)
    override func layoutSubviews() {
        super.layoutSubviews()
        updateView()
    }

    func updateView() {
        if maskImageView.image != nil {
            maskImageView.frame = bounds
            mask = maskImageView
        }
    }
} 

使い方

  1. 新しいファイルを作成し、上記のコードに貼り付けます。
  2. UIImageViewをストーリーボードに追加します(必要に応じて画像を割り当てます)。
  3. Identity Inspectorの場合:カスタムクラスを "UIImageViewWithMask"(上記のカスタムクラス名)に変更します。
  4. 属性インスペクター上:使用するマスク画像を選択します。

ストーリーボードのマスキング

ノート

  • マスクイメージには、黒以外の部分の透明な背景(PNG)が必要です。

12

CALayerまたはCGImageCreateWithMaskを使用して両方のコードを試しましたが、どれも機能しませんでした

しかし、問題はpngファイル形式であり、コードではないことがわかりました!!
だから私の発見を共有するために!

使いたい場合

- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage

アルファチャネルなしの24ビット png 使用する必要があります

CALayerマスクを使用する場合は、(24ビットまたは8ビット)アルファチャネル付きの png 使用する必要があります。pngの透明部分が画像をマスクします(滑らかなグラデーションアルファマスクの場合。アルファチャネル付きの24ビットpngを使用します)。


10
- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage {
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

        CGImageRef maskImageRef = [maskImage CGImage];

        // create a bitmap graphics context the size of the image
        CGContextRef mainViewContentContext = CGBitmapContextCreate (NULL, maskImage.size.width, maskImage.size.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);
        CGColorSpaceRelease(colorSpace);

        if (mainViewContentContext==NULL)
            return NULL;

        CGFloat ratio = 0;

        ratio = maskImage.size.width/ image.size.width;

        if(ratio * image.size.height < maskImage.size.height) {
            ratio = maskImage.size.height/ image.size.height;
        }

        CGRect rect1  = {{0, 0}, {maskImage.size.width, maskImage.size.height}};
        CGRect rect2  = {{-((image.size.width*ratio)-maskImage.size.width)/2 , -((image.size.height*ratio)-maskImage.size.height)/2}, {image.size.width*ratio, image.size.height*ratio}};


        CGContextClipToMask(mainViewContentContext, rect1, maskImageRef);
        CGContextDrawImage(mainViewContentContext, rect2, image.CGImage);


        // Create CGImageRef of the main view bitmap content, and then
        // release that bitmap context
        CGImageRef newImage = CGBitmapContextCreateImage(mainViewContentContext);
        CGContextRelease(mainViewContentContext);

        UIImage *theImage = [UIImage imageWithCGImage:newImage];

        CGImageRelease(newImage);

        // return the image
        return theImage;
}

これでうまくいきます。


ありがとう、この答えは、他の人がより多くのより大きな画像でのパフォーマンスについて話すよりも優れています。
Radu Ursache 2014年

1
リバースマスキングについてのアイデア(上記のプロセスの逆)。つまり、塗りつぶし領域(透明にする)と透明領域を塗りつぶして削除することを意味します。
ミラノパテル2015年

おかげで、このコードは最初よりもうまく機能します!! しかし、私は2つの問題があります。「kCGImageAlphaPremultipliedLast」に関する警告(修正のために「CGBitmapInfo」にキャストします)、および網膜画像に対しては機能しません!! あなたは私を助けてくれますか?? ...
fingerup

@Milanpatel簡単な解決策は、マスク画像の色を単に反転させることです。:)
ディズ

@ZyiOSマスクされた画像のフレームをどのようにカスタマイズできますか?つまり、ユーザーはマスクされた画像のサイズを増減できます。
Dalvik

8

SWIFT 3 XCODE 8.1

func maskImage(image: UIImage, withMask maskImage: UIImage) -> UIImage {

    let maskRef = maskImage.cgImage

    let mask = CGImage(
        maskWidth: maskRef!.width,
        height: maskRef!.height,
        bitsPerComponent: maskRef!.bitsPerComponent,
        bitsPerPixel: maskRef!.bitsPerPixel,
        bytesPerRow: maskRef!.bytesPerRow,
        provider: maskRef!.dataProvider!,
        decode: nil,
        shouldInterpolate: false)

    let masked = image.cgImage!.masking(mask!)
    let maskedImage = UIImage(cgImage: masked!)

    // No need to release. Core Foundation objects are automatically memory managed.

    return maskedImage

}

//使用のため

testImage.image = maskImage(image: UIImage(named: "OriginalImage")!, withMask: UIImage(named: "maskImage")!)

写真をくれませんか
Ahmed Safadi

3

承認されたソリューションのSwiftバージョン:

func maskImage(image: UIImage, withMask maskImage: UIImage) -> UIImage {

    let maskRef = maskImage.CGImage

    let mask = CGImageMaskCreate(
        CGImageGetWidth(maskRef),
        CGImageGetHeight(maskRef),
        CGImageGetBitsPerComponent(maskRef),
        CGImageGetBitsPerPixel(maskRef),
        CGImageGetBytesPerRow(maskRef),
        CGImageGetDataProvider(maskRef),
        nil,
        false)

    let masked = CGImageCreateWithMask(image.CGImage, mask)
    let maskedImage = UIImage(CGImage: masked)!

    // No need to release. Core Foundation objects are automatically memory managed.

    return maskedImage

}

誰かがそれを必要とする場合に備えて。

それは完璧に私のために働いています。


これのSwift 3.0バージョンはありますか?
Van Du Tran

2

正解は現在機能していないことがわかり、UIImageViewで画像をマスクするのに役立つ小さなドロップインクラスを実装しました。

こちらから入手できます:https : //github.com/Werbary/WBMaskedImageView

例:

WBMaskedImageView *imgView = [[WBMaskedImageView alloc] initWithFrame:frame];
imgView.originalImage = [UIImage imageNamed:@"original_image.png"];
imgView.maskImage = [UIImage imageNamed:@"mask_image.png"];

1
いいね!それは本当に役に立ちました。
abhimuralidharan
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.