Slide 1

Slide 1 text

"QQ,JUͰ͓ֆඳ͖Λͯ͠ΈΑ͏ Kyome macOS native symposium #06 2019/12/21

Slide 2

Slide 2 text

ࣗݾ঺հ झຯͰNBD04޲͚ΞϓϦΛ։ൃ͍ͯ͠Δֶੜσϕϩούʔ དྷ೥౓͔ΒJ04ͷ৬ۀΤϯδχΞʹͳΔ༧ఆ Takuto Nakamura @Kyomesuke

Slide 3

Slide 3 text

ࣗݾ঺հ RunCat TweetShot ScreenPointer Measures ϝχϡʔόʔͰೣΛ૸Βͤ͸͡ΊͨਓͰ͢🐈

Slide 4

Slide 4 text

4DSFFO1PJOUFS Ϛ΢εΧʔιϧΛϙΠϯλʔ ͱ༷ͯ͠ʑʹڧௐදݱͰ͖Δ
 ϓϨθϯςʔγϣϯࢧԉπʔϧ

Slide 5

Slide 5 text

ࠓճͷτϐοΫ AppKitͰͷਤܗඳըख๏ • macOSͷ࠲ඪܥͷ͓͞Β͍ • NSBezierPathͰ؆୯ͳਤܗඳը • NSGraphicsContextͰҰาઌͷදݱ • ίʔυͰਤܗΛඳը͢ΔϝϦοτ

Slide 6

Slide 6 text

NBD04ͷ࠲ඪܥ ref. Apple Inc. "Coordinate system" (2018) https://developer.apple.com/library/archive/documentation/General/Conceptual/Devpedia-CocoaApp/CoordinateSystem.html iOS macOS

Slide 7

Slide 7 text

NBD04ͷ࠲ඪܥ macOS ਖ਼ํ޲ɿ൓࣌ܭճΓ

Slide 8

Slide 8 text

NBD04Ͱͷਤܗඳը • Core Graphics - CGPath (CGMutablePath) - CGContext • AppKit - NSBezierPath - NSGraphicsContext

Slide 9

Slide 9 text

NBD04Ͱͷਤܗඳը • Core Graphics - CGPath (CGMutablePath) - CGContext • AppKit - NSBezierPath - NSGraphicsContext Կ͕ҧ͏ͷʁʁ😖

Slide 10

Slide 10 text

NBD04Ͱͷਤܗඳը • Core Graphics - CGPath (CGMutablePath) - CGContext • AppKit - NSBezierPath - NSGraphicsContext ͦΕͧΕͷϥούʔʁ ͲͪΒ͔ͷํ͕ѻָ͍͕ͱ͍͏͜ͱ΋ͳ͍🤔

Slide 11

Slide 11 text

