Skip to content

Commit ea8180c

Browse files
committed
Use NSImageRep instead of NSImage
1 parent 29fa39d commit ea8180c

File tree

5 files changed

+46
-52
lines changed

5 files changed

+46
-52
lines changed

Plug-Ins/Image Editor/ImageWindowController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ class ImageWindowController: AbstractEditor, ResourceEditor, PreviewProvider, Ex
206206

207207
@IBAction func paste(_ sender: Any) {
208208
guard imageView.isEditable,
209-
let image = NSPasteboard.general.readObjects(forClasses: [NSImage.self])?.first as? NSImage
209+
let image = NSImage(pasteboard: .general)
210210
else {
211211
return
212212
}

Plug-Ins/NovaTools/Sprite Editor/Sprite.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ protocol WriteableSprite: Sprite {
2323
// Init for writing
2424
init(width: Int, height: Int, count: Int)
2525

26-
func writeSheet(_ image: NSImage, dither: Bool) -> [NSBitmapImageRep]
26+
func writeSheet(_ rep: NSImageRep, dither: Bool) -> [NSBitmapImageRep]
2727

28-
func writeFrames(_ images: [NSImage], dither: Bool) -> [NSBitmapImageRep]
28+
func writeFrames(_ reps: [NSImageRep], dither: Bool) -> [NSBitmapImageRep]
2929
}
3030

3131
// Utility functions helpful for implementers

Plug-Ins/NovaTools/Sprite Editor/SpriteImporter.swift

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ class SpriteImporter: NSObject, NSOpenSavePanelDelegate {
4141
}
4242
}
4343
@objc dynamic private var directory = true
44-
private var image: NSImage?
45-
private var images: [NSImage]?
44+
private var image: NSImageRep?
45+
private var images: [NSImageRep]?
4646

