From 5678c8231414e83d4b218cfc79ce08d34b6fe6db Mon Sep 17 00:00:00 2001 From: Patrick Kladek Date: Tue, 8 Feb 2022 13:36:52 +0400 Subject: [PATCH 1/4] Disable Alpha channel in exported images --- Screenshot Framer/Supporting Files/Code/SSFView.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Screenshot Framer/Supporting Files/Code/SSFView.swift b/Screenshot Framer/Supporting Files/Code/SSFView.swift index abb5ccf..13a2ab2 100644 --- a/Screenshot Framer/Supporting Files/Code/SSFView.swift +++ b/Screenshot Framer/Supporting Files/Code/SSFView.swift @@ -53,6 +53,7 @@ extension NSView { rep.size = imageSize rep.pixelsHigh = Int(imageSize.height) rep.pixelsWide = Int(imageSize.width) + rep.hasAlpha = false self.cacheDisplay(in: self.bounds, to: rep) return rep.representation(using: .png, properties: [:]) } From 87ebc6ae2ad1feeff0fb075bd465981440b4e1ef Mon Sep 17 00:00:00 2001 From: Patrick Kladek Date: Tue, 8 Feb 2022 14:07:09 +0400 Subject: [PATCH 2/4] fix cli export when no limits are set --- .../Help Controller/ExportController.swift | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Screenshot Framer/Document Window/Content View Controller/Help Controller/ExportController.swift b/Screenshot Framer/Document Window/Content View Controller/Help Controller/ExportController.swift index fe13714..ee00951 100644 --- a/Screenshot Framer/Document Window/Content View Controller/Help Controller/ExportController.swift +++ b/Screenshot Framer/Document Window/Content View Controller/Help Controller/ExportController.swift @@ -69,8 +69,25 @@ final class ExportController { for language in self.languageController.allLanguages(prefered: language) { viewStateController.newViewState(language: language) - guard let lower = self.lastLayerState.outputConfig.prefered(from: start) else { continue } - guard let upper = self.lastLayerState.outputConfig.prefered(end: end) else { continue } + + var lower: Int + var upper: Int + + if let start = start { + guard let _lower = self.lastLayerState.outputConfig.prefered(from: start) else { continue } // swiftlint:disable:this identifier_name + + lower = _lower + } else { + lower = self.lastLayerState.outputConfig.fromImageNumber + } + + if let end = end { + guard let _upper = self.lastLayerState.outputConfig.prefered(end: end) else { continue } // swiftlint:disable:this identifier_name + + upper = _upper + } else { + upper = self.lastLayerState.outputConfig.toImageNumber + } for index in lower...upper { viewStateController.newViewState(imageNumber: index) From b607d23914753178a6be583172b614afa4287656 Mon Sep 17 00:00:00 2001 From: Patrick Kladek Date: Tue, 8 Feb 2022 16:45:36 +0400 Subject: [PATCH 3/4] Add transparency to export options --- Screenshot Framer CLI/Export.swift | 5 +- .../ContentViewController.swift | 9 +- .../ContentViewController.xib | 82 +++++++++++-------- .../Help Controller/ExportController.swift | 16 ++-- Screenshot Framer/Model/LayerState.swift | 11 ++- .../Model/LayerStateHistory.swift | 3 +- Screenshot Framer/Model/Operations.swift | 18 ++++ Screenshot Framer/Model/OutputConfig.swift | 1 + .../Supporting Files/Code/SSFView.swift | 19 +---- 9 files changed, 99 insertions(+), 65 deletions(-) diff --git a/Screenshot Framer CLI/Export.swift b/Screenshot Framer CLI/Export.swift index 1721c75..b8b4aa4 100644 --- a/Screenshot Framer CLI/Export.swift +++ b/Screenshot Framer CLI/Export.swift @@ -81,7 +81,10 @@ extension Export { let fileCapsule = FileCapsule() fileCapsule.projectURL = project.deletingLastPathComponent() - guard let layerStateHistory = self.layerStateHistory(for: project) else { return } + guard let layerStateHistory = self.layerStateHistory(for: project) else { + ConsoleIO.writeMessage("Could not open file: \(project.lastPathComponent)", to: .error) + return + } let fileController = FileController(fileCapsule: fileCapsule) let languageController = LanguageController(fileCapsule: fileCapsule) diff --git a/Screenshot Framer/Document Window/Content View Controller/ContentViewController.swift b/Screenshot Framer/Document Window/Content View Controller/ContentViewController.swift index d7eb314..8ae8a75 100644 --- a/Screenshot Framer/Document Window/Content View Controller/ContentViewController.swift +++ b/Screenshot Framer/Document Window/Content View Controller/ContentViewController.swift @@ -37,6 +37,7 @@ final class ContentViewController: NSViewController, NSMenuItemValidation { @IBOutlet private var tableView: SSFTableView! @IBOutlet private var addMenu: NSMenu! @IBOutlet private var layoutWarningButton: NSButton! + @IBOutlet private var transparencyCheckbox: NSButton! @IBOutlet private var textFieldOutput: NSTextField! @IBOutlet private var textFieldFromImageNumber: NSTextField! @IBOutlet private var textFieldToImageNumber: NSTextField! @@ -183,7 +184,7 @@ final class ContentViewController: NSViewController, NSMenuItemValidation { } @IBAction func outputConfigDidChange(_ sender: AnyObject?) { - guard let sender = sender as? NSTextField else { return } + guard let sender = sender as? NSView else { return } switch sender { case self.textFieldOutput: @@ -209,6 +210,11 @@ final class ContentViewController: NSViewController, NSMenuItemValidation { let operation = UpdateToImageNuberOperation(layerStateHistory: self.layerStateHistory, toImageNumber: self.textFieldToImageNumber.integerValue) operation.apply() + case self.transparencyCheckbox: + let transparent = self.transparencyCheckbox.state == .on ? true : false + let operation = UpdateTransparencyOperation(layerStateHistory: self.layerStateHistory, transparent: transparent) + operation.apply() + default: return } @@ -303,6 +309,7 @@ final class ContentViewController: NSViewController, NSMenuItemValidation { self.scrollView.documentView = self.layoutController.layoutHierarchy(layers: self.lastLayerState.layers) self.layoutWarningButton.isHidden = self.layoutController.layoutErrors.isEmpty + self.transparencyCheckbox.state = self.lastLayerState.outputConfig.transparent ? .on : .off self.textFieldOutput.stringValue = self.lastLayerState.outputConfig.output self.textFieldFromImageNumber.integerValue = self.lastLayerState.outputConfig.fromImageNumber self.textFieldToImageNumber.integerValue = self.lastLayerState.outputConfig.toImageNumber diff --git a/Screenshot Framer/Document Window/Content View Controller/ContentViewController.xib b/Screenshot Framer/Document Window/Content View Controller/ContentViewController.xib index de4ec88..b5d7374 100644 --- a/Screenshot Framer/Document Window/Content View Controller/ContentViewController.xib +++ b/Screenshot Framer/Document Window/Content View Controller/ContentViewController.xib @@ -1,8 +1,8 @@ - + - + @@ -19,26 +19,27 @@ + - + - + - + - + - + @@ -48,30 +49,29 @@ - + - - + + - + - + - + - @@ -83,11 +83,11 @@ - + - + @@ -128,7 +128,7 @@ - + @@ -141,13 +141,13 @@ - + - + @@ -187,7 +187,7 @@ - + @@ -195,7 +195,7 @@ - + @@ -203,7 +203,7 @@ - + @@ -211,7 +211,7 @@ - + @@ -222,7 +222,7 @@ - + @@ -233,7 +233,7 @@ - + @@ -241,12 +241,12 @@ + + @@ -275,7 +286,7 @@ - + @@ -287,8 +298,9 @@ + - + @@ -329,12 +341,12 @@ - + - + - + diff --git a/Screenshot Framer/Document Window/Content View Controller/Help Controller/ExportController.swift b/Screenshot Framer/Document Window/Content View Controller/Help Controller/ExportController.swift index ee00951..68789a3 100644 --- a/Screenshot Framer/Document Window/Content View Controller/Help Controller/ExportController.swift +++ b/Screenshot Framer/Document Window/Content View Controller/Help Controller/ExportController.swift @@ -15,16 +15,18 @@ protocol ExportControllerDelegate: AnyObject { final class ExportController { + private var shouldCancel: Bool = false + // MARK: - Properties - private var shouldCancel: Bool = false let fileController: FileController let languageController: LanguageController let layerStateHistory: LayerStateHistory weak var delegate: ExportControllerDelegate? - var lastLayerState: LayerState { return self.layerStateHistory.currentLayerState } - + var lastLayerState: LayerState { + return self.layerStateHistory.currentLayerState + } // MARK: - Lifecycle @@ -49,7 +51,7 @@ final class ExportController { guard let url = self.fileController.outputURL(for: self.lastLayerState, viewState: viewState) else { return [.noOutputFile] } try? fileManager.createDirectory(at: url.deletingLastPathComponent(), withIntermediateDirectories: true, attributes: nil) - if let data = view.pngData() { + if let data = view.pngData(transparent: self.lastLayerState.outputConfig.transparent) { try? data.write(to: url, options: .atomic) } @@ -95,7 +97,7 @@ final class ExportController { guard let url = self.fileController.outputURL(for: self.lastLayerState, viewState: viewStateController.viewState) else { return [.noOutputFile] } try? fileManager.createDirectory(at: url.deletingLastPathComponent(), withIntermediateDirectories: true, attributes: nil) - if let data = view.pngData() { + if let data = view.pngData(transparent: self.lastLayerState.outputConfig.transparent) { try? data.write(to: url, options: .atomic) } @@ -136,7 +138,7 @@ final class ExportController { let tempURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("Preview \(name).png") do { - try view.pngData()?.write(to: tempURL) + try view.pngData(transparent: self.lastLayerState.outputConfig.transparent)?.write(to: tempURL) } catch { let alert = NSAlert(error: error) alert.runModal() @@ -173,7 +175,7 @@ final class ExportController { let tempURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("Preview Languages of \(name).png") do { - try view.pngData()?.write(to: tempURL) + try view.pngData(transparent: self.lastLayerState.outputConfig.transparent)?.write(to: tempURL) } catch { let alert = NSAlert(error: error) alert.runModal() diff --git a/Screenshot Framer/Model/LayerState.swift b/Screenshot Framer/Model/LayerState.swift index 6d7be67..7a66682 100644 --- a/Screenshot Framer/Model/LayerState.swift +++ b/Screenshot Framer/Model/LayerState.swift @@ -127,20 +127,25 @@ struct LayerState: Codable { // MARK: - Output Config func updating(output: String) -> LayerState { - let newConfig = OutputConfig(output: output, fromImageNumber: self.outputConfig.fromImageNumber, toImageNumber: self.outputConfig.toImageNumber) + let newConfig = OutputConfig(transparent: self.outputConfig.transparent, output: output, fromImageNumber: self.outputConfig.fromImageNumber, toImageNumber: self.outputConfig.toImageNumber) return LayerState(title: "Updating Export Output", layers: self.layers, outputConfig: newConfig) } func updating(fromImageNumber: Int) -> LayerState { - let newConfig = OutputConfig(output: self.outputConfig.output, fromImageNumber: fromImageNumber, toImageNumber: self.outputConfig.toImageNumber) + let newConfig = OutputConfig(transparent: self.outputConfig.transparent, output: self.outputConfig.output, fromImageNumber: fromImageNumber, toImageNumber: self.outputConfig.toImageNumber) return LayerState(title: "Updating Export From Image Number", layers: self.layers, outputConfig: newConfig) } func updating(toImageNumber: Int) -> LayerState { - let newConfig = OutputConfig(output: self.outputConfig.output, fromImageNumber: self.outputConfig.fromImageNumber, toImageNumber: toImageNumber) + let newConfig = OutputConfig(transparent: self.outputConfig.transparent, output: self.outputConfig.output, fromImageNumber: self.outputConfig.fromImageNumber, toImageNumber: toImageNumber) return LayerState(title: "Updating Export To Image Number", layers: self.layers, outputConfig: newConfig) } + func updating(transparency: Bool) -> LayerState { + let newConfig = OutputConfig(transparent: transparency, output: self.outputConfig.output, fromImageNumber: self.outputConfig.fromImageNumber, toImageNumber: self.outputConfig.toImageNumber) + return LayerState(title: "Updating Export Transparency", layers: self.layers, outputConfig: newConfig) + } + // MARK: - Private diff --git a/Screenshot Framer/Model/LayerStateHistory.swift b/Screenshot Framer/Model/LayerStateHistory.swift index 3e99fe9..a42abb8 100644 --- a/Screenshot Framer/Model/LayerStateHistory.swift +++ b/Screenshot Framer/Model/LayerStateHistory.swift @@ -33,7 +33,8 @@ final class LayerStateHistory { // MARK: - Lifecycle init() { - let initialState = LayerState(title: "Initial Operation", layers: [], outputConfig: OutputConfig(output: "", fromImageNumber: 1, toImageNumber: 5)) + let config = OutputConfig(transparent: false, output: "", fromImageNumber: 1, toImageNumber: 5) + let initialState = LayerState(title: "Initial Operation", layers: [], outputConfig: config) self.append(initialState) } diff --git a/Screenshot Framer/Model/Operations.swift b/Screenshot Framer/Model/Operations.swift index 34a5e2d..3ffd2dc 100644 --- a/Screenshot Framer/Model/Operations.swift +++ b/Screenshot Framer/Model/Operations.swift @@ -111,6 +111,24 @@ final class UpdateToImageNuberOperation: OperationProtocol { } +final class UpdateTransparencyOperation: OperationProtocol { + + let layerStateHistory: LayerStateHistory + let transparent: Bool + + init(layerStateHistory: LayerStateHistory, transparent: Bool) { + self.layerStateHistory = layerStateHistory + self.transparent = transparent + } + + func apply() { + let lastLayerState = self.layerStateHistory.currentLayerState + let newLayerState = lastLayerState.updating(transparency: self.transparent) + self.layerStateHistory.append(newLayerState) + } +} + + final class UpdateFrameOperation: OperationProtocol { let layerStateHistory: LayerStateHistory diff --git a/Screenshot Framer/Model/OutputConfig.swift b/Screenshot Framer/Model/OutputConfig.swift index 211c270..517780e 100644 --- a/Screenshot Framer/Model/OutputConfig.swift +++ b/Screenshot Framer/Model/OutputConfig.swift @@ -13,6 +13,7 @@ struct OutputConfig: Codable { // MARK: - Properties + let transparent: Bool let output: String let fromImageNumber: Int let toImageNumber: Int diff --git a/Screenshot Framer/Supporting Files/Code/SSFView.swift b/Screenshot Framer/Supporting Files/Code/SSFView.swift index 13a2ab2..688cfc2 100644 --- a/Screenshot Framer/Supporting Files/Code/SSFView.swift +++ b/Screenshot Framer/Supporting Files/Code/SSFView.swift @@ -46,30 +46,15 @@ final class SSFView: NSView { extension NSView { - func pngData() -> Data? { + func pngData(transparent: Bool) -> Data? { let imageSize = self.bounds.size guard let rep = self.bitmapImageRepForCachingDisplay(in: self.bounds) else { return nil } rep.size = imageSize rep.pixelsHigh = Int(imageSize.height) rep.pixelsWide = Int(imageSize.width) - rep.hasAlpha = false + rep.hasAlpha = transparent self.cacheDisplay(in: self.bounds, to: rep) return rep.representation(using: .png, properties: [:]) } } - -extension NSView { - var snapshot: NSImage { - guard let bitmapRep = self.bitmapImageRepForCachingDisplay(in: bounds) else { return NSImage() } - bitmapRep.size = self.frame.size - self.cacheDisplay(in: bounds, to: bitmapRep) - let image = NSImage(size: bounds.size) - image.addRepresentation(bitmapRep) - return image - } - - func imageData() -> Data? { - return self.snapshot.tiffRepresentation - } -} From cd969c2113c6f29ce2c32e27a750a1934488699a Mon Sep 17 00:00:00 2001 From: Patrick Kladek Date: Tue, 8 Feb 2022 16:56:16 +0400 Subject: [PATCH 4/4] Bump Version Number --- Screenshot Framer CLI/main.swift | 1 + Screenshot Framer.xcodeproj/project.pbxproj | 2 ++ Screenshot Framer/Supporting Files/Info.plist | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Screenshot Framer CLI/main.swift b/Screenshot Framer CLI/main.swift index 52bc867..28c1022 100644 --- a/Screenshot Framer CLI/main.swift +++ b/Screenshot Framer CLI/main.swift @@ -12,6 +12,7 @@ struct ScreenshotFramer: ParsableCommand { static let configuration = CommandConfiguration( abstract: "A Swift command-line tool to frame localised screenshots for the AppStore", + version: "2.0" subcommands: [Export.self, Website.self]) init() { } diff --git a/Screenshot Framer.xcodeproj/project.pbxproj b/Screenshot Framer.xcodeproj/project.pbxproj index 113fa07..95f7f31 100644 --- a/Screenshot Framer.xcodeproj/project.pbxproj +++ b/Screenshot Framer.xcodeproj/project.pbxproj @@ -766,6 +766,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + MARKETING_VERSION = 2.0; PRODUCT_BUNDLE_IDENTIFIER = com.ideasoncanvas.ScreenshotFramer; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -787,6 +788,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + MARKETING_VERSION = 2.0; PRODUCT_BUNDLE_IDENTIFIER = com.ideasoncanvas.ScreenshotFramer; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/Screenshot Framer/Supporting Files/Info.plist b/Screenshot Framer/Supporting Files/Info.plist index 8fb4078..905f6d3 100644 --- a/Screenshot Framer/Supporting Files/Info.plist +++ b/Screenshot Framer/Supporting Files/Info.plist @@ -40,7 +40,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0 + $(MARKETING_VERSION) CFBundleVersion 5 LSMinimumSystemVersion