Add composite image rendering
This commit is contained in:
parent
2134cbc6a8
commit
39a0de2c75
3 changed files with 84 additions and 18 deletions
|
@ -246,13 +246,16 @@ DQ
|
|||
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ipM-NH-wUM">
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ipM-NH-wUM">
|
||||
<rect key="frame" x="20" y="20" width="440" height="201"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="chN-IE-x52"/>
|
||||
</imageView>
|
||||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ifc-N4-GCF">
|
||||
<popUpButton verticalHuggingPriority="750" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ifc-N4-GCF">
|
||||
<rect key="frame" x="18" y="226" width="101" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="96" id="Csg-An-ug2"/>
|
||||
</constraints>
|
||||
<popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="P5l-BO-Pd1">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
|
@ -262,9 +265,11 @@ DQ
|
|||
<action selector="selectLayerAction:" target="5gI-5U-AMq" id="nzQ-6F-mUw"/>
|
||||
</connections>
|
||||
</popUpButton>
|
||||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="vY4-dQ-JOJ">
|
||||
<popUpButton verticalHuggingPriority="750" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="vY4-dQ-JOJ">
|
||||
<rect key="frame" x="122" y="226" width="101" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="96" id="FeE-01-aTL"/>
|
||||
</constraints>
|
||||
<popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="IVG-g2-g5C">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
|
@ -276,10 +281,9 @@ DQ
|
|||
</popUpButton>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="ipM-NH-wUM" secondAttribute="bottom" constant="20" symbolic="YES" id="9wh-iS-c9w"/>
|
||||
<constraint firstAttribute="trailing" secondItem="ipM-NH-wUM" secondAttribute="trailing" constant="20" symbolic="YES" id="H7s-2P-Zaq"/>
|
||||
<constraint firstItem="ipM-NH-wUM" firstAttribute="leading" secondItem="ERx-hH-rdd" secondAttribute="leading" constant="20" symbolic="YES" id="aib-B6-dBu"/>
|
||||
<constraint firstItem="ipM-NH-wUM" firstAttribute="top" secondItem="ERx-hH-rdd" secondAttribute="top" constant="20" symbolic="YES" id="xk9-1v-JRt"/>
|
||||
<constraint firstItem="Ifc-N4-GCF" firstAttribute="top" secondItem="ERx-hH-rdd" secondAttribute="top" constant="20" symbolic="YES" id="BmT-9r-weG"/>
|
||||
<constraint firstItem="vY4-dQ-JOJ" firstAttribute="leading" secondItem="Ifc-N4-GCF" secondAttribute="trailing" constant="8" symbolic="YES" id="hgm-Np-cYB"/>
|
||||
<constraint firstItem="vY4-dQ-JOJ" firstAttribute="baseline" secondItem="Ifc-N4-GCF" secondAttribute="baseline" id="uHT-fd-ze3"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
|
|
|
@ -2,14 +2,29 @@ import Cocoa
|
|||
import ZIPFoundation
|
||||
import CoreFoundation
|
||||
|
||||
struct SilicaChunk {
|
||||
init() {
|
||||
x = 0
|
||||
y = 0
|
||||
image = NSImage()
|
||||
}
|
||||
|
||||
var x: Int
|
||||
var y: Int
|
||||
var image: NSImage
|
||||
}
|
||||
|
||||
struct SilicaLayer {
|
||||
var chunks: [NSImage] = []
|
||||
var chunks: [SilicaChunk] = []
|
||||
}
|
||||
|
||||
struct SilicaDocument {
|
||||
var trackedTime: Int = 0
|
||||
var tileSize: Int = 0
|
||||
|
||||
var width: Int = 0
|
||||
var height: Int = 0
|
||||
|
||||
var layers: [SilicaLayer] = []
|
||||
}
|
||||
|
||||
|
@ -27,6 +42,7 @@ class Document: NSDocument {
|
|||
let TrackedTimeKey = "SilicaDocumentTrackedTimeKey"
|
||||
let LayersKey = "layers"
|
||||
let TileSizeKey = "tileSize"
|
||||
let SizeKey = "size"
|
||||
|
||||
let LayerClassName = "SilicaLayer"
|
||||
|
||||
|
@ -78,11 +94,20 @@ class Document: NSDocument {
|
|||
}
|
||||
}
|
||||
|
||||
layer.chunks = Array(repeating: NSImage(), count: chunkPaths.count)
|
||||
layer.chunks = Array(repeating: SilicaChunk(), count: chunkPaths.count)
|
||||
|
||||
DispatchQueue.concurrentPerform(iterations: chunkPaths.count) { (i: Int) in
|
||||
let entry = chunkPaths[i]
|
||||
|
||||
let pathURL = URL(fileURLWithPath: entry.path)
|
||||
let pathComponents = pathURL.lastPathComponent.replacingOccurrences(of: ".chunk", with: "").components(separatedBy: "~")
|
||||
|
||||
let x = Int(pathComponents[0])
|
||||
let y = Int(pathComponents[1])
|
||||
|
||||
layer.chunks[i].x = x!
|
||||
layer.chunks[i].y = y!
|
||||
|
||||
guard let archive = Archive(data: self.data!, accessMode: Archive.AccessMode.read) else {
|
||||
return
|
||||
}
|
||||
|
@ -109,15 +134,16 @@ class Document: NSDocument {
|
|||
|
||||
let render: CGColorRenderingIntent = CGColorRenderingIntent.defaultIntent
|
||||
let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue)
|
||||
.union(.byteOrder32Little)
|
||||
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.last.rawValue)
|
||||
.union(.byteOrder32Big)
|
||||
let providerRef: CGDataProvider? = CGDataProvider(data: image_data as CFData)
|
||||
|
||||
let cgimage: CGImage? = CGImage(width: info.tileSize, height: info.tileSize, bitsPerComponent: 8, bitsPerPixel: 32, bytesPerRow: info.tileSize * 4, space: rgbColorSpace, bitmapInfo: bitmapInfo, provider: providerRef!, decode: nil, shouldInterpolate: true, intent: render)
|
||||
let cgimage: CGImage? = CGImage(width: info.tileSize, height: info.tileSize, bitsPerComponent: 8, bitsPerPixel: 32, bytesPerRow: info.tileSize * 4, space: rgbColorSpace, bitmapInfo: bitmapInfo, provider: providerRef!, decode: nil, shouldInterpolate: false, intent: render)
|
||||
|
||||
if cgimage != nil {
|
||||
let image = NSImage(cgImage: cgimage!, size: NSZeroSize)
|
||||
|
||||
layer.chunks[i] = image
|
||||
layer.chunks[i].image = image
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,6 +158,17 @@ class Document: NSDocument {
|
|||
info.trackedTime = (dict[TrackedTimeKey] as! NSNumber).intValue
|
||||
info.tileSize = (dict[TileSizeKey] as! NSNumber).intValue
|
||||
|
||||
let sizeClassKey = dict[SizeKey]
|
||||
let sizeClassID = objectRefGetValue(sizeClassKey as CFTypeRef)
|
||||
let sizeString = objectsArray[Int(sizeClassID)] as! String
|
||||
|
||||
let sizeComponents = sizeString.replacingOccurrences(of: "{", with: "").replacingOccurrences(of: "}", with: "").components(separatedBy: ", ")
|
||||
let width = Int(sizeComponents[0])
|
||||
let height = Int(sizeComponents[1])
|
||||
|
||||
info.width = width!
|
||||
info.height = height!
|
||||
|
||||
let layersClassKey = dict[LayersKey]
|
||||
let layersClassID = objectRefGetValue(layersClassKey as CFTypeRef)
|
||||
let layersClass = objectsArray[Int(layersClassID)] as! NSDictionary
|
||||
|
@ -218,5 +255,30 @@ class Document: NSDocument {
|
|||
|
||||
parseDocument(archive: archive, dict: dict)
|
||||
}
|
||||
|
||||
func makeComposite() -> NSImage {
|
||||
let image = NSImage(size: NSSize(width: info.width, height: info.height))
|
||||
image.lockFocus()
|
||||
|
||||
let rows = Int(ceil(Float(info.height) / Float(info.tileSize)))
|
||||
|
||||
for layer in info.layers.reversed() {
|
||||
for chunk in layer.chunks {
|
||||
let x = chunk.x
|
||||
var y = chunk.y
|
||||
|
||||
if y == rows {
|
||||
y = 0
|
||||
}
|
||||
|
||||
let rect = NSRect(x: info.tileSize * x, y: info.height - (info.tileSize * y), width: info.tileSize, height: info.tileSize)
|
||||
|
||||
chunk.image.draw(in: rect)
|
||||
}
|
||||
}
|
||||
|
||||
image.unlockFocus()
|
||||
return image
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ class ViewController: NSViewController {
|
|||
func loadCanvas() {
|
||||
let document = self.view.window?.windowController?.document as? Document
|
||||
|
||||
imageView.image = document?.info.layers[selectedLayer].chunks[selectedChunk]
|
||||
imageView.image = document?.info.layers[selectedLayer].chunks[selectedChunk].image
|
||||
}
|
||||
|
||||
@IBAction func selectLayerAction(_ sender: Any) {
|
||||
|
@ -45,14 +45,14 @@ class ViewController: NSViewController {
|
|||
chunkPopup.removeAllItems()
|
||||
|
||||
for (i, chunk) in (document?.info.layers[selectedLayer].chunks.enumerated())! {
|
||||
chunkPopup.addItem(withTitle: "Chunk " + String(i))
|
||||
chunkPopup.addItem(withTitle: "Chunk " + String(chunk.x) + " " + String(chunk.y))
|
||||
}
|
||||
}
|
||||
|
||||
override func viewWillAppear() {
|
||||
let document = self.view.window?.windowController?.document as? Document
|
||||
|
||||
imageView.image = document?.thumbnail
|
||||
imageView.image = document?.makeComposite()
|
||||
|
||||
for (i, layer) in (document?.info.layers.enumerated())! {
|
||||
layerPopup.addItem(withTitle: "Layer " + String(i))
|
||||
|
|
Reference in a new issue