import Foundation /// Represents a image chunk struct SilicaChunk { var x: Int = 0 var y: Int = 0 var image: CGImage? } /// Supported Silica blend modes, including extended blend modes enum BlendMode : Int { case Normal = 0, Multiply = 1, Screen = 2, Add = 3, Lighten = 4, Exclusion = 5, Difference = 6, Subtract = 7, LinearBurn = 8, ColorDodge = 9, ColorBurn = 10, Overlay = 11, HardLight = 12, Color = 13, Luminosity = 14, Hue = 15, Saturation = 16, SoftLight = 17, // TODO: where is 18? Darken = 19, // extended modes HardMix = 20, VividLight = 21, LinearLight = 22, PinLight = 23, LighterColor = 24, DarkerColor = 25, Divide = 26 } /// Represents the image data for a Silica Layer, may not be an actual layer present to the user, such as a mask. struct SilicaLayerData { var blendMode: BlendMode = .Normal var chunks: [SilicaChunk] = [] var opacity: Double = 1.0 var hidden: Bool = false } /// A Silica Layer, which equates to a real layer present in the document struct SilicaLayer : Equatable { static func == (lhs: SilicaLayer, rhs: SilicaLayer) -> Bool { return lhs.name == rhs.name && lhs.clipped == rhs.clipped } var name: String = "" var data: SilicaLayerData = SilicaLayerData() var mask: SilicaLayerData? var clipped: Bool = false } /// Container for the Silica Document format struct SilicaDocument { var trackedTime: Int = 0 var tileSize: Int = 0 var orientation: Int = 0 var flippedHorizontally: Bool = false var flippedVertically: Bool = false var name: String = "" var authorName: String = "" var strokeCount: Int = 0 var backgroundColor: CGColor = .white var colorSpace: CGColorSpace = CGColorSpaceCreateDeviceRGB() var width: Int = 0 var height: Int = 0 var rows: Int = 0 var columns: Int = 0 var remainderWidth: Int = 0 var remainderHeight: Int = 0 var layers: [SilicaLayer] = [] var videoFrame: (Int, Int) = (0, 0) func nsSize() -> NSSize { return NSSize(width: width, height: height) } func cgSize() -> CGSize { return CGSize(width: width, height: height) } func cgRect() -> CGRect { return CGRect(origin: .zero, size: cgSize()) } /// Calculates the correct tile size, taking into account the remainder between tile size and image size. /// - Parameters: /// - x: The X position of the tile. /// - y: The Y position of the tile. /// - Returns: A tuple containing the correct tile size. func getTileSize(_ x: Int, _ y: Int) -> (Int, Int) { var tileWidth: Int = tileSize var tileHeight: Int = tileSize if((x + 1) == columns) { tileWidth -= remainderWidth } if(y == rows) { tileHeight -= remainderHeight } return (tileWidth, tileHeight) } /// Calculates a `NSRect` for a `SilicaChunk`. /// - Parameter chunk: The `SilicaChunk` to return a `NSRect` for. /// - Returns: A `NSRect` containg the rectangle for the chunk. func getChunkRect(_ chunk: SilicaChunk) -> NSRect { let x = chunk.x var y = chunk.y let (tileWidth, tileHeight) = getTileSize(x, y) if y == rows { y = 0 } return NSRect(x: tileSize * x, y: height - (tileSize * y), width: tileWidth, height: tileHeight) } }