added MTMathImage - draw latex image offscreen.
This commit is contained in:
@@ -18,6 +18,7 @@ public typealias MTBezierPath = UIBezierPath
|
|||||||
public typealias MTLabel = UILabel
|
public typealias MTLabel = UILabel
|
||||||
public typealias MTEdgeInsets = UIEdgeInsets
|
public typealias MTEdgeInsets = UIEdgeInsets
|
||||||
public typealias MTRect = CGRect
|
public typealias MTRect = CGRect
|
||||||
|
public typealias MTImage = UIImage
|
||||||
|
|
||||||
let MTEdgeInsetsZero = UIEdgeInsets.zero
|
let MTEdgeInsetsZero = UIEdgeInsets.zero
|
||||||
func MTGraphicsGetCurrentContext() -> CGContext? { UIGraphicsGetCurrentContext() }
|
func MTGraphicsGetCurrentContext() -> CGContext? { UIGraphicsGetCurrentContext() }
|
||||||
@@ -31,6 +32,7 @@ public typealias MTColor = NSColor
|
|||||||
public typealias MTBezierPath = NSBezierPath
|
public typealias MTBezierPath = NSBezierPath
|
||||||
public typealias MTEdgeInsets = NSEdgeInsets
|
public typealias MTEdgeInsets = NSEdgeInsets
|
||||||
public typealias MTRect = NSRect
|
public typealias MTRect = NSRect
|
||||||
|
public typealias MTImage = NSImage
|
||||||
|
|
||||||
let MTEdgeInsetsZero = NSEdgeInsets.init(top: 0, left: 0, bottom: 0, right: 0)
|
let MTEdgeInsetsZero = NSEdgeInsets.init(top: 0, left: 0, bottom: 0, right: 0)
|
||||||
func MTGraphicsGetCurrentContext() -> CGContext? { NSGraphicsContext.current?.cgContext }
|
func MTGraphicsGetCurrentContext() -> CGContext? { NSGraphicsContext.current?.cgContext }
|
||||||
|
|||||||
@@ -11,15 +11,14 @@ import Foundation
|
|||||||
|
|
||||||
public class MTFontManager {
|
public class MTFontManager {
|
||||||
|
|
||||||
static public private(set) var manager:MTFontManager! = nil
|
static public private(set) var manager: MTFontManager = {
|
||||||
|
MTFontManager()
|
||||||
|
}()
|
||||||
|
|
||||||
let kDefaultFontSize = CGFloat(20)
|
let kDefaultFontSize = CGFloat(20)
|
||||||
|
|
||||||
static var fontManager : MTFontManager {
|
static var fontManager : MTFontManager {
|
||||||
if manager == nil {
|
return manager
|
||||||
manager = MTFontManager()
|
|
||||||
}
|
|
||||||
return manager!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public init() { }
|
public init() { }
|
||||||
|
|||||||
111
Sources/SwiftMath/MathRender/MTMathImage.swift
Normal file
111
Sources/SwiftMath/MathRender/MTMathImage.swift
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
//
|
||||||
|
// File.swift
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Peter Tang on 12/9/2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
#if os(iOS)
|
||||||
|
import UIKit
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if os(macOS)
|
||||||
|
import AppKit
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public class MTMathImage {
|
||||||
|
public var font: MTFont? = nil
|
||||||
|
public let fontSize: CGFloat
|
||||||
|
public let textColor: MTColor
|
||||||
|
|
||||||
|
public let labelMode: MTMathUILabelMode
|
||||||
|
public let textAlignment: MTTextAlignment
|
||||||
|
|
||||||
|
public var contentInsets: MTEdgeInsets = MTEdgeInsetsZero
|
||||||
|
|
||||||
|
public let latex: String
|
||||||
|
private(set) var intrinsicContentSize = CGSize.zero
|
||||||
|
|
||||||
|
public init(latex: String, fontSize: CGFloat, textColor: MTColor, labelMode: MTMathUILabelMode = .display, textAlignment: MTTextAlignment = .center) {
|
||||||
|
self.latex = latex
|
||||||
|
self.fontSize = fontSize
|
||||||
|
self.textColor = textColor
|
||||||
|
self.labelMode = labelMode
|
||||||
|
self.textAlignment = textAlignment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
extension MTMathImage {
|
||||||
|
public var currentStyle: MTLineStyle {
|
||||||
|
switch labelMode {
|
||||||
|
case .display: return .display
|
||||||
|
case .text: return .text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private func intrinsicContentSize(_ displayList: MTMathListDisplay) -> CGSize {
|
||||||
|
CGSize(width: displayList.width + contentInsets.left + contentInsets.right,
|
||||||
|
height: displayList.ascent + displayList.descent + contentInsets.top + contentInsets.bottom)
|
||||||
|
}
|
||||||
|
public func asImage() -> (NSError?, MTImage?) {
|
||||||
|
func layoutImage(size: CGSize, displayList: MTMathListDisplay) {
|
||||||
|
var textX = CGFloat(0)
|
||||||
|
switch self.textAlignment {
|
||||||
|
case .left: textX = contentInsets.left
|
||||||
|
case .center: textX = (size.width - contentInsets.left - contentInsets.right - displayList.width) / 2 + contentInsets.left
|
||||||
|
case .right: textX = size.width - displayList.width - contentInsets.right
|
||||||
|
}
|
||||||
|
let availableHeight = size.height - contentInsets.bottom - contentInsets.top
|
||||||
|
|
||||||
|
// center things vertically
|
||||||
|
var height = displayList.ascent + displayList.descent
|
||||||
|
if height < fontSize/2 {
|
||||||
|
height = fontSize/2 // set height to half the font size
|
||||||
|
}
|
||||||
|
let textY = (availableHeight - height) / 2 + displayList.descent + contentInsets.bottom
|
||||||
|
displayList.position = CGPoint(x: textX, y: textY)
|
||||||
|
}
|
||||||
|
if font == nil {
|
||||||
|
self.font = MTFontManager.fontManager.defaultFont
|
||||||
|
}
|
||||||
|
var error: NSError?
|
||||||
|
guard let mathList = MTMathListBuilder.build(fromString: latex, error: &error), error == nil,
|
||||||
|
let displayList = MTTypesetter.createLineForMathList(mathList, font: font, style: currentStyle) else {
|
||||||
|
return (error, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
intrinsicContentSize = intrinsicContentSize(displayList)
|
||||||
|
displayList.textColor = textColor
|
||||||
|
|
||||||
|
let size = intrinsicContentSize
|
||||||
|
layoutImage(size: size, displayList: displayList)
|
||||||
|
|
||||||
|
#if os(iOS)
|
||||||
|
let renderer = UIGraphicsImageRenderer(size: size)
|
||||||
|
let image = renderer.image { rendererContext in
|
||||||
|
rendererContext.cgContext.saveGState()
|
||||||
|
rendererContext.cgContext.concatenate(.flippedVertically(size.height))
|
||||||
|
displayList.draw(rendererContext.cgContext)
|
||||||
|
rendererContext.cgContext.restoreGState()
|
||||||
|
}
|
||||||
|
return (nil, image)
|
||||||
|
#endif
|
||||||
|
#if os(macOS)
|
||||||
|
let image = NSImage(size: size, flipped: true) { bounds in
|
||||||
|
guard let context = NSGraphicsContext.current?.cgContext else { return false }
|
||||||
|
context.saveGState()
|
||||||
|
displayList.draw(context)
|
||||||
|
context.restoreGState()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return (nil, image)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private extension CGAffineTransform {
|
||||||
|
static func flippedVertically(_ height: CGFloat) -> CGAffineTransform {
|
||||||
|
var transform = CGAffineTransform(scaleX: 1, y: -1)
|
||||||
|
transform = transform.translatedBy(x: 0, y: -height)
|
||||||
|
return transform
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user