Upgrade to Pro — share decks privately, control downloads, hide ads and more …

AppKitでお絵描きをしてみよう / macOS native symposium #06

AppKitでお絵描きをしてみよう / macOS native symposium #06

AppKitにはNSBezierPathやNSGraphicsContextを用いた図形描画の方法が用意されています。今回は図形描画の基本を押さえながら、注意点や雑学をご紹介いたします。汎用性が高い図形描画の世界に足を踏み入れてみましょう。

このスライドはmacOS native Symposium #06で使用されたものです。

Kyome (Takuto Nakamura)

August 21, 2022
Tweet

More Decks by Kyome (Takuto Nakamura)

Other Decks in Programming

Transcript

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

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

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

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

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

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

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

  8. NBD04Ͱͷਤܗඳը • Core Graphics - CGPath (CGMutablePath) - CGContext •

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

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

    AppKit - NSBezierPath - NSGraphicsContext ͦΕͧΕͷϥούʔʁ ͲͪΒ͔ͷํ͕ѻָ͍͕ͱ͍͏͜ͱ΋ͳ͍🤔
  11. NBD04Ͱͷਤܗඳը • CGPath (CGMutablePath) w ͜Ε୯ମͰ͸7JFXʹ௚઀ඳըͰ͖ͳ͍ 
 $"4IBQF-BZFSʹQBUIΛ౉͔͢ɼ 
 $($POUFYUͷྗΛआΓΔඞཁ͕͋Δ

    w ͭͷ$(1BUI͚ͩͰ͸ଟ৭දݱ͸Ͱ͖ͳ͍
  12. NBD04Ͱͷਤܗඳը • CGContext w άϥϑΟοΫεͷίϯςΩετΛࢦఆͯ͠ɼ 
 ਤܗඳը΍ը૾ͷ݁߹͕Ͱ͖Δ w ࠷ڧ💪 w

    /4(SBQIJDT$POUFYUʹঌשͯ͠΋Β͏ඞཁ͕͋Δ
  13. NBD04Ͱͷਤܗඳը • NSBezierPath w /47JFXͷESBXϝιου಺ʹͯ࢖͏͜ͱͰɼ 
 ௚઀ਤܗͷඳը໋ྩΛग़ͤΔɹˠखܰʹ࢖͑Δ

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


    දݱ͕Մೳ😊
  15. NBD04Ͱͷओཁͳਤܗඳըख๏ • Core Graphics - CGPath (CGMutablePath) - CGContext •

    AppKit - NSBezierPath - NSGraphicsContext ࠓճͷओ໾
  16. /4#F[JFS1BUI ઢ෼ͷύεͱϕδΣۂઢͷύεΛ·ͱΊͯѻ͑Δ ਤܗඳը༻ΦϒδΣΫτ

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

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

  19. /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() } } ͜Μͳײ͡ˠ ͱΓ͋͑ͣඳ͍ͯΈΑ͏ʢجຊʣ
  20. /4#F[JFS1BUI class CustomView: NSView { override func draw(_ dirtyRect: NSRect)

    { super.draw(dirtyRect) } } εςοϓ͝ͱʹ֬ೝͯ͠ΈΑ͏
  21. /4#F[JFS1BUI let path = NSBezierPath() path.move(to: NSPoint(x: 10, y: 10))

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

    ⤴︎
  23. /4#F[JFS1BUI path.curve(to: NSPoint(x: 240, y: 10), controlPoint1: NSPoint(x: 225, y:

    180), controlPoint2: NSPoint(x: 240, y: 165)) εςοϓ͝ͱʹ֬ೝͯ͠ΈΑ͏ ύεʹϕδΣۂઢΛ௥Ճ → ϕδΣۂઢͷऴ఺ͷ࠲ඪ ੍ޚ఺ͷ࠲ඪ
  24. /4#F[JFS1BUI path.close() path.stroke() // Ξ΢τϥΠϯ path.fill() // ృΓͭͿ͠ ดͨ͡ύε͕׬੒ʂ →

    εςοϓ͝ͱʹ֬ೝͯ͠ΈΑ͏
  25. /4#F[JFS1BUI • ઢ෼͸࢝఺ͱऴ఺ͷ2఺ɼϕδΣۂઢ͸4ͭͷ੍ޚ఺ • ύεʹ௥Ճ͞Εͨ࠷ޙͷ࠲ඪ͕࢝఺ʹͳΔ͜ͱʹ஫ҙ ஫ҙ఺⚠ P0 P1 P2 P3

    P0 P1 ύεͷ࠷ޙͷ࠲ඪ ύεͷ࠷ޙͷ࠲ඪ
  26. /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:) ଞʹ΋༷ʑͳύε௥Ճϝιου͕͋Δ
  27. /4#F[JFS1BUI path.relativeMove(to: NSPoint.zero) path.relativeLine(to: NSPoint.zero) path.relativeCurve(to: NSPoint.zero, controlPoint1: NSPoint.zero, controlPoint2:

    NSPoint.zero) ૬ର࠲ඪΛ࢖ͬͯύεΛ௥ՃՄೳ ※ ݱࡏͷύεͷ࠷ऴ఺͔Βͷ૬ର࠲ඪ
  28. /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() ෳ߹ύεͷ࡞੡
  29. /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) ετϩʔΫͷΧελϚΠζ
  30. /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() } } } } ύεͷཁૉΛऔΓग़͢
  31. /4#F[JFS1BUI ύεͷཁૉΛऔΓग़͢ DMPTF ͢Δͱɼ಺෦తʹ͸ύεΛดͨ͡ޙʹ 
 ऴ఺ʹNPWF ͢Δ →ดͨ͡ύεͷཁૉΛऔΓग़࣌͢ɼ࠷ޙͷmoveʹ
 ஫ҙ͠ͳ͍ͱɼෳ߹ύεͷ෼ׂ࣌ʹۭͷύε΋
 ༨ܭʹੜ੒ͯ͠͠·͏ɽ

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

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

  34. /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() ͜͏͍ͨ͠ ͜͏ͳͬͪΌ͏
  35. /4#F[JFS1BUI جຊతʹดͨ͡ύε͸൓࣌ܭճΓΛ৺͕͚Δ ಺ଆ ֎ଆ ಺ଆ

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

  37. /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
  38. /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() ͍͍ײ͡ʹแؚؔ܎Λߟ͑ͯ͘Γൈ͍ͯ͘ΕΔ
  39. /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() →
  40. /4#F[JFS1BUI ֯౓Λѻ͏࣌ͷ஫ҙ఺ ހ౓๏ ౓਺๏ π / 3 60°

  41. /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() } }
  42. /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() } } ؤுΕ͹͜Μͳ͜ͱ΋Ͱ͖Δʂ
  43. /4#F[JFS1BUI·ͱΊ w ઢ෼ͷύεͱϕδΣۂઢͷύεΛ·ͱΊͯ࢖ͬͯ 
 ؆୯ͳखॱͰਤܗΛඳըͰ͖Δ w ෳ߹ύε΍ετϩʔΫͷΧελϚΠζ͕Ͱ͖Δ w ύεͷਐߦํ޲ʹ͸ཁ஫ҙ⚠

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

  45. 4DSFFO1PJOUFSͰͷ՝୊

  46. 4DSFFO1PJOUFSͰͷ՝୊

  47. /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
  48. /4(SBQIJDT$POUFYU ύεͷॏͶృΓͷํ๏Λ৭ʑม͑ΒΕΔ

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

    color burn luminosity NSCompositingOperation
  50. /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() } }
  51. /4(SBQIJDT$POUFYU ScreenPointerͰ͸clearΛ࢖ͬͯղܾ

  52. ͓·͚ը૾ͰృΓͭͿ͠ ܧ͗໨ͷͳ͍ύλʔϯΛ༻͍Δ͜ͱͰςΫενϟΛషΕΔ 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()
  53. ͓·͚/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) ྑ͍ྫ
  54. ίʔυͰਤܗΛඳը͢ΔϝϦοτ • ಈతʹਤܗΛมߋͰ͖Δ • ղ૾౓Λؾʹ͠ͳͯ͘ྑ͍

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

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

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

  58. Thank you!

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