diff --git a/iOSClient/Extensions/UIImage+Extension.swift b/iOSClient/Extensions/UIImage+Extension.swift index 0502b7f08a..40b8be463a 100644 --- a/iOSClient/Extensions/UIImage+Extension.swift +++ b/iOSClient/Extensions/UIImage+Extension.swift @@ -41,10 +41,13 @@ extension UIImage { } } - UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0) - self.draw(in: CGRect(origin: .zero, size: newSize)) - defer { UIGraphicsEndImageContext() } - return UIGraphicsGetImageFromCurrentImageContext() + let format = UIGraphicsImageRendererFormat.default() + format.opaque = false + format.scale = 1.0 + let renderer = UIGraphicsImageRenderer(size: newSize, format: format) + return renderer.image { _ in + self.draw(in: CGRect(origin: .zero, size: newSize)) + } } func fixedOrientation() -> UIImage? { diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index e1a560361c..8d0c486b37 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -190,10 +190,10 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, let searchBar = searchController?.searchBar searchBar?.delegate = self searchBar?.autocapitalizationType = .none - searchBar?.backgroundImage = UIImage() navigationItem.searchController = searchController navigationItem.hidesSearchBarWhenScrolling = false + navigationItem.preferredSearchBarPlacement = .inline } // Cell diff --git a/iOSClient/Menu/NCContextMenuMain.swift b/iOSClient/Menu/NCContextMenuMain.swift index c57af4a957..131d52557e 100644 --- a/iOSClient/Menu/NCContextMenuMain.swift +++ b/iOSClient/Menu/NCContextMenuMain.swift @@ -507,7 +507,12 @@ class NCContextMenuMain: NSObject { if let image = await NCUtility().convertSVGtoPNGWriteToUserData(serverUrl: metadata.urlBase + iconUrl, rewrite: false, account: metadata.account).image { - iconImage = image + if let image = image.withTintColor( + NCBrandColor.shared.iconImageColor, + renderingMode: .alwaysOriginal + ).resizeImage(size: CGSize(width: 20, height: 20)) { + iconImage = image + } } } diff --git a/iOSClient/Utility/NCSVGRenderer.swift b/iOSClient/Utility/NCSVGRenderer.swift index be88278e0c..95b7d75c7a 100644 --- a/iOSClient/Utility/NCSVGRenderer.swift +++ b/iOSClient/Utility/NCSVGRenderer.swift @@ -12,8 +12,10 @@ final class NCSVGRenderer: NSObject, WKNavigationDelegate { private let utilityFileSystem = NCUtilityFileSystem() func renderSVGToUIImage(svgData: Data?, - size: CGSize = CGSize(width: 128, height: 128), - backgroundColor: UIColor = .clear) async throws -> UIImage? { + size: CGSize = CGSize(width: 256, height: 256), + backgroundColor: UIColor = .clear, + trimTransparentPixels: Bool = true, + alphaThreshold: UInt8 = 8) async throws -> UIImage? { guard let svgData else { return nil } @@ -78,9 +80,70 @@ final class NCSVGRenderer: NSObject, WKNavigationDelegate { let scaled = renderer.image { _ in image.draw(in: CGRect(origin: .zero, size: targetSize)) } + + if trimTransparentPixels, + let trimmed = Self.trimTransparentPixels(in: scaled, alphaThreshold: alphaThreshold) { + return trimmed + } + return scaled } + private static func trimTransparentPixels(in image: UIImage, alphaThreshold: UInt8) -> UIImage? { + guard let cgImage = image.cgImage else { return nil } + + let width = cgImage.width + let height = cgImage.height + let bytesPerRow = width * 4 + let colorSpace = CGColorSpaceCreateDeviceRGB() + + guard let context = CGContext( + data: nil, + width: width, + height: height, + bitsPerComponent: 8, + bytesPerRow: bytesPerRow, + space: colorSpace, + bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue + ), let data = context.data else { + return nil + } + + context.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height)) + + let buffer = data.bindMemory(to: UInt8.self, capacity: width * height * 4) + var minX = width + var minY = height + var maxX = 0 + var maxY = 0 + var found = false + + for y in 0.. alphaThreshold { + found = true + if x < minX { minX = x } + if y < minY { minY = y } + if x > maxX { maxX = x } + if y > maxY { maxY = y } + } + } + } + + guard found else { return nil } + + let cropRect = CGRect( + x: minX, + y: minY, + width: maxX - minX + 1, + height: maxY - minY + 1 + ) + + guard let cropped = cgImage.cropping(to: cropRect) else { return nil } + return UIImage(cgImage: cropped, scale: image.scale, orientation: .up) + } + private func loadHTMLAsync(webView: WKWebView, html: String) async throws { // Cancel any in-flight load to avoid overlapping delegates/continuations webView.stopLoading() diff --git a/iOSClient/Utility/NCUtility+Image.swift b/iOSClient/Utility/NCUtility+Image.swift index 0f495107f4..583789726f 100644 --- a/iOSClient/Utility/NCUtility+Image.swift +++ b/iOSClient/Utility/NCUtility+Image.swift @@ -264,8 +264,9 @@ extension NCUtility { #if !EXTENSION func convertSVGtoPNGWriteToUserData(serverUrl: String, - size: CGFloat = 128, + size: CGFloat = 256, rewrite: Bool, + trimTransparentPixels: Bool = true, account: String, id: Int? = nil) async -> (image: UIImage?, id: Int?) { var serverUrl = serverUrl @@ -313,7 +314,7 @@ extension NCUtility { // is a SVG do { - let image = try await NCSVGRenderer().renderSVGToUIImage(svgData: data, size: CGSize(width: size, height: size)) + let image = try await NCSVGRenderer().renderSVGToUIImage(svgData: data, size: CGSize(width: size, height: size), trimTransparentPixels: trimTransparentPixels) guard let image, let pngImageData = image.pngData() else { return(nil, id)