4747
override init() {
4848
gridX = Self.GRID_X
@@ -51,8 +51,8 @@ class SpriteImporter: NSObject, NSOpenSavePanelDelegate {
5151
}
5252

5353
func beginSheetModal(for window: NSWindow,
54-
sheetCallback: @escaping(NSImage, Int, Int, Bool) -> Void,
55-
framesCallback: @escaping([NSImage], Bool) -> Void) {
54+
sheetCallback: @escaping(NSImageRep, Int, Int, Bool) -> Void,
55+
framesCallback: @escaping([NSImageRep], Bool) -> Void) {
5656
self.reset()
5757
let panel = NSOpenPanel()
5858
panel.allowedFileTypes = ["public.image"]
@@ -74,8 +74,8 @@ class SpriteImporter: NSObject, NSOpenSavePanelDelegate {
7474
}
7575

7676
func beginSheetModal(for window: NSWindow,
77-
with image: NSImage,
78-
sheetCallback: @escaping(NSImage, Int, Int, Bool) -> Void) {
77+
with image: NSImageRep,
78+
sheetCallback: @escaping(NSImageRep, Int, Int, Bool) -> Void) {
7979
self.setImage(image)
8080
self.updateGrid()
8181
// The width of the options view will change when used in the open panel - reset it to an appropriate value
@@ -85,7 +85,9 @@ class SpriteImporter: NSObject, NSOpenSavePanelDelegate {
8585
alert.accessoryView = optionsView
8686
if #available(macOS 11, *) {
8787
// We don't really want an icon but the alert necessarily has one - on macOS 11 we can use the given image
88-
alert.icon = image
88+
let icon = NSImage(size: image.size)
89+
icon.addRepresentation(image)
90+
alert.icon = icon
8991
alert.messageText = ""
9092
} else {
9193
// On older systems the default app icon works better but we do need a title
@@ -107,13 +109,8 @@ class SpriteImporter: NSObject, NSOpenSavePanelDelegate {
107109
func panel(_ sender: Any, validate url: URL) throws {
108110
if directory {
109111
var items = try FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)
110-
items.sort(by: { $0.path.localizedStandardCompare($1.path) == .orderedAscending })
111-
var images: [NSImage] = []
112-
for item in items {
113-
if let image = NSImage(contentsOf: item), image.isValid {
114-
images.append(image)
115-
}
116-
}
112+
items.sort { $0.path.localizedStandardCompare($1.path) == .orderedAscending }
113+
let images = items.compactMap(NSImageRep.init)
117114
guard !images.isEmpty else {
118115
throw SpriteImporterError.noImages
119116
}
@@ -122,10 +119,10 @@ class SpriteImporter: NSObject, NSOpenSavePanelDelegate {
122119
guard let image else {
123120
throw SpriteImporterError.unsupportedFile
124121
}
125-
guard gridX > 0, image.representations[0].pixelsWide % gridX == 0 else {
122+
guard image.pixelsWide.isMultiple(of: gridX) else {
126123
throw SpriteImporterError.invalidX(gridX)
127124
}
128-
guard gridY > 0, image.representations[0].pixelsHigh % gridY == 0 else {
125+
guard image.pixelsHigh.isMultiple(of: gridY) else {
129126
throw SpriteImporterError.invalidY(gridY)
130127
}
131128
}
@@ -138,7 +135,7 @@ class SpriteImporter: NSObject, NSOpenSavePanelDelegate {
138135
if (try? url.resourceValues(forKeys: [.isDirectoryKey]).isDirectory) == true {
139136
panel.prompt = NSLocalizedString("Import Folder", comment: "")
140137
} else {
141-
self.setImage(NSImage(contentsOf: url))
138+
self.setImage(NSImageRep(contentsOf: url))
142139
panel.prompt = NSLocalizedString("Import Image", comment: "")
143140
}
144141
}
@@ -151,19 +148,19 @@ class SpriteImporter: NSObject, NSOpenSavePanelDelegate {
151148
preview.image = nil
152149
return
153150
}
154-
let width = image.representations[0].pixelsWide
155-
let height = image.representations[0].pixelsHigh
156-
guard gridX > 0, width % gridX == 0, gridY > 0, height % gridY == 0 else {
151+
let width = image.pixelsWide
152+
let height = image.pixelsHigh
153+
guard width.isMultiple(of: gridX), height.isMultiple(of: gridY) else {
157154
frameSize.stringValue = "grid mismatch"
158155
preview.image = nil
159156
return
160157
}
161158
frameSize.stringValue = "\(width/gridX) x \(height/gridY)"
162-
let size = NSSize(width: image.size.width/CGFloat(gridX), height: image.size.height/CGFloat(gridY))
163-
preview.image = NSImage(size: size)
164-
preview.image?.lockFocus()
165-
image.draw(at: .zero, from: NSRect(x: 0, y: image.size.height-size.height, width: size.width, height: size.height), operation: .copy, fraction: 1)
166-
preview.image?.unlockFocus()
159+
let size = NSSize(width: width/gridX, height: height/gridY)
160+
preview.image = NSImage(size: size, flipped: false) { rect in
161+
let srcRect = NSRect(x: 0, y: image.size.height-size.height, width: size.width, height: size.height)
162+
return image.draw(in: rect, from: srcRect, operation: .copy, fraction: 1, respectFlipped: true, hints: nil)
163+
}
167164
}
168165

169166
private func reset() {
@@ -175,16 +172,16 @@ class SpriteImporter: NSObject, NSOpenSavePanelDelegate {
175172
preview.image = nil
176173
}
177174

178-
private func setImage(_ image: NSImage?) {
175+
private func setImage(_ image: NSImageRep?) {
179176
directory = false
180177
guard let image,
181-
let rep = image.representations.first,
182-
rep.pixelsWide > 0 && rep.pixelsHigh > 0
178+
image.pixelsWide > 0 && image.pixelsHigh > 0
183179
else {
184180
imageSize.stringValue = "unsupported"
185181
return
186182
}
183+
image.size = NSSize(width: image.pixelsWide, height: image.pixelsHigh)
187184
self.image = image
188-
imageSize.stringValue = "\(rep.pixelsWide) x \(rep.pixelsHigh)"
185+
imageSize.stringValue = "\(image.pixelsWide) x \(image.pixelsHigh)"
189186
}
190187
}

Plug-Ins/NovaTools/Sprite Editor/SpriteWindowController.swift

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class SpriteWindowController: AbstractEditor, ResourceEditor, PreviewProvider, E
99
]
1010

1111
let resource: Resource
12-
private var sprite: Sprite!
12+
private var sprite: Sprite?
1313
private var frames: [NSBitmapImageRep] = []
1414
private var currentFrame = 0
1515
private var timer: Timer?
@@ -86,7 +86,8 @@ class SpriteWindowController: AbstractEditor, ResourceEditor, PreviewProvider, E
8686
}
8787
if !resource.data.isEmpty {
8888
do {
89-
sprite = try spriteType.init(resource.data)
89+
let sprite = try spriteType.init(resource.data)
90+
self.sprite = sprite
9091
for _ in 0..<sprite.frameCount {
9192
frames.append(try sprite.readFrame())
9293
}
@@ -100,8 +101,8 @@ class SpriteWindowController: AbstractEditor, ResourceEditor, PreviewProvider, E
100101
return
101102
}
102103
currentFrame = (currentFrame + 1) % frames.count
103-
if !image.representations.isEmpty {
104-
image.removeRepresentation(image.representations[0])
104+
if let rep = image.representations.first {
105+
image.removeRepresentation(rep)
105106
}
106107
image.addRepresentation(frames[currentFrame])
107108
image.size = frames[currentFrame].size
@@ -111,7 +112,7 @@ class SpriteWindowController: AbstractEditor, ResourceEditor, PreviewProvider, E
111112

112113
private func updateView() {
113114
playing = false
114-
if !frames.isEmpty {
115+
if let sprite, !frames.isEmpty {
115116
// Shrink the window
116117
window?.setContentSize(window!.contentMinSize)
117118
// Expand to fit
@@ -163,33 +164,31 @@ class SpriteWindowController: AbstractEditor, ResourceEditor, PreviewProvider, E
163164

164165
@IBAction func paste(_ sender: Any) {
165166
guard writeableType != nil,
166-
let image = NSPasteboard.general.readObjects(forClasses: [NSImage.self])?.first as? NSImage
167+
let rep = NSImageRep(pasteboard: .general)
167168
else {
168169
return
169170
}
170-
importPanel.beginSheetModal(for: window!, with: image, sheetCallback: self.importSheet)
171+
importPanel.beginSheetModal(for: window!, with: rep, sheetCallback: self.importSheet)
171172
}
172173

173-
private func importSheet(image: NSImage, gridX: Int, gridY: Int, dither: Bool) {
174+
private func importSheet(rep: NSImageRep, gridX: Int, gridY: Int, dither: Bool) {
174175
guard let writeableType else {
175176
return
176177
}
177-
let rep = image.representations[0]
178178
let newSprite = writeableType.init(width: rep.pixelsWide / gridX, height: rep.pixelsHigh / gridY, count: gridX * gridY)
179179
sprite = newSprite
180-
frames = newSprite.writeSheet(image, dither: dither)
180+
frames = newSprite.writeSheet(rep, dither: dither)
181181
self.updateView()
182182
self.setDocumentEdited(true)
183183
}
184184

185-
private func importFrames(images: [NSImage], dither: Bool) {
186-
guard let writeableType else {
185+
private func importFrames(reps: [NSImageRep], dither: Bool) {
186+
guard let writeableType, let rep = reps.first else {
187187
return
188188
}
189-
let rep = images[0].representations[0]
190-
let newSprite = writeableType.init(width: rep.pixelsWide, height: rep.pixelsHigh, count: images.count)
189+
let newSprite = writeableType.init(width: rep.pixelsWide, height: rep.pixelsHigh, count: reps.count)
191190
sprite = newSprite
192-
frames = newSprite.writeFrames(images, dither: dither)
191+
frames = newSprite.writeFrames(reps, dither: dither)
193192
self.updateView()
194193
self.setDocumentEdited(true)
195194
}

Plug-Ins/NovaTools/Sprite Editor/SpriteWorld.swift

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,7 @@ class SpriteWorld: WriteableSprite {
127127
}
128128
}
129129

130-
func writeSheet(_ image: NSImage, dither: Bool = false) -> [NSBitmapImageRep] {
131-
let rep = image.representations[0]
130+
func writeSheet(_ rep: NSImageRep, dither: Bool = false) -> [NSBitmapImageRep] {
132131
// Reset the resolution
133132
rep.size = NSSize(width: rep.pixelsWide, height: rep.pixelsHigh)
134133
let gridX = rep.pixelsWide / frameWidth
@@ -150,10 +149,9 @@ class SpriteWorld: WriteableSprite {
150149
return frames
151150
}
152151

153-
func writeFrames(_ images: [NSImage], dither: Bool = false) -> [NSBitmapImageRep] {
152+
func writeFrames(_ reps: [NSImageRep], dither: Bool = false) -> [NSBitmapImageRep] {
154153
var frames: [NSBitmapImageRep] = []
155-
for image in images {
156-
let rep = image.representations[0]
154+
for rep in reps {
157155
// Reset the resolution
158156
rep.size = NSSize(width: rep.pixelsWide, height: rep.pixelsHigh)
159157
let frame = self.newFrame()

0 commit comments

Comments
 (0)