From 7b43a2e1fa2a94f674d4b8d07f639a56660df038 Mon Sep 17 00:00:00 2001 From: scchn Date: Sat, 4 May 2024 09:14:28 +0800 Subject: [PATCH] Update `ZPLImageEncoder` --- .../ZPLBuilder/Commands/GraphicField.swift | 29 +++--- .../Commands/HostDirectoryList.swift | 2 +- .../Commands/PrintDirectoryLabel.swift | 2 +- .../Commands/UseFontNameToCallFont.swift | 2 +- .../ZPLImageEncoder/ZPLCGImageReader.swift | 75 +++++++++++++++ .../Utils/ZPLImageEncoder/ZPLImage.swift | 14 +++ .../ZPLImageEncoder.swift | 91 ++++--------------- .../ZPLImageEncoder/ZPLImageReader.swift | 17 ++++ 8 files changed, 141 insertions(+), 91 deletions(-) create mode 100644 Sources/ZPLBuilder/Utils/ZPLImageEncoder/ZPLCGImageReader.swift create mode 100644 Sources/ZPLBuilder/Utils/ZPLImageEncoder/ZPLImage.swift rename Sources/ZPLBuilder/Utils/{ => ZPLImageEncoder}/ZPLImageEncoder.swift (60%) create mode 100644 Sources/ZPLBuilder/Utils/ZPLImageEncoder/ZPLImageReader.swift diff --git a/Sources/ZPLBuilder/Commands/GraphicField.swift b/Sources/ZPLBuilder/Commands/GraphicField.swift index 1973854..912374d 100644 --- a/Sources/ZPLBuilder/Commands/GraphicField.swift +++ b/Sources/ZPLBuilder/Commands/GraphicField.swift @@ -16,25 +16,22 @@ import CoreGraphics public struct GraphicField: ZPLCommandConvertible { private let encoder: ZPLImageEncoder - public var cgImage: CGImage? - public var size: CGSize? + public var image: ZPLImageReader? public var command: String { - guard let cgImage, - let encoded = encoder.encode(cgImage: cgImage, targetSize: size) + guard let image = image, let encoded = encoder.encode(imageReader: image) else { return "" } return "^GFA,\(encoded.totalBytes),\(encoded.totalBytes),\(encoded.bytesPerRow),\(encoded.data)" } - private init(size: CGSize?, encoder: ZPLImageEncoder) { + private init(encoder: ZPLImageEncoder) { self.encoder = encoder } - public init(cgImage: CGImage, size: CGSize? = nil, encoder: ZPLImageEncoder = .default) { + public init(imageReader: ZPLImageReader, encoder: ZPLImageEncoder = .default) { self.encoder = encoder - self.cgImage = cgImage - self.size = size + self.image = imageReader } } #endif @@ -44,10 +41,12 @@ import AppKit extension GraphicField { public init(image: NSImage, size: CGSize? = nil, encoder: ZPLImageEncoder = .default) { - if let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil) { - self.init(cgImage: cgImage, size: size, encoder: encoder) + if let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil), + let image = ZPLCGImageReader(cgImage: cgImage, targetSize: size) + { + self.init(imageReader: image, encoder: encoder) } else { - self.init(size: size, encoder: encoder) + self.init(encoder: encoder) } } } @@ -56,10 +55,12 @@ import UIKit extension GraphicField { public init(image: UIImage, size: CGSize? = nil, encoder: ZPLImageEncoder = .default) { - if let cgImage = image.cgImage { - self.init(cgImage: cgImage, size: size, encoder: encoder) + if let cgImage = image.cgImage, + let image = ZPLCGImageReader(cgImage: cgImage, targetSize: size) + { + self.init(imageReader: image, encoder: encoder) } else { - self.init(size: size, encoder: encoder) + self.init(encoder: encoder) } } } diff --git a/Sources/ZPLBuilder/Commands/HostDirectoryList.swift b/Sources/ZPLBuilder/Commands/HostDirectoryList.swift index d938c19..82c00ef 100644 --- a/Sources/ZPLBuilder/Commands/HostDirectoryList.swift +++ b/Sources/ZPLBuilder/Commands/HostDirectoryList.swift @@ -2,7 +2,7 @@ // HostDirectoryList.swift // // -// Created by 陳世爵 on 2023/12/27. +// Created by chen on 2023/12/27. // import Foundation diff --git a/Sources/ZPLBuilder/Commands/PrintDirectoryLabel.swift b/Sources/ZPLBuilder/Commands/PrintDirectoryLabel.swift index 2aac80c..dc016da 100644 --- a/Sources/ZPLBuilder/Commands/PrintDirectoryLabel.swift +++ b/Sources/ZPLBuilder/Commands/PrintDirectoryLabel.swift @@ -2,7 +2,7 @@ // PrintDirectoryLabel.swift // // -// Created by 陳世爵 on 2023/12/4. +// Created by chen on 2023/12/4. // import Foundation diff --git a/Sources/ZPLBuilder/Commands/UseFontNameToCallFont.swift b/Sources/ZPLBuilder/Commands/UseFontNameToCallFont.swift index d0339f4..bff4770 100644 --- a/Sources/ZPLBuilder/Commands/UseFontNameToCallFont.swift +++ b/Sources/ZPLBuilder/Commands/UseFontNameToCallFont.swift @@ -2,7 +2,7 @@ // UseFontNameToCallFont.swift // // -// Created by 陳世爵 on 2023/12/4. +// Created by chen on 2023/12/4. // import Foundation diff --git a/Sources/ZPLBuilder/Utils/ZPLImageEncoder/ZPLCGImageReader.swift b/Sources/ZPLBuilder/Utils/ZPLImageEncoder/ZPLCGImageReader.swift new file mode 100644 index 0000000..89d9a63 --- /dev/null +++ b/Sources/ZPLBuilder/Utils/ZPLImageEncoder/ZPLCGImageReader.swift @@ -0,0 +1,75 @@ +// +// ZPLCGImageReader.swift +// +// +// Created by chen on 2024/5/4. +// + +#if canImport(CoreGraphics) +import Foundation +import CoreGraphics +import OSLog + +public struct ZPLCGImageReader: ZPLImageReader { + private let imageData: CFData + private let imagePtr: UnsafePointer + private let bytesPerPixel: Int + private let bytesPerRow: Int + + public var width: Int + public var height: Int + + public init?(cgImage: CGImage, targetSize: CGSize?) { + guard cgImage.width > 0, cgImage.height > 0 else { + return nil + } + + self.width = { + if let targetWidth = targetSize?.width { + return Int(targetWidth) + } else { + return cgImage.width + } + }() + self.height = { + if let targetHeight = targetSize?.height { + return Int(targetHeight) + } else { + return cgImage.height + } + }() + + guard + self.width > 0, self.height > 0, + let cgImage = width == cgImage.width && height == cgImage.height + ? cgImage + : cgImage.resized(width: width, height: height), + let imageData = cgImage.dataProvider?.data, + let imagePtr = CFDataGetBytePtr(imageData) + else { + return nil + } + + self.imageData = imageData + self.imagePtr = imagePtr + self.bytesPerPixel = cgImage.bitsPerPixel / 8 + self.bytesPerRow = cgImage.bytesPerRow + } + + private func offset(x: Int, y: Int) -> Int { + y * bytesPerRow + x * bytesPerPixel + } + + public func getRed(x: Int, y: Int) -> UInt8 { + imagePtr[offset(x: x, y: y)] + } + + public func getGreen(x: Int, y: Int) -> UInt8 { + imagePtr[offset(x: x, y: y) + 1] + } + + public func getBlue(x: Int, y: Int) -> UInt8 { + imagePtr[offset(x: x, y: y) + 2] + } +} +#endif diff --git a/Sources/ZPLBuilder/Utils/ZPLImageEncoder/ZPLImage.swift b/Sources/ZPLBuilder/Utils/ZPLImageEncoder/ZPLImage.swift new file mode 100644 index 0000000..861ae79 --- /dev/null +++ b/Sources/ZPLBuilder/Utils/ZPLImageEncoder/ZPLImage.swift @@ -0,0 +1,14 @@ +// +// File.swift +// +// +// Created by chen on 2024/5/4. +// + +import Foundation + +public struct ZPLImage { + public var bytesPerRow: Int + public var totalBytes: Int + public var data: String +} diff --git a/Sources/ZPLBuilder/Utils/ZPLImageEncoder.swift b/Sources/ZPLBuilder/Utils/ZPLImageEncoder/ZPLImageEncoder.swift similarity index 60% rename from Sources/ZPLBuilder/Utils/ZPLImageEncoder.swift rename to Sources/ZPLBuilder/Utils/ZPLImageEncoder/ZPLImageEncoder.swift index 7cff7e3..3c14ad1 100644 --- a/Sources/ZPLBuilder/Utils/ZPLImageEncoder.swift +++ b/Sources/ZPLBuilder/Utils/ZPLImageEncoder/ZPLImageEncoder.swift @@ -5,19 +5,7 @@ // Created by chen on 2023/11/18. // -#if canImport(CoreGraphics) import Foundation -import CoreGraphics -import OSLog - -@available(macOS 11.0, iOS 14.0, *) -private let logger = Logger(subsystem: "ZPLBuidler", category: "ZPLImageEncoder") - -public struct ZPLImage { - public var bytesPerRow: Int - public var totalBytes: Int - public var data: String -} public class ZPLImageEncoder { /// The default encoder of ``GraphicField``. @@ -32,79 +20,35 @@ public class ZPLImageEncoder { } - public func encode(cgImage: CGImage, targetSize: CGSize?) -> ZPLImage? { - let width: Int - let height: Int - - if let targetWidth = targetSize?.width { - width = Int(targetWidth) - } else { - width = cgImage.width - } - - if let targetHeight = targetSize?.height { - height = Int(targetHeight) - } else { - height = cgImage.height - } - - guard width > 0, height > 0, cgImage.width > 0, cgImage.height > 0 else { - if #available(macOS 11.0, iOS 14.0, *) { - logger.notice("Invalid image size or target size.") - } - return nil - } - guard let cgImage = width == cgImage.width && height == cgImage.height - ? cgImage - : cgImage.resized(width: width, height: height) - else { - if #available(macOS 11.0, iOS 14.0, *) { - logger.notice("Failed to resize image.") - } - return nil - } - guard let data = isCompressed ? makeCompressedData(cgImage: cgImage) : makeData(cgImage: cgImage), + public func encode(imageReader: ZPLImageReader) -> ZPLImage? { + guard let data = isCompressed ? makeCompressedData(imageReader: imageReader) : makeData(imageReader: imageReader), !data.isEmpty else { - if #available(macOS 11.0, iOS 14.0, *) { - logger.notice("Failed to encode image.") - } return nil } - let bytesPerRow = width / Self.componentValueSize + (width.isMultiple(of: Self.componentValueSize) ? 0 : 1) - let totalBytes = bytesPerRow * height + let bytesPerRow = imageReader.width / Self.componentValueSize + (imageReader.width.isMultiple(of: Self.componentValueSize) ? 0 : 1) + let totalBytes = bytesPerRow * imageReader.height return ZPLImage(bytesPerRow: bytesPerRow, totalBytes: totalBytes, data: data) } - private func enumerateComponents(cgImage: CGImage, _ block: (Int, Int, String, Bool) -> Void) { - guard let imageData = cgImage.dataProvider?.data, - let imagePtr = CFDataGetBytePtr(imageData) - else { - return - } - - let width = cgImage.width - let height = cgImage.height - let bytesPerPixel = cgImage.bitsPerPixel / 8 - let bytesPerRow = cgImage.bytesPerRow + private func enumerateComponents(imageReader: ZPLImageReader, _ block: (Int, Int, String, Bool) -> Void) { + let width = imageReader.width + let height = imageReader.height for y in 0.. String? { + private func makeData(imageReader: ZPLImageReader) -> String? { var body = "" - enumerateComponents(cgImage: cgImage) { x, y, components, _ in + enumerateComponents(imageReader: imageReader) { x, y, components, _ in body.append(components) } @@ -145,9 +89,9 @@ extension ZPLImageEncoder { } extension ZPLImageEncoder { - private func makeCompressedData(cgImage: CGImage) -> String? { - let divisable = cgImage.width.isMultiple(of: Self.componentValueSize) - let bytesPerRow = cgImage.width / Self.componentValueSize + (divisable ? 0 : 1) + private func makeCompressedData(imageReader: ZPLImageReader) -> String? { + let divisable = imageReader.width.isMultiple(of: Self.componentValueSize) + let bytesPerRow = imageReader.width / Self.componentValueSize + (divisable ? 0 : 1) let maxRepeatCount = bytesPerRow * 2 var repeatCount = 1 var aux: Character? @@ -155,7 +99,7 @@ extension ZPLImageEncoder { var prevLine: [Character] = [] var body: [Character] = [] - enumerateComponents(cgImage: cgImage) { x, y, components, isEOL in + enumerateComponents(imageReader: imageReader) { x, y, components, isEOL in for component in components { guard let _aux = aux else { aux = component @@ -256,4 +200,3 @@ private let encodingTable: [Int: Character] = [ 380: "y", 400: "z", ] -#endif diff --git a/Sources/ZPLBuilder/Utils/ZPLImageEncoder/ZPLImageReader.swift b/Sources/ZPLBuilder/Utils/ZPLImageEncoder/ZPLImageReader.swift new file mode 100644 index 0000000..ab44972 --- /dev/null +++ b/Sources/ZPLBuilder/Utils/ZPLImageEncoder/ZPLImageReader.swift @@ -0,0 +1,17 @@ +// +// ZPLImageReader.swift +// +// +// Created by chen on 2024/5/4. +// + +import Foundation + +public protocol ZPLImageReader { + var width: Int { get } + var height: Int { get } + + func getRed(x: Int, y: Int) -> UInt8 + func getGreen(x: Int, y: Int) -> UInt8 + func getBlue(x: Int, y: Int) -> UInt8 +}