.inverseMask() ๐ŸŒ€

่‡ช่ฃฝ็š„้ฎ็ฝฉ๏ผŒไฝœ็”จๅ‰›ๅฅฝ่ทŸๅฎ˜ๆ–น็š„ .mask() ็›ธๅใ€‚

import SwiftUI

extension View {
    // view.inverseMask(_:)
    public func inverseMask<M: View>(_ mask: M) -> some View {
        // exchange foreground and background
        let inversed = mask
            .foregroundColor(.black)  // opacity = 0 (hide)
            .background(Color.white)  // opacity = 1 (show)
            .compositingGroup()       // โญ๏ธ composite all layers
            // โญ๏ธ dark   -> transparent  (opacity = 0)
            //    bright -> opaque black (opacity = 1)
            //    ๆœ‰้ปžใ€Œ่ฒ ็‰‡ใ€็š„ๆ„Ÿ่ฆบใ€‚
            .luminanceToAlpha()       // โญ๏ธ turn luminance into alpha (opacity)
        return self.mask(inversed)
    }
}

็ดฐ็ฏ€่ชชๆ˜Ž

ๅœจ .inverseMask() ไธญ็”จๅˆฐ็š„ .foregroundColor(.black) ๅ’Œ .backgroud(Color.white)๏ผŒๅฐ Image ไพ†่ชชๆฒ’ๆœ‰ไปปไฝ•ไฝœ็”จ๏ผŒๅฆ‚ไธ‹ๅœ–ๆ‰€็คบ๏ผš

ไฝ† .luminanceToAlpha() ๆœƒๅฐ‡ๅŽŸๅœ–ไธญใ€Œ้ป‘่‰ฒ็š„้ƒจๅˆ†ใ€่ฝ‰็‚บใ€Œ้€ๆ˜Žใ€(opacity = 0)๏ผŒ่€Œใ€Œ็™ฝ่‰ฒ็š„้ƒจๅˆ†ใ€ๅ‰‡่ฝ‰็‚บใ€Œๅ…จ้ป‘ใ€(opacity = 1)๏ผŒ้€™ๆ™‚็š„ๅœ–ๆœ‰้ปžๅƒ็›ธ็‰‡็š„ใ€Œๅบ•็‰‡ใ€(่ฒ ็‰‡)ใ€‚

ๅฅ—็”จ .mask() ็š„ๆ™‚ๅ€™๏ผŒopacity = 1 ็š„ๆœƒใ€Œไฟ็•™ๅŽŸไพ†็š„่‰ฒๅฝฉใ€๏ผŒopacity = 0 ็š„้ƒจๅˆ†ๅ‰‡่ฝ‰็‚บใ€Œ้€ๆ˜Žใ€ใ€‚้€™ๅฐฑๆ˜ฏ็ˆฒไป€้บผๅŽŸๅœ–ๅฐ็‹—็š„็œผ็›ๅ››ๅ‘จๆฏ”่ผƒ้ป‘๏ผŒๆœƒ้€ ๆˆๆœ€ๅพŒ็š„ๅœ–ๅœจๅฐ็‹—็œผ็›ๅ››ๅ‘จๆœ‰ไบ›้€ๆ˜Žใ€‚

็ธฝไน‹๏ผŒmask ๅŽŸๅœ–ไธญๆฏ”่ผƒ็™ฝ็š„้ƒจๅˆ†๏ผŒไฝœ็‚บใ€Œ่ขซๅ‰ช่ฃๅฐ่ฑกใ€็š„็›ธๅฐ้ƒจๅˆ†ๆœƒ่ขซไฟ็•™ไธ‹ไพ†๏ผŒmask ๅŽŸๅœ–ไธญ่ผƒ้ป‘็š„้ƒจๅˆ†ๅ‰‡่ฝ‰็‚บ้€ๆ˜Ž๏ผŒ่‡ณๆ–ผ่ถ…ๅ‡บ mask ๅŽŸๅœ–็ฏ„ๅœ็š„้ƒจๅˆ†๏ผŒๅ‰‡็›ดๆŽฅ่ขซ่ฃๆŽ‰ใ€‚ โš ๏ธ ไฝ†ๆณจๆ„๏ผšๅšๅฎŒ .mask() ไน‹ๅพŒ๏ผŒframe ็š„ๅคงๅฐ้‚„ๆ˜ฏๅŽŸไพ†ใ€Œ่ขซๅ‰ช่ฃๅฐ่ฑกใ€็š„ๅคงๅฐๅ–”๏ผ

ๅฐๆ–ผไธ€ๅผต็…ง็‰‡ photo ไพ†่ชช๏ผš paper.inverseMask(photo) == paper.mask(photo.luminanceToAlpha()) photo ่ผƒๆทก็š„้ƒจๅˆ†๏ผŒpaper ๆœƒ่ฎŠ้€ๆ˜Žไธ€ไบ›ใ€‚

ไฝ† paper.mask(photo) ๅ‰‡ๆœƒๅฎŒๅ…จไฟ็•™ paper ็š„้ก่‰ฒ๏ผŒๅชๆŠŠ paper ๅœจ photo ไปฅๅค–็š„้ƒจๅˆ†่ฃๆŽ‰่€Œๅทฒ๏ผŒ้€™ๅฏ่ƒฝๆ˜ฏๅ› ็‚บ photo ็…ง็‰‡ๆœฌไพ†็š„ๆฏๅ€‹ๅƒ็ด  opacity = 1 ็š„็ทฃๆ•…ใ€‚

import SwiftUI
import PlaygroundSupport

extension View {
    @ViewBuilder
    func label(_ text: String) -> some View {
        VStack(alignment: .leading) {
            self.border(Color.black)
            Text(text).padding(.leading).padding(.bottom, 10)
        }.border(Color.black)
    }
}

let shad = Color.black.opacity(0.8)
let numberPaper = Image("numbers")).resizable().scaledToFill()
    .rotationEffect(.degrees(90)).frame(maxWidth: 280)

struct ContentView: View {
    
    let puppy: some View = Image("puppy")).resizable().scaledToFit().frame(width: 150)
    
    var v1: some View { puppy.foregroundColor(.black) } // opacity = 0 (hide)
    var v2: some View { v1.background(Color.white) }   // opacity = 1 (show)
    var v3: some View { v2.compositingGroup() }        // โญ๏ธ composite all layers
    var v4: some View { v3.luminanceToAlpha() }        // โญ๏ธ turn luminance into alpha
    
    var v5: some View {
        ZStack {
            numberPaper.mask(v4).shadow(color: shad, radius: 4, x: 4, y: 4) 
            puppy.hidden().border(Color.black)
        }.background(Gradient.down(.yellow, .green))
    }
    
    var body: some View {
        VStack(alignment: .leading) {
            HStack {
                puppy.label("image")
                v1   .label("fg = black")
                v2   .label("bg = white")
            }
            
            HStack(alignment: .top) {
                v4.background(Color.white).label("ไบฎๅบฆ่ฝ‰ alpha")
                v5.label("mask(image)")
            }
            
        } // container (HStack)
            .padding()
            .background(Color.gray)
        
    } // body
}

PlaygroundPage.current.setLiveView(ContentView())

Last updated