mirror of https://github.com/lukechilds/damus.git
Browse Source
Changelog-Fixed: Fixed crash on some SVG profile pictures Closes: #416translations_damus-localizations-en-us-xcloc-localized-contents-en-us-xliff--master_pl_PL
committed by
William Casarin
4 changed files with 116 additions and 38 deletions
@ -0,0 +1,101 @@ |
|||
// |
|||
// CoreSVG.swift |
|||
// damus |
|||
// |
|||
// Created by Oleg Abalonski on 1/27/23. |
|||
// Ref: https://gist.github.com/ollieatkinson/eb87a82fcb5500d5561fed8b0900a9f7 |
|||
|
|||
import Darwin |
|||
import Foundation |
|||
import UIKit |
|||
|
|||
@objc |
|||
class CGSVGDocument: NSObject { } |
|||
|
|||
var CGSVGDocumentRetain: (@convention(c) (CGSVGDocument?) -> Unmanaged<CGSVGDocument>?) = load("CGSVGDocumentRetain") |
|||
var CGSVGDocumentRelease: (@convention(c) (CGSVGDocument?) -> Void) = load("CGSVGDocumentRelease") |
|||
var CGSVGDocumentCreateFromData: (@convention(c) (CFData?, CFDictionary?) -> Unmanaged<CGSVGDocument>?) = load("CGSVGDocumentCreateFromData") |
|||
var CGContextDrawSVGDocument: (@convention(c) (CGContext?, CGSVGDocument?) -> Void) = load("CGContextDrawSVGDocument") |
|||
var CGSVGDocumentGetCanvasSize: (@convention(c) (CGSVGDocument?) -> CGSize) = load("CGSVGDocumentGetCanvasSize") |
|||
|
|||
typealias ImageWithCGSVGDocument = @convention(c) (AnyObject, Selector, CGSVGDocument) -> UIImage |
|||
var ImageWithCGSVGDocumentSEL: Selector = NSSelectorFromString("_imageWithCGSVGDocument:") |
|||
|
|||
let CoreSVG = dlopen("/System/Library/PrivateFrameworks/CoreSVG.framework/CoreSVG", RTLD_NOW) |
|||
|
|||
func load<T>(_ name: String) -> T { |
|||
unsafeBitCast(dlsym(CoreSVG, name), to: T.self) |
|||
} |
|||
|
|||
public class SVG { |
|||
|
|||
deinit { CGSVGDocumentRelease(document) } |
|||
|
|||
let document: CGSVGDocument |
|||
|
|||
public convenience init?(_ value: String) { |
|||
guard let data = value.data(using: .utf8) else { return nil } |
|||
self.init(data) |
|||
} |
|||
|
|||
public init?(_ data: Data) { |
|||
guard let document = CGSVGDocumentCreateFromData(data as CFData, nil)?.takeUnretainedValue() else { return nil } |
|||
guard CGSVGDocumentGetCanvasSize(document) != .zero else { return nil } |
|||
self.document = document |
|||
} |
|||
|
|||
public var size: CGSize { |
|||
CGSVGDocumentGetCanvasSize(document) |
|||
} |
|||
|
|||
public func image() -> UIImage? { |
|||
let ImageWithCGSVGDocument = unsafeBitCast(UIImage.self.method(for: ImageWithCGSVGDocumentSEL), to: ImageWithCGSVGDocument.self) |
|||
let image = ImageWithCGSVGDocument(UIImage.self, ImageWithCGSVGDocumentSEL, document) |
|||
return image |
|||
} |
|||
|
|||
public func draw(in context: CGContext) { |
|||
draw(in: context, size: size) |
|||
} |
|||
|
|||
public func draw(in context: CGContext, size target: CGSize) { |
|||
|
|||
var target = target |
|||
|
|||
let ratio = ( |
|||
x: target.width / size.width, |
|||
y: target.height / size.height |
|||
) |
|||
|
|||
let rect = ( |
|||
document: CGRect(origin: .zero, size: size), () |
|||
) |
|||
|
|||
let scale: (x: CGFloat, y: CGFloat) |
|||
|
|||
if target.width <= 0 { |
|||
scale = (ratio.y, ratio.y) |
|||
target.width = size.width * scale.x |
|||
} else if target.height <= 0 { |
|||
scale = (ratio.x, ratio.x) |
|||
target.width = size.width * scale.y |
|||
} else { |
|||
let min = min(ratio.x, ratio.y) |
|||
scale = (min, min) |
|||
target.width = size.width * scale.x |
|||
target.height = size.height * scale.y |
|||
} |
|||
|
|||
let transform = ( |
|||
scale: CGAffineTransform(scaleX: scale.x, y: scale.y), |
|||
aspect: CGAffineTransform(translationX: (target.width / scale.x - rect.document.width) / 2, y: (target.height / scale.y - rect.document.height) / 2) |
|||
) |
|||
|
|||
context.translateBy(x: 0, y: target.height) |
|||
context.scaleBy(x: 1, y: -1) |
|||
context.concatenate(transform.scale) |
|||
context.concatenate(transform.aspect) |
|||
|
|||
CGContextDrawSVGDocument(context, document) |
|||
} |
|||
} |
Loading…
Reference in new issue