mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-04-22 01:18:36 +03:00
91 lines
3.2 KiB
Swift
91 lines
3.2 KiB
Swift
import Cocoa
|
|
|
|
extension NSImage {
|
|
/// Combine multiple images with the given blend modes. This is useful given a set
|
|
/// of layers to create a final rasterized image.
|
|
static func combine(images: [NSImage], blendingModes: [CGBlendMode]) -> NSImage? {
|
|
guard images.count == blendingModes.count else { return nil }
|
|
guard images.count > 0 else { return nil }
|
|
|
|
// The final size will be the same size as our first image.
|
|
let size = images.first!.size
|
|
|
|
// Create a bitmap context manually
|
|
guard let bitmapContext = CGContext(
|
|
data: nil,
|
|
width: Int(size.width),
|
|
height: Int(size.height),
|
|
bitsPerComponent: 8,
|
|
bytesPerRow: 0,
|
|
space: CGColorSpaceCreateDeviceRGB(),
|
|
bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue
|
|
) else { return nil }
|
|
|
|
// Clear the context
|
|
bitmapContext.setFillColor(.clear)
|
|
bitmapContext.fill(.init(origin: .zero, size: size))
|
|
|
|
// Draw each image with its corresponding blend mode
|
|
for (index, image) in images.enumerated() {
|
|
guard let cgImage = image.cgImage(
|
|
forProposedRect: nil,
|
|
context: nil,
|
|
hints: nil
|
|
) else { return nil }
|
|
|
|
let blendMode = blendingModes[index]
|
|
bitmapContext.setBlendMode(blendMode)
|
|
bitmapContext.draw(cgImage, in: CGRect(origin: .zero, size: size))
|
|
}
|
|
|
|
// Create a CGImage from the context
|
|
guard let combinedCGImage = bitmapContext.makeImage() else { return nil }
|
|
|
|
// Wrap the CGImage in an NSImage
|
|
return NSImage(cgImage: combinedCGImage, size: size)
|
|
}
|
|
|
|
/// Apply a gradient onto this image, using this image as a mask.
|
|
func gradient(colors: [NSColor]) -> NSImage? {
|
|
let resultImage = NSImage(size: size)
|
|
resultImage.lockFocus()
|
|
defer { resultImage.unlockFocus() }
|
|
|
|
// Draw the gradient
|
|
guard let gradient = NSGradient(colors: colors) else { return nil }
|
|
gradient.draw(in: .init(origin: .zero, size: size), angle: 90)
|
|
|
|
// Apply the mask
|
|
draw(at: .zero, from: .zero, operation: .destinationIn, fraction: 1.0)
|
|
|
|
return resultImage
|
|
}
|
|
|
|
// Tint an NSImage with the given color by applying a basic fill on top of it.
|
|
func tint(color: NSColor) -> NSImage? {
|
|
// Create a new image with the same size as the base image
|
|
let newImage = NSImage(size: size)
|
|
|
|
// Draw into the new image
|
|
newImage.lockFocus()
|
|
defer { newImage.unlockFocus() }
|
|
|
|
// Set up the drawing context
|
|
guard let context = NSGraphicsContext.current?.cgContext else { return nil }
|
|
defer { context.restoreGState() }
|
|
|
|
// Draw the base image
|
|
guard let cgImage = cgImage(forProposedRect: nil, context: nil, hints: nil) else { return nil }
|
|
context.draw(cgImage, in: .init(origin: .zero, size: size))
|
|
|
|
// Set the tint color and blend mode
|
|
context.setFillColor(color.cgColor)
|
|
context.setBlendMode(.sourceAtop)
|
|
|
|
// Apply the tint color over the entire image
|
|
context.fill(.init(origin: .zero, size: size))
|
|
|
|
return newImage
|
|
}
|
|
}
|