From e646939f12a00aa53ad95082d01dbc0493e3d3da Mon Sep 17 00:00:00 2001 From: shogo4405 Date: Wed, 24 Jul 2024 00:50:55 +0900 Subject: [PATCH] Fixed a bug where the application crashes when the area is large. --- Sources/Screen/Screen.swift | 4 +++- Sources/Screen/ScreenObject.swift | 36 ++++++++++++++++++++++++----- Sources/Screen/ScreenRenderer.swift | 7 +++++- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/Sources/Screen/Screen.swift b/Sources/Screen/Screen.swift index 9668b0066..eb9f6aca9 100644 --- a/Sources/Screen/Screen.swift +++ b/Sources/Screen/Screen.swift @@ -21,6 +21,7 @@ protocol ScreenObserver: AnyObject { /// An object that manages offscreen rendering a foundation. public final class Screen: ScreenObjectContainerConvertible { + static let size = CGSize(width: 1280, height: 720) private static let lockFrags = CVPixelBufferLockFlags(rawValue: 0) /// The total of child counts. @@ -42,11 +43,12 @@ public final class Screen: ScreenObjectContainerConvertible { } /// Specifies the video size to use when output a video. - public var size: CGSize = .init(width: 1280, height: 720) { + public var size: CGSize = Screen.size { didSet { guard size != oldValue else { return } + renderer.bounds = .init(origin: .zero, size: size) CVPixelBufferPoolCreate(nil, nil, attributes as CFDictionary?, &pixelBufferPool) } } diff --git a/Sources/Screen/ScreenObject.swift b/Sources/Screen/ScreenObject.swift index 83c2e6c65..26e65c0fd 100644 --- a/Sources/Screen/ScreenObject.swift +++ b/Sources/Screen/ScreenObject.swift @@ -153,22 +153,46 @@ public final class ImageScreenObject: ScreenObject { guard cgImage != oldValue else { return } - if let cgImage { - size = cgImage.size - } invalidateLayout() } } override public func makeImage(_ renderer: some ScreenRenderer) -> CGImage? { - return cgImage + let intersection = bounds.intersection(renderer.bounds) + + guard bounds != intersection else { + return cgImage + } + + // Handling when the drawing area is exceeded. + let x: CGFloat + switch horizontalAlignment { + case .left: + x = bounds.origin.x + case .center: + x = bounds.origin.x / 2 + case .right: + x = 0.0 + } + + let y: CGFloat + switch verticalAlignment { + case .top: + y = 0.0 + case .middle: + y = abs(bounds.origin.y) / 2 + case .bottom: + y = abs(bounds.origin.y) + } + + return cgImage?.cropping(to: .init(origin: .init(x: x, y: y), size: intersection.size)) } override public func makeBounds(_ size: CGSize) -> CGRect { guard let cgImage else { - return super.makeBounds(self.size) + return super.makeBounds(size) } - return super.makeBounds(cgImage.size) + return super.makeBounds(size == .zero ? cgImage.size : size) } } diff --git a/Sources/Screen/ScreenRenderer.swift b/Sources/Screen/ScreenRenderer.swift index 3d0f5e6b8..ba5315e06 100644 --- a/Sources/Screen/ScreenRenderer.swift +++ b/Sources/Screen/ScreenRenderer.swift @@ -9,6 +9,8 @@ public protocol ScreenRenderer: AnyObject { var context: CIContext { get } /// Specifies the backgroundColor for output video. var backgroundColor: CGColor { get set } + /// The current screen bounds. + var bounds: CGRect { get } /// Layouts a screen object. func layout(_ screenObject: ScreenObject) /// Draws a sceen object. @@ -18,6 +20,8 @@ public protocol ScreenRenderer: AnyObject { } final class ScreenRendererByCPU: ScreenRenderer { + var bounds: CGRect = .init(origin: .zero, size: Screen.size) + lazy var context = { guard let deive = MTLCreateSystemDefaultDevice() else { return CIContext(options: nil) @@ -142,7 +146,8 @@ final class ScreenRendererByCPU: ScreenRenderer { } let origin = screenObject.bounds.origin - let start = Int(origin.y) * canvas.rowBytes + Int(origin.x) * 4 + let start = Int(max(0, origin.y)) * canvas.rowBytes + Int(max(0, origin.x)) * 4 + var destination = vImage_Buffer( data: canvas.data.advanced(by: start), height: image.height,