NBD04Ͱͷਤܗඳը • CGPath (CGMutablePath) w ͜Ε୯ମͰ͸7JFXʹ௚઀ඳըͰ͖ͳ͍ 
 $"4IBQF-BZFSʹQBUIΛ౉͔͢ɼ 
 $($POUFYUͷྗΛआΓΔඞཁ͕͋Δ w ͭͷ$(1BUI͚ͩͰ͸ଟ৭දݱ͸Ͱ͖ͳ͍

Slide 12

Slide 12 text

NBD04Ͱͷਤܗඳը • CGContext w άϥϑΟοΫεͷίϯςΩετΛࢦఆͯ͠ɼ 
 ਤܗඳը΍ը૾ͷ݁߹͕Ͱ͖Δ w ࠷ڧ💪 w /4(SBQIJDT$POUFYUʹঌשͯ͠΋Β͏ඞཁ͕͋Δ

Slide 13

Slide 13 text

NBD04Ͱͷਤܗඳը • NSBezierPath w /47JFXͷESBXϝιου಺ʹͯ࢖͏͜ͱͰɼ 
 ௚઀ਤܗͷඳը໋ྩΛग़ͤΔɹˠखܰʹ࢖͑Δ

Slide 14

Slide 14 text

NBD04Ͱͷਤܗඳը • NSGraphicsContext w άϥϑΟοΫεͷίϯςΩετΛ੍ޚͰ͖Δ 
 ʢݱࡏͷ$($POUFYUΛঌשͰ͖Δʣ w /4#F[JFS1BUIͱڠྗͯ͠खܰʹҰา౿ΈࠐΜͩ 
 දݱ͕Մೳ😊

Slide 15

Slide 15 text

NBD04Ͱͷओཁͳਤܗඳըख๏ • Core Graphics - CGPath (CGMutablePath) - CGContext • AppKit - NSBezierPath - NSGraphicsContext ࠓճͷओ໾

Slide 16

Slide 16 text

/4#F[JFS1BUI ઢ෼ͷύεͱϕδΣۂઢͷύεΛ·ͱΊͯѻ͑Δ ਤܗඳը༻ΦϒδΣΫτ

Slide 17

Slide 17 text

/4#F[JFS1BUI ઢ෼ͷύεͱϕδΣۂઢͷύεΛ·ͱΊͯѻ͑Δ ਤܗඳը༻ΦϒδΣΫτ ͪΐͬͱ·ͬͯ ‼︎ ϕδΣۂઢͬͯͳʹʁʁ

Slide 18

Slide 18 text

ϕδΣۂઢ /ݸͷ੍ޚ఺͔ΒಘΒΕΔ/࣍ۂઢ ੍ޚ఺ͷσʔλ͚ͩͰ׈Β͔ͳۂઢΛඳ͚ΔͷͰศརʂ /4#F[JFS1BUI͸੍ޚ఺ݸͷ࣍ۂઢΛѻ͏ P0 P1 P2 P3

Slide 19

Slide 19 text

/4#F[JFS1BUI class CustomView: NSView { override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) let path = NSBezierPath() path.move(to: NSPoint(x: 10, y: 10)) path.line(to: NSPoint(x: 150, y: 120)) path.curve(to: NSPoint(x: 240, y: 10), controlPoint1: NSPoint(x: 225, y: 180), controlPoint2: NSPoint(x: 240, y: 165)) path.close() path.stroke() } } ͜Μͳײ͡ˠ ͱΓ͋͑ͣඳ͍ͯΈΑ͏ʢجຊʣ

Slide 20

Slide 20 text

/4#F[JFS1BUI class CustomView: NSView { override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) } } εςοϓ͝ͱʹ֬ೝͯ͠ΈΑ͏

Slide 21

Slide 21 text

/4#F[JFS1BUI let path = NSBezierPath() path.move(to: NSPoint(x: 10, y: 10)) εςοϓ͝ͱʹ֬ೝͯ͠ΈΑ͏ ඳ͖ग़͠ͷ࠲ඪΛҠಈ → ඳ͖ग़͠ͷ࠲ඪ ⤴︎

Slide 22

Slide 22 text

/4#F[JFS1BUI path.line(to: NSPoint(x: 150, y: 120)) εςοϓ͝ͱʹ֬ೝͯ͠ΈΑ͏ ύεʹઢ෼Λ௥Ճ → ઢ෼ͷऴ఺ͷ࠲ඪ ⤴︎

Slide 23

Slide 23 text

/4#F[JFS1BUI path.curve(to: NSPoint(x: 240, y: 10), controlPoint1: NSPoint(x: 225, y: 180), controlPoint2: NSPoint(x: 240, y: 165)) εςοϓ͝ͱʹ֬ೝͯ͠ΈΑ͏ ύεʹϕδΣۂઢΛ௥Ճ → ϕδΣۂઢͷऴ఺ͷ࠲ඪ ੍ޚ఺ͷ࠲ඪ

Slide 24

Slide 24 text

/4#F[JFS1BUI path.close() path.stroke() // Ξ΢τϥΠϯ path.fill() // ృΓͭͿ͠ ดͨ͡ύε͕׬੒ʂ → εςοϓ͝ͱʹ֬ೝͯ͠ΈΑ͏

Slide 25

Slide 25 text

/4#F[JFS1BUI • ઢ෼͸࢝఺ͱऴ఺ͷ2఺ɼϕδΣۂઢ͸4ͭͷ੍ޚ఺ • ύεʹ௥Ճ͞Εͨ࠷ޙͷ࠲ඪ͕࢝఺ʹͳΔ͜ͱʹ஫ҙ ஫ҙ఺⚠ P0 P1 P2 P3 P0 P1 ύεͷ࠷ޙͷ࠲ඪ ύεͷ࠷ޙͷ࠲ඪ

Slide 26

Slide 26 text

/4#F[JFS1BUI // ௕ํܗ path.appendRect(rect:) // ପԁ path.appendOval(in:) // ؙ֯ͷ௕ํܗ path.appendRoundedRect(rect:, xRadius:, yRadius:) // ހ path.appendArc(from:, to:, radius:) path.appendArc(withCenter:, radius:, startAngle:, endAngle:) ଞʹ΋༷ʑͳύε௥Ճϝιου͕͋Δ

Slide 27

Slide 27 text

/4#F[JFS1BUI path.relativeMove(to: NSPoint.zero) path.relativeLine(to: NSPoint.zero) path.relativeCurve(to: NSPoint.zero, controlPoint1: NSPoint.zero, controlPoint2: NSPoint.zero) ૬ର࠲ඪΛ࢖ͬͯύεΛ௥ՃՄೳ ※ ݱࡏͷύεͷ࠷ऴ఺͔Βͷ૬ର࠲ඪ

Slide 28

Slide 28 text

/4#F[JFS1BUI let face = NSBezierPath(ovalIn: NSRect(x: 60, y: 40, width: 80, height: 80)) let earL = NSBezierPath(ovalIn: NSRect(x: 50, y: 105, width: 40, height: 40)) let earR = NSBezierPath(ovalIn: NSRect(x: 110, y: 105, width: 40, height: 40)) // ύεʹύεΛೖΕΒΕΔ face.append(earL) face.append(earR) face.fill() ෳ߹ύεͷ࡞੡

Slide 29

Slide 29 text

/4#F[JFS1BUI // ઢ෯ͷઃఆ path.lineWidth = 3 // ύεͷ୺఺ͷॲཧͷઃఆ path.lineCapStyle = .round // ύεͷηάϝϯτؒͷॲཧͷઃఆ path.lineJoinStyle = .bevel // ϚΠλʔݶքͷઃఆ path.miterLimit = 5 // ഁઢͷઃఆ path.setLineDash([8.0, 12.0], count: 2, phase: 0) ετϩʔΫͷΧελϚΠζ

Slide 30

Slide 30 text

/4#F[JFS1BUI extension NSBezierPath { func printPathElement() { var points = [CGPoint](repeating: CGPoint.zero, count: 3) for i in (0 ..< self.elementCount) { switch self.element(at: i, associatedPoints: &points) { case .moveTo: print("move:", points[0]) case .lineTo: print("line to:", points[0]) case .curveTo: print("curve to:", points[2]) print("controlPoint1:", points[0]) print("controlPoint2:", points[1]) case.closePath: print("close") @unknown default: fatalError() } } } } ύεͷཁૉΛऔΓग़͢

Slide 31

Slide 31 text

/4#F[JFS1BUI ύεͷཁૉΛऔΓग़͢ DMPTF ͢Δͱɼ಺෦తʹ͸ύεΛดͨ͡ޙʹ 
 ऴ఺ʹNPWF ͢Δ →ดͨ͡ύεͷཁૉΛऔΓग़࣌͢ɼ࠷ޙͷmoveʹ
 ஫ҙ͠ͳ͍ͱɼෳ߹ύεͷ෼ׂ࣌ʹۭͷύε΋
 ༨ܭʹੜ੒ͯ͠͠·͏ɽ

Slide 32

Slide 32 text

/4#F[JFS1BUI جຊతʹดͨ͡ύε͸൓࣌ܭճΓΛ৺͕͚Δ ಺ଆ ֎ଆ ↙︎ ύε

Slide 33

Slide 33 text

/4#F[JFS1BUI جຊతʹดͨ͡ύε͸൓࣌ܭճΓΛ৺͕͚Δ ಺ଆ ֎ଆ ֎ଆ ಺ଆ

Slide 34

Slide 34 text

/4#F[JFS1BUI جຊతʹดͨ͡ύε͸൓࣌ܭճΓΛ৺͕͚Δ let path = NSBezierPath() path.appendRect(NSRect(x: 10, y: 10, width: 190, height: 150)) path.appendOval(in: NSRect(x: 40, y: 30, width: 70, height: 60)) NSColor.red.setFill() path.fill() ͜͏͍ͨ͠ ͜͏ͳͬͪΌ͏

Slide 35

Slide 35 text

/4#F[JFS1BUI جຊతʹดͨ͡ύε͸൓࣌ܭճΓΛ৺͕͚Δ ಺ଆ ֎ଆ ಺ଆ

Slide 36

Slide 36 text

/4#F[JFS1BUI جຊతʹดͨ͡ύε͸൓࣌ܭճΓΛ৺͕͚Δ ಺ଆ ֎ଆ ֎ଆ

Slide 37

Slide 37 text

/4#F[JFS1BUI جຊతʹดͨ͡ύε͸൓࣌ܭճΓΛ৺͕͚Δ let path = NSBezierPath() path.appendRect(NSRect(x: 10, y: 10, width: 190, height: 150)) let ellipse = NSBezierPath() ellipse.appendOval(in: NSRect(x: 50, y: 50, width: 80, height: 70)) // ύεͷਐߦํ޲Λ൓సͤͯ͞௥Ճ͢Δ path.append(ellipse.reversed) NSColor.red.setFill() path.fill() ͘Γ͵͖OK

Slide 38

Slide 38 text

/4#F[JFS1BUI ύεͷਐߦํ޲Λߟ͑ͳͯ͘΋ྑ͍ํ๏΋͋Δ let path = NSBezierPath() // ͓·͡ͳ͍ path.windingRule = .evenOdd path.appendRect(NSRect(x: 10, y: 10, width: 190, height: 150)) path.appendOval(in: NSRect(x: 50, y: 50, width: 80, height: 70)) NSColor.red.setFill() path.fill() ͍͍ײ͡ʹแؚؔ܎Λߟ͑ͯ͘Γൈ͍ͯ͘ΕΔ

Slide 39

Slide 39 text

/4#F[JFS1BUI ΞϑΟϯม׵ let path = NSBezierPath() path.appendRoundedRect(NSRect(x: 0, y: 0, width: 100, height: 100), xRadius: 15, yRadius: 15) path.transform(using: AffineTransform(translationByX: -50, byY: -50)) path.transform(using: AffineTransform(scaleByX: 1.2, byY: 1.4)) path.transform(using: AffineTransform(rotationByRadians: CGFloat.pi / 3)) path.transform(using: AffineTransform(translationByX: 120, byY: 120)) path.fill() →

Slide 40

Slide 40 text

/4#F[JFS1BUI ֯౓Λѻ͏࣌ͷ஫ҙ఺ ހ౓๏ ౓਺๏ π / 3 60°

Slide 41

Slide 41 text

/4#F[JFS1BUI class CustomView: NSView { override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) let path = NSBezierPath() NSColor.black.set() path.windingRule = NSBezierPath.WindingRule.evenOdd path.appendRect(self.frame) let apple = NSBezierPath() // Apple apple.move(to: NSPoint(x: 110.89, y: 99.2)) apple.curve(to: NSPoint(x: 105.97, y: 108.09), controlPoint1: NSPoint(x: 109.5, y: 102.41), controlPoint2: NSPoint(x: 107.87, y: 105.37)) apple.curve(to: NSPoint(x: 99.64, y: 115.79), controlPoint1: NSPoint(x: 103.39, y: 111.8), controlPoint2: NSPoint(x: 101.27, y: 114.37)) apple.curve(to: NSPoint(x: 91.5, y: 119.4), controlPoint1: NSPoint(x: 97.11, y: 118.13), controlPoint2: NSPoint(x: 94.4, y: 119.33)) apple.curve(to: NSPoint(x: 83.99, y: 117.59), controlPoint1: NSPoint(x: 89.42, y: 119.4), controlPoint2: NSPoint(x: 86.91, y: 118.8)) apple.curve(to: NSPoint(x: 75.9, y: 115.79), controlPoint1: NSPoint(x: 81.06, y: 116.39), controlPoint2: NSPoint(x: 78.36, y: 115.79)) apple.curve(to: NSPoint(x: 67.58, y: 117.59), controlPoint1: NSPoint(x: 73.31, y: 115.79), controlPoint2: NSPoint(x: 70.54, y: 116.39)) apple.curve(to: NSPoint(x: 60.39, y: 119.49), controlPoint1: NSPoint(x: 64.61, y: 118.8), controlPoint2: NSPoint(x: 62.21, y: 119.43)) apple.curve(to: NSPoint(x: 52.07, y: 115.79), controlPoint1: NSPoint(x: 57.6, y: 119.61), controlPoint2: NSPoint(x: 54.83, y: 118.38)) apple.curve(to: NSPoint(x: 45.44, y: 107.82), controlPoint1: NSPoint(x: 50.3, y: 114.24), controlPoint2: NSPoint(x: 48.09, y: 111.58)) apple.curve(to: NSPoint(x: 38.44, y: 93.82), controlPoint1: NSPoint(x: 42.6, y: 103.8), controlPoint2: NSPoint(x: 40.27, y: 99.14)) apple.curve(to: NSPoint(x: 35.5, y: 77.15), controlPoint1: NSPoint(x: 36.48, y: 88.09), controlPoint2: NSPoint(x: 35.5, y: 82.53)) apple.curve(to: NSPoint(x: 39.48, y: 61.21), controlPoint1: NSPoint(x: 35.5, y: 70.98), controlPoint2: NSPoint(x: 36.82, y: 65.67)) apple.curve(to: NSPoint(x: 47.8, y: 52.74), controlPoint1: NSPoint(x: 41.56, y: 57.63), controlPoint2: NSPoint(x: 44.33, y: 54.81)) apple.curve(to: NSPoint(x: 59.06, y: 49.54), controlPoint1: NSPoint(x: 51.27, y: 50.67), controlPoint2: NSPoint(x: 55.02, y: 49.61)) apple.curve(to: NSPoint(x: 67.76, y: 51.58), controlPoint1: NSPoint(x: 61.27, y: 49.54), controlPoint2: NSPoint(x: 64.16, y: 50.23)) apple.curve(to: NSPoint(x: 74.67, y: 53.62), controlPoint1: NSPoint(x: 71.35, y: 52.94), controlPoint2: NSPoint(x: 73.66, y: 53.62)) apple.curve(to: NSPoint(x: 82.33, y: 51.22), controlPoint1: NSPoint(x: 75.42, y: 53.62), controlPoint2: NSPoint(x: 77.98, y: 52.82)) apple.curve(to: NSPoint(x: 92.73, y: 49.36), controlPoint1: NSPoint(x: 86.43, y: 49.73), controlPoint2: NSPoint(x: 89.9, y: 49.12)) apple.curve(to: NSPoint(x: 110.05, y: 58.53), controlPoint1: NSPoint(x: 100.43, y: 49.98), controlPoint2: NSPoint(x: 106.2, y: 53.03)) apple.curve(to: NSPoint(x: 99.83, y: 76.13), controlPoint1: NSPoint(x: 103.17, y: 62.72), controlPoint2: NSPoint(x: 99.77, y: 68.59)) apple.curve(to: NSPoint(x: 106.17, y: 90.76), controlPoint1: NSPoint(x: 99.89, y: 82), controlPoint2: NSPoint(x: 102.01, y: 86.88)) apple.curve(to: NSPoint(x: 112.5, y: 94.94), controlPoint1: NSPoint(x: 108.05, y: 92.56), controlPoint2: NSPoint(x: 110.16, y: 93.95)) apple.curve(to: NSPoint(x: 110.89, y: 99.2), controlPoint1: NSPoint(x: 111.99, y: 96.42), controlPoint2: NSPoint(x: 111.46, y: 97.84)) // Leaf apple.move(to: NSPoint(x: 93.25, y: 29.36)) apple.curve(to: NSPoint(x: 88.25, y: 42.23), controlPoint1: NSPoint(x: 93.25, y: 33.96), controlPoint2: NSPoint(x: 91.58, y: 38.26)) apple.curve(to: NSPoint(x: 74.1, y: 49.26), controlPoint1: NSPoint(x: 84.23, y: 46.96), controlPoint2: NSPoint(x: 79.37, y: 49.69)) apple.curve(to: NSPoint(x: 74, y: 47.52), controlPoint1: NSPoint(x: 74.03, y: 48.71), controlPoint2: NSPoint(x: 74, y: 48.13)) apple.curve(to: NSPoint(x: 79.3, y: 34.51), controlPoint1: NSPoint(x: 74, y: 43.1), controlPoint2: NSPoint(x: 75.91, y: 38.38)) apple.curve(to: NSPoint(x: 85.76, y: 29.63), controlPoint1: NSPoint(x: 80.99, y: 32.55), controlPoint2: NSPoint(x: 83.15, y: 30.93)) apple.curve(to: NSPoint(x: 93.15, y: 27.52), controlPoint1: NSPoint(x: 88.37, y: 28.35), controlPoint2: NSPoint(x: 90.83, y: 27.65)) apple.curve(to: NSPoint(x: 93.25, y: 29.36), controlPoint1: NSPoint(x: 93.22, y: 28.14), controlPoint2: NSPoint(x: 93.25, y: 28.75)) apple.line(to: NSPoint(x: 93.25, y: 29.36)) apple.close() apple.transform(using: AffineTransform(scaleByX: 1, byY: -1)) apple.transform(using: AffineTransform(translationByX: -75, byY: 77)) apple.transform(using: AffineTransform(scale: 2.0)) apple.transform(using: AffineTransform(translationByX: frame.midX, byY: frame.midY)) path.append(apple) path.fill() } }

Slide 42

Slide 42 text

/4#F[JFS1BUI class CustomView: NSView { override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) let path = NSBezierPath() NSColor.black.set() path.windingRule = NSBezierPath.WindingRule.evenOdd path.appendRect(self.frame) let apple = NSBezierPath() // Apple apple.move(to: NSPoint(x: 110.89, y: 99.2)) apple.curve(to: NSPoint(x: 105.97, y: 108.09), controlPoint1: NSPoint(x: 109.5, y: 102.41), controlPoint2: NSPoint(x: 107.87, y: 105.37)) apple.curve(to: NSPoint(x: 99.64, y: 115.79), controlPoint1: NSPoint(x: 103.39, y: 111.8), controlPoint2: NSPoint(x: 101.27, y: 114.37)) apple.curve(to: NSPoint(x: 91.5, y: 119.4), controlPoint1: NSPoint(x: 97.11, y: 118.13), controlPoint2: NSPoint(x: 94.4, y: 119.33)) apple.curve(to: NSPoint(x: 83.99, y: 117.59), controlPoint1: NSPoint(x: 89.42, y: 119.4), controlPoint2: NSPoint(x: 86.91, y: 118.8)) apple.curve(to: NSPoint(x: 75.9, y: 115.79), controlPoint1: NSPoint(x: 81.06, y: 116.39), controlPoint2: NSPoint(x: 78.36, y: 115.79)) apple.curve(to: NSPoint(x: 67.58, y: 117.59), controlPoint1: NSPoint(x: 73.31, y: 115.79), controlPoint2: NSPoint(x: 70.54, y: 116.39)) apple.curve(to: NSPoint(x: 60.39, y: 119.49), controlPoint1: NSPoint(x: 64.61, y: 118.8), controlPoint2: NSPoint(x: 62.21, y: 119.43)) apple.curve(to: NSPoint(x: 52.07, y: 115.79), controlPoint1: NSPoint(x: 57.6, y: 119.61), controlPoint2: NSPoint(x: 54.83, y: 118.38)) apple.curve(to: NSPoint(x: 45.44, y: 107.82), controlPoint1: NSPoint(x: 50.3, y: 114.24), controlPoint2: NSPoint(x: 48.09, y: 111.58)) apple.curve(to: NSPoint(x: 38.44, y: 93.82), controlPoint1: NSPoint(x: 42.6, y: 103.8), controlPoint2: NSPoint(x: 40.27, y: 99.14)) apple.curve(to: NSPoint(x: 35.5, y: 77.15), controlPoint1: NSPoint(x: 36.48, y: 88.09), controlPoint2: NSPoint(x: 35.5, y: 82.53)) apple.curve(to: NSPoint(x: 39.48, y: 61.21), controlPoint1: NSPoint(x: 35.5, y: 70.98), controlPoint2: NSPoint(x: 36.82, y: 65.67)) apple.curve(to: NSPoint(x: 47.8, y: 52.74), controlPoint1: NSPoint(x: 41.56, y: 57.63), controlPoint2: NSPoint(x: 44.33, y: 54.81)) apple.curve(to: NSPoint(x: 59.06, y: 49.54), controlPoint1: NSPoint(x: 51.27, y: 50.67), controlPoint2: NSPoint(x: 55.02, y: 49.61)) apple.curve(to: NSPoint(x: 67.76, y: 51.58), controlPoint1: NSPoint(x: 61.27, y: 49.54), controlPoint2: NSPoint(x: 64.16, y: 50.23)) apple.curve(to: NSPoint(x: 74.67, y: 53.62), controlPoint1: NSPoint(x: 71.35, y: 52.94), controlPoint2: NSPoint(x: 73.66, y: 53.62)) apple.curve(to: NSPoint(x: 82.33, y: 51.22), controlPoint1: NSPoint(x: 75.42, y: 53.62), controlPoint2: NSPoint(x: 77.98, y: 52.82)) apple.curve(to: NSPoint(x: 92.73, y: 49.36), controlPoint1: NSPoint(x: 86.43, y: 49.73), controlPoint2: NSPoint(x: 89.9, y: 49.12)) apple.curve(to: NSPoint(x: 110.05, y: 58.53), controlPoint1: NSPoint(x: 100.43, y: 49.98), controlPoint2: NSPoint(x: 106.2, y: 53.03)) apple.curve(to: NSPoint(x: 99.83, y: 76.13), controlPoint1: NSPoint(x: 103.17, y: 62.72), controlPoint2: NSPoint(x: 99.77, y: 68.59)) apple.curve(to: NSPoint(x: 106.17, y: 90.76), controlPoint1: NSPoint(x: 99.89, y: 82), controlPoint2: NSPoint(x: 102.01, y: 86.88)) apple.curve(to: NSPoint(x: 112.5, y: 94.94), controlPoint1: NSPoint(x: 108.05, y: 92.56), controlPoint2: NSPoint(x: 110.16, y: 93.95)) apple.curve(to: NSPoint(x: 110.89, y: 99.2), controlPoint1: NSPoint(x: 111.99, y: 96.42), controlPoint2: NSPoint(x: 111.46, y: 97.84)) // Leaf apple.move(to: NSPoint(x: 93.25, y: 29.36)) apple.curve(to: NSPoint(x: 88.25, y: 42.23), controlPoint1: NSPoint(x: 93.25, y: 33.96), controlPoint2: NSPoint(x: 91.58, y: 38.26)) apple.curve(to: NSPoint(x: 74.1, y: 49.26), controlPoint1: NSPoint(x: 84.23, y: 46.96), controlPoint2: NSPoint(x: 79.37, y: 49.69)) apple.curve(to: NSPoint(x: 74, y: 47.52), controlPoint1: NSPoint(x: 74.03, y: 48.71), controlPoint2: NSPoint(x: 74, y: 48.13)) apple.curve(to: NSPoint(x: 79.3, y: 34.51), controlPoint1: NSPoint(x: 74, y: 43.1), controlPoint2: NSPoint(x: 75.91, y: 38.38)) apple.curve(to: NSPoint(x: 85.76, y: 29.63), controlPoint1: NSPoint(x: 80.99, y: 32.55), controlPoint2: NSPoint(x: 83.15, y: 30.93)) apple.curve(to: NSPoint(x: 93.15, y: 27.52), controlPoint1: NSPoint(x: 88.37, y: 28.35), controlPoint2: NSPoint(x: 90.83, y: 27.65)) apple.curve(to: NSPoint(x: 93.25, y: 29.36), controlPoint1: NSPoint(x: 93.22, y: 28.14), controlPoint2: NSPoint(x: 93.25, y: 28.75)) apple.line(to: NSPoint(x: 93.25, y: 29.36)) apple.close() apple.transform(using: AffineTransform(scaleByX: 1, byY: -1)) apple.transform(using: AffineTransform(translationByX: -75, byY: 77)) apple.transform(using: AffineTransform(scale: 2.0)) apple.transform(using: AffineTransform(translationByX: frame.midX, byY: frame.midY)) path.append(apple) path.fill() } } ؤுΕ͹͜Μͳ͜ͱ΋Ͱ͖Δʂ

Slide 43

Slide 43 text

/4#F[JFS1BUI·ͱΊ w ઢ෼ͷύεͱϕδΣۂઢͷύεΛ·ͱΊͯ࢖ͬͯ 
 ؆୯ͳखॱͰਤܗΛඳըͰ͖Δ w ෳ߹ύε΍ετϩʔΫͷΧελϚΠζ͕Ͱ͖Δ w ύεͷਐߦํ޲ʹ͸ཁ஫ҙ⚠

Slide 44

Slide 44 text

/4#F[JFS1BUI·ͱΊ w ઢ෼ͷύεͱϕδΣۂઢͷύεΛ·ͱΊͯ࢖ͬͯ 
 ؆୯ͳखॱͰਤܗΛඳըͰ͖Δ w ෳ߹ύε΍ετϩʔΫͷΧελϚΠζ͕Ͱ͖Δ w ύεͷਐߦํ޲ʹ͸ཁ஫ҙ⚠ ͔͠͠...

Slide 45

Slide 45 text

4DSFFO1PJOUFSͰͷ՝୊

Slide 46

Slide 46 text

4DSFFO1PJOUFSͰͷ՝୊

Slide 47

Slide 47 text

/4(SBQIJDT$POUFYU άϥϑΟοΫεͷίϯςΩετΛ੍ޚͰ͖Δ w ඳըઌ͸8JOEPXͱ*NBHFͷͲͬͪ w ృΓͷํ๏͸ͲΜͳ෩ʹ͢Δʁ w ӨΛ͚ͭΔʁ w จࣈΛϨϯμϦϯά͢Δͱ͖ͷϑΥϯτ͸ʁ w ΞϯνΤΠϦΞε͸Ͳ͏͢Δʁ w FUD ref. Apple Inc. "Graphics Contexts" (2012) https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CocoaDrawingGuide/GraphicsContexts/GraphicsContexts.html

Slide 48

Slide 48 text

/4(SBQIJDT$POUFYU ύεͷॏͶృΓͷํ๏Λ৭ʑม͑ΒΕΔ

Slide 49

Slide 49 text

/4(SBQIJDT$POUFYU ύεͷॏͶృΓͷํ๏Λ৭ʑม͑ΒΕΔ source out clear exclusion source in multiply hue color burn luminosity NSCompositingOperation

Slide 50

Slide 50 text

/4(SBQIJDT$POUFYU ύεͷॏͶృΓͷํ๏Λ৭ʑม͑ΒΕΔ class CustomView: NSView { override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) guard let context = NSGraphicsContext.current else { return } context.saveGraphicsState() // Լ૚ͷύεΛඳ͘ let pathA = NSBezierPath() // ɾɾɾ // ృΓॏͶͷઃఆΛ͢Δ context.compositingOperation = NSCompositingOperation.clear // ্૚ͷύεΛඳ͘ let pathB = NSBezierPath() // ɾɾɾ context.restoreGraphicsState() } }

Slide 51

Slide 51 text

/4(SBQIJDT$POUFYU ScreenPointerͰ͸clearΛ࢖ͬͯղܾ

Slide 52

Slide 52 text

͓·͚ը૾ͰృΓͭͿ͠ ܧ͗໨ͷͳ͍ύλʔϯΛ༻͍Δ͜ͱͰςΫενϟΛషΕΔ let path = NSBezierPath() path.appendOval(in: NSRect(x: 10, y: 10, width: 200, height: 200)) let pattern = NSImage(imageLiteralResourceName: "pattern") NSColor(patternImage: pattern).setFill() path.fill()

Slide 53

Slide 53 text

͓·͚/4(SBEJFOU μϝͳྫ /4$PMPSDMFBS͸࢖ͬͪΌμϝʂ let start = NSColor(red: 0.549, green: 0.757, blue: 0.847, alpha: 1.0) let endA = NSColor.clear let endB = start.withAlphaComponent(0.0) let gradientA = NSGradient(starting: start, ending: endA) gradientA?.draw(in: NSRect(x: 5, y: 5, width: 150, height: 150), angle: 90) let gradientB = NSGradient(starting: start, ending: endB) gradientB?.draw(in: NSRect(x: 160, y: 5, width: 150, height: 150), angle: 90) ྑ͍ྫ

Slide 54

Slide 54 text

ίʔυͰਤܗΛඳը͢ΔϝϦοτ • ಈతʹਤܗΛมߋͰ͖Δ • ղ૾౓Λؾʹ͠ͳͯ͘ྑ͍

Slide 55

Slide 55 text

ίʔυͰਤܗΛඳը͢ΔϝϦοτ ͜Μͳײ͡ͷΧ΢ϯλʔ͕࡞ΕΔ

Slide 56

Slide 56 text

ίʔυͰਤܗΛඳը͢ΔϝϦοτ αΠζ΍܏͖ͷมߋ͕ 
 Մೳͳ෼౓ث΋࡞ΕΔ

Slide 57

Slide 57 text

ίʔυͰਤܗΛඳը͢ΔϝϦοτ ͜ΜͳϙοϓΦʔόʔ 
 ΋ࣗ࡞Ͱ͖Δ

Slide 58

Slide 58 text

Thank you!

Slide 59

Slide 59 text

͓·͚/41PJOU /44J[F /43FDU ͦΕͧΕ$(1PJOUɼ$(4J[Fɼ$(3FDUͷΤΠϦΞε