From cea81a2221858d634ae6ae5632e370c898b46b24 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Wed, 15 Jun 2022 10:58:30 -0400 Subject: [PATCH] Move class extensions into their own file --- SilicaViewer.xcodeproj/project.pbxproj | 4 + SilicaViewer/AppDelegate.swift | 33 ------- SilicaViewer/Document.swift | 82 ---------------- SilicaViewer/ExportAccessoryView.swift | 10 -- SilicaViewer/Extensions.swift | 124 +++++++++++++++++++++++++ 5 files changed, 128 insertions(+), 125 deletions(-) create mode 100644 SilicaViewer/Extensions.swift diff --git a/SilicaViewer.xcodeproj/project.pbxproj b/SilicaViewer.xcodeproj/project.pbxproj index 53529a9..77d7a48 100644 --- a/SilicaViewer.xcodeproj/project.pbxproj +++ b/SilicaViewer.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 030F700E2415C6B500A43F01 /* PreviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 030F700D2415C6B500A43F01 /* PreviewViewController.swift */; }; 030F70112415C6B500A43F01 /* PreviewViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 030F700F2415C6B500A43F01 /* PreviewViewController.xib */; }; 030F70162415C6B500A43F01 /* QuickLook.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 030F70082415C6B500A43F01 /* QuickLook.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 03328514285A2AB700AEEBF3 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03328513285A2AB700AEEBF3 /* Extensions.swift */; }; 035D1A0426F0927200B332BE /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035D19F826F0927200B332BE /* ViewController.swift */; }; 035D1A0526F0927200B332BE /* cbridge.c in Sources */ = {isa = PBXBuildFile; fileRef = 035D19FA26F0927200B332BE /* cbridge.c */; }; 035D1A0626F0927200B332BE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 035D19FB26F0927200B332BE /* Assets.xcassets */; }; @@ -101,6 +102,7 @@ 030F70102415C6B500A43F01 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/PreviewViewController.xib; sourceTree = ""; }; 030F70122415C6B500A43F01 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 030F70132415C6B500A43F01 /* Quicklook.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Quicklook.entitlements; sourceTree = ""; }; + 03328513285A2AB700AEEBF3 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; 035D19F826F0927200B332BE /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 035D19F926F0927200B332BE /* SilicaViewer.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = SilicaViewer.entitlements; sourceTree = ""; }; 035D19FA26F0927200B332BE /* cbridge.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cbridge.c; sourceTree = ""; }; @@ -245,6 +247,7 @@ 035D1A0326F0927200B332BE /* Info.plist */, 0371996627BACD8700EE1DFD /* ExportAccessoryView.xib */, 0371996827BACDE800EE1DFD /* ExportAccessoryView.swift */, + 03328513285A2AB700AEEBF3 /* Extensions.swift */, ); path = SilicaViewer; sourceTree = ""; @@ -509,6 +512,7 @@ buildActionMask = 2147483647; files = ( 035D1A0A26F0927200B332BE /* AppDelegate.swift in Sources */, + 03328514285A2AB700AEEBF3 /* Extensions.swift in Sources */, 035D1A0B26F0927200B332BE /* TimelapseViewController.swift in Sources */, 035D1A0426F0927200B332BE /* ViewController.swift in Sources */, 035D1A0526F0927200B332BE /* cbridge.c in Sources */, diff --git a/SilicaViewer/AppDelegate.swift b/SilicaViewer/AppDelegate.swift index 9eaceb5..fcdc6b2 100644 --- a/SilicaViewer/AppDelegate.swift +++ b/SilicaViewer/AppDelegate.swift @@ -305,36 +305,3 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations { } } } - -extension CGImage { - // we really only handle 90 degree turns, which is totally fine - func rotate(angle : CGFloat, flipHorizontally : Bool, flipVertically : Bool) -> CGImage? { - let newWidth: CGFloat = CGFloat(height) - let newHeight: CGFloat = CGFloat(width) - - let ctx = CGContext(data: nil, - width: Int(newWidth), - height: Int(newHeight), - bitsPerComponent: bitsPerComponent, - bytesPerRow: bytesPerRow, - space: colorSpace!, - bitmapInfo: bitmapInfo.rawValue)! - - ctx.translateBy(x: newWidth / 2, y: newHeight / 2) - ctx.rotate(by: -angle) - - if flipVertically { - ctx.scaleBy(x: 1.0, y: -1.0) - } - - if flipHorizontally { - ctx.scaleBy(x: -1.0, y: 1.0) - } - - let dstRect = CGRect(x: -width / 2, y: -height / 2, width: width, height: height) - ctx.draw(self, in: dstRect) - - return ctx.makeImage() - } -} - diff --git a/SilicaViewer/Document.swift b/SilicaViewer/Document.swift index a847a99..e64aa27 100644 --- a/SilicaViewer/Document.swift +++ b/SilicaViewer/Document.swift @@ -806,85 +806,3 @@ class Document: NSDocument { return NSImage(data: thumbnailData) } } - -public extension NSImage { - func imageRotatedByDegreess(degrees:CGFloat) -> NSImage { - var imageBounds = NSMakeRect(0.0, 0.0, size.width, size.height) - - let pathBounds = NSBezierPath(rect: imageBounds) - var transform = NSAffineTransform() - transform.rotate(byDegrees: degrees) - pathBounds.transform(using: transform as AffineTransform) - - let rotatedBounds:NSRect = NSMakeRect(NSZeroPoint.x, NSZeroPoint.y, pathBounds.bounds.size.width, pathBounds.bounds.size.height ) - let rotatedImage = NSImage(size: rotatedBounds.size) - - imageBounds.origin.x = NSMidX(rotatedBounds) - (NSWidth(imageBounds) / 2) - imageBounds.origin.y = NSMidY(rotatedBounds) - (NSHeight(imageBounds) / 2) - - transform = NSAffineTransform() - transform.translateX(by: +(NSWidth(rotatedBounds) / 2 ), yBy: +(NSHeight(rotatedBounds) / 2)) - transform.rotate(byDegrees: degrees) - transform.translateX(by: -(NSWidth(rotatedBounds) / 2 ), yBy: -(NSHeight(rotatedBounds) / 2)) - - rotatedImage.lockFocus() - transform.concat() - - self.draw(in: imageBounds, from: .zero, operation: .copy, fraction: 1.0) - - rotatedImage.unlockFocus() - - return rotatedImage - } - - func flipHorizontally() -> NSImage { - let flipedImage = NSImage(size: size) - flipedImage.lockFocus() - - let transform = NSAffineTransform() - transform.translateX(by: size.width, yBy: 0.0) - transform.scaleX(by: -1.0, yBy: 1.0) - transform.concat() - - let rect = NSMakeRect(0, 0, size.width, size.height) - self.draw(at: .zero, from: rect, operation: .sourceOver, fraction: 1.0) - - flipedImage.unlockFocus() - - return flipedImage - } - - func flipVertically() -> NSImage { - let flipedImage = NSImage(size: size) - flipedImage.lockFocus() - - let transform = NSAffineTransform() - transform.translateX(by: 0.0, yBy: size.height) - transform.scaleX(by: 1.0, yBy: -1.0) - transform.concat() - - let rect = NSMakeRect(0, 0, size.width, size.height) - self.draw(at: .zero, from: rect, operation: .sourceOver, fraction: 1.0) - - flipedImage.unlockFocus() - - return flipedImage - } -} - -extension CGImage { - func toGrayscale() -> CGImage? { - let rect = CGRect(x: 0, y: 0, width: width, height: height) - let grayColorSpace = CGColorSpaceCreateDeviceGray() - let maskBitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue).union(.byteOrder16Big) - - let ccgContext = CGContext(data: nil, width: width, height: height, bitsPerComponent: 16, bytesPerRow: width * 2, space: grayColorSpace, bitmapInfo: maskBitmapInfo.rawValue) - - ccgContext?.setFillColor(.black) - ccgContext?.fill(rect) - - ccgContext?.draw(self, in: rect) - - return ccgContext?.makeImage() - } -} diff --git a/SilicaViewer/ExportAccessoryView.swift b/SilicaViewer/ExportAccessoryView.swift index e4303d1..d779524 100644 --- a/SilicaViewer/ExportAccessoryView.swift +++ b/SilicaViewer/ExportAccessoryView.swift @@ -22,13 +22,3 @@ class ExportAccessoryView : NSView { savePanel?.allowedFileTypes?.append((typeBox.titleOfSelectedItem?.lowercased())!) } } - -extension NSView { - class func fromNib() -> T? { - var topLevelObjects : NSArray? - guard Bundle.main.loadNibNamed("\(self)", owner: nil, topLevelObjects: &topLevelObjects) else { - return nil - } - return topLevelObjects!.first(where: { $0 is T }) as? T - } -} diff --git a/SilicaViewer/Extensions.swift b/SilicaViewer/Extensions.swift new file mode 100644 index 0000000..47c4109 --- /dev/null +++ b/SilicaViewer/Extensions.swift @@ -0,0 +1,124 @@ +import Foundation +import AppKit + +extension CGImage { + func toGrayscale() -> CGImage? { + let rect = CGRect(x: 0, y: 0, width: width, height: height) + let grayColorSpace = CGColorSpaceCreateDeviceGray() + let maskBitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue).union(.byteOrder16Big) + + let ccgContext = CGContext(data: nil, width: width, height: height, bitsPerComponent: 16, bytesPerRow: width * 2, space: grayColorSpace, bitmapInfo: maskBitmapInfo.rawValue) + + ccgContext?.setFillColor(.black) + ccgContext?.fill(rect) + + ccgContext?.draw(self, in: rect) + + return ccgContext?.makeImage() + } + + // we really only handle 90 degree turns, which is totally fine + func rotate(angle : CGFloat, flipHorizontally : Bool, flipVertically : Bool) -> CGImage? { + let newWidth: CGFloat = CGFloat(height) + let newHeight: CGFloat = CGFloat(width) + + let ctx = CGContext(data: nil, + width: Int(newWidth), + height: Int(newHeight), + bitsPerComponent: bitsPerComponent, + bytesPerRow: bytesPerRow, + space: colorSpace!, + bitmapInfo: bitmapInfo.rawValue)! + + ctx.translateBy(x: newWidth / 2, y: newHeight / 2) + ctx.rotate(by: -angle) + + if flipVertically { + ctx.scaleBy(x: 1.0, y: -1.0) + } + + if flipHorizontally { + ctx.scaleBy(x: -1.0, y: 1.0) + } + + let dstRect = CGRect(x: -width / 2, y: -height / 2, width: width, height: height) + ctx.draw(self, in: dstRect) + + return ctx.makeImage() + } +} + +extension NSImage { + func imageRotatedByDegreess(degrees:CGFloat) -> NSImage { + var imageBounds = NSMakeRect(0.0, 0.0, size.width, size.height) + + let pathBounds = NSBezierPath(rect: imageBounds) + var transform = NSAffineTransform() + transform.rotate(byDegrees: degrees) + pathBounds.transform(using: transform as AffineTransform) + + let rotatedBounds:NSRect = NSMakeRect(NSZeroPoint.x, NSZeroPoint.y, pathBounds.bounds.size.width, pathBounds.bounds.size.height ) + let rotatedImage = NSImage(size: rotatedBounds.size) + + imageBounds.origin.x = NSMidX(rotatedBounds) - (NSWidth(imageBounds) / 2) + imageBounds.origin.y = NSMidY(rotatedBounds) - (NSHeight(imageBounds) / 2) + + transform = NSAffineTransform() + transform.translateX(by: +(NSWidth(rotatedBounds) / 2 ), yBy: +(NSHeight(rotatedBounds) / 2)) + transform.rotate(byDegrees: degrees) + transform.translateX(by: -(NSWidth(rotatedBounds) / 2 ), yBy: -(NSHeight(rotatedBounds) / 2)) + + rotatedImage.lockFocus() + transform.concat() + + self.draw(in: imageBounds, from: .zero, operation: .copy, fraction: 1.0) + + rotatedImage.unlockFocus() + + return rotatedImage + } + + func flipHorizontally() -> NSImage { + let flipedImage = NSImage(size: size) + flipedImage.lockFocus() + + let transform = NSAffineTransform() + transform.translateX(by: size.width, yBy: 0.0) + transform.scaleX(by: -1.0, yBy: 1.0) + transform.concat() + + let rect = NSMakeRect(0, 0, size.width, size.height) + self.draw(at: .zero, from: rect, operation: .sourceOver, fraction: 1.0) + + flipedImage.unlockFocus() + + return flipedImage + } + + func flipVertically() -> NSImage { + let flipedImage = NSImage(size: size) + flipedImage.lockFocus() + + let transform = NSAffineTransform() + transform.translateX(by: 0.0, yBy: size.height) + transform.scaleX(by: 1.0, yBy: -1.0) + transform.concat() + + let rect = NSMakeRect(0, 0, size.width, size.height) + self.draw(at: .zero, from: rect, operation: .sourceOver, fraction: 1.0) + + flipedImage.unlockFocus() + + return flipedImage + } +} + +extension NSView { + class func fromNib() -> T? { + var topLevelObjects : NSArray? + guard Bundle.main.loadNibNamed("\(self)", owner: nil, topLevelObjects: &topLevelObjects) else { + return nil + } + return topLevelObjects!.first(where: { $0 is T }) as? T + } +}