added MTMathImage - draw latex image offscreen.

This commit is contained in:
Peter Tang
2023-09-12 07:18:44 +08:00
parent c15d09e04e
commit 32ba7c128a
3 changed files with 118 additions and 6 deletions

View File

@@ -18,6 +18,7 @@ public typealias MTBezierPath = UIBezierPath
public typealias MTLabel = UILabel
public typealias MTEdgeInsets = UIEdgeInsets
public typealias MTRect = CGRect
public typealias MTImage = UIImage
let MTEdgeInsetsZero = UIEdgeInsets.zero
func MTGraphicsGetCurrentContext() -> CGContext? { UIGraphicsGetCurrentContext() }
@@ -31,6 +32,7 @@ public typealias MTColor = NSColor
public typealias MTBezierPath = NSBezierPath
public typealias MTEdgeInsets = NSEdgeInsets
public typealias MTRect = NSRect
public typealias MTImage = NSImage
let MTEdgeInsetsZero = NSEdgeInsets.init(top: 0, left: 0, bottom: 0, right: 0)
func MTGraphicsGetCurrentContext() -> CGContext? { NSGraphicsContext.current?.cgContext }

View File

@@ -11,17 +11,16 @@ import Foundation
public class MTFontManager {
static public private(set) var manager:MTFontManager! = nil
static public private(set) var manager: MTFontManager = {
MTFontManager()
}()
let kDefaultFontSize = CGFloat(20)
static var fontManager : MTFontManager {
if manager == nil {
manager = MTFontManager()
}
return manager!
return manager
}
public init() { }
var nameToFontMap = [String: MTFont]()

View 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
}
}