From 1b51316ab6a54a14dd0578feef3e1fe46c094aa6 Mon Sep 17 00:00:00 2001
From: Wilhelm Oks <oksw@MBP-von-Wilhelm.fritz.box>
Date: Fri, 13 Dec 2024 14:41:26 +0100
Subject: [PATCH] AuthToken, ImageDataConversion

---
 Sources/SwiftDevRant/AuthToken.swift          | 10 +++
 .../SwiftDevRant/ImageDataConversion.swift    | 87 +++++++++++++++++++
 2 files changed, 97 insertions(+)
 create mode 100644 Sources/SwiftDevRant/AuthToken.swift
 create mode 100644 Sources/SwiftDevRant/ImageDataConversion.swift

diff --git a/Sources/SwiftDevRant/AuthToken.swift b/Sources/SwiftDevRant/AuthToken.swift
new file mode 100644
index 0000000..793cf65
--- /dev/null
+++ b/Sources/SwiftDevRant/AuthToken.swift
@@ -0,0 +1,10 @@
+public struct AuthToken: Codable, Hashable {
+    public struct Container: Codable {
+        public let auth_token: AuthToken
+    }
+    
+    public let id: Int
+    public let key: String
+    public let expire_time: Int
+    public let user_id: Int
+}
diff --git a/Sources/SwiftDevRant/ImageDataConversion.swift b/Sources/SwiftDevRant/ImageDataConversion.swift
new file mode 100644
index 0000000..bd51d26
--- /dev/null
+++ b/Sources/SwiftDevRant/ImageDataConversion.swift
@@ -0,0 +1,87 @@
+#if os(iOS)
+import UIKit
+#elseif os(macOS)
+import AppKit
+#endif
+
+private struct ImageHeaderData {
+    static let png: UInt8 = 0x89
+    static let jpeg: UInt8 = 0xFF
+    static let gif: UInt8 = 0x47
+    static let tiff_01: UInt8 = 0x49
+    static let tiff_02: UInt8 = 0x4D
+}
+
+enum ImageFormat {
+    case png
+    case jpeg
+    case gif
+    case tiff
+}
+
+extension Data {
+    var imageFormat: ImageFormat? {
+        let buffer = self.first
+        if buffer == ImageHeaderData.png {
+            return .png
+        } else if buffer == ImageHeaderData.jpeg {
+            return .jpeg
+        } else if buffer == ImageHeaderData.gif {
+            return .gif
+        } else if buffer == ImageHeaderData.tiff_01 || buffer == ImageHeaderData.tiff_02 {
+            return .tiff
+        } else {
+            return nil
+        }
+    }
+}
+
+public protocol ImageDataConverter {
+    /// Converts the image `data` to another format and returns the resulting Data.
+    func convert(_ data: Data) -> Data
+}
+
+public extension ImageDataConverter {
+    #if os(macOS)
+    func jpegData(from image: NSImage) -> Data? {
+        guard let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil) else { return nil }
+        let bitmapRep = NSBitmapImageRep(cgImage: cgImage)
+        return bitmapRep.representation(using: .jpeg, properties: [:])
+    }
+    #endif
+}
+
+extension Collection where Element == ImageDataConverter {
+    /// Applies all converters to the provided `data` sequentially and returns the result.
+    func convert(_ data: Data) -> Data {
+        var result = data
+        for converter in self {
+            result = converter.convert(result)
+        }
+        return result
+    }
+}
+
+/// An `ImageDataConverter` that converts image formats which are not supported by devRant to jpeg.
+/// Data of supported formats is just returned without any conversion.
+/// If the conversion fails, the original Data is returned.
+public struct UnsupportedToJpegImageDataConverter: ImageDataConverter {
+    public func convert(_ data: Data) -> Data {
+        switch data.imageFormat {
+        case nil: // Format not recognized so it's probably not supported by devRant.
+            #if os(iOS)
+            return UIImage(data: data)?.jpegData(compressionQuality: 1) ?? data
+            #elseif os(macOS)
+            return NSImage(data: data).flatMap(jpegData) ?? data
+            #else
+            return data // This converter doesn't support platforms other than iOS and macOS. If you need to support other platforms, you can implement and use an own converter.
+            #endif
+        default: // Supported format recognized. No conversion needed.
+            return data
+        }
+    }
+}
+
+public extension ImageDataConverter where Self == UnsupportedToJpegImageDataConverter {
+    static var unsupportedToJpeg: Self { Self() }
+}