Source/Charts/Utils/Platform+Graphics.swift (123 lines of code) (raw):
//
// Platform+Graphics.swift
// Charts
//
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
// A port of MPAndroidChart for iOS
// Licensed under Apache License 2.0
//
// https://github.com/danielgindi/Charts
//
enum Orientation
{
case portrait, landscape
}
extension CGSize
{
var orientation: Orientation { return width > height ? .landscape : .portrait }
}
extension CGRect
{
var orientation: Orientation { size.orientation }
}
// MARK: - UIKit
#if canImport(UIKit)
import UIKit
func NSUIGraphicsGetCurrentContext() -> CGContext?
{
return UIGraphicsGetCurrentContext()
}
func NSUIGraphicsGetImageFromCurrentImageContext() -> NSUIImage!
{
return UIGraphicsGetImageFromCurrentImageContext()
}
func NSUIGraphicsPushContext(_ context: CGContext)
{
UIGraphicsPushContext(context)
}
func NSUIGraphicsPopContext()
{
UIGraphicsPopContext()
}
func NSUIGraphicsEndImageContext()
{
UIGraphicsEndImageContext()
}
func NSUIImagePNGRepresentation(_ image: NSUIImage) -> Data?
{
return image.pngData()
}
func NSUIImageJPEGRepresentation(_ image: NSUIImage, _ quality: CGFloat = 0.8) -> Data?
{
return image.jpegData(compressionQuality: quality)
}
func NSUIGraphicsBeginImageContextWithOptions(_ size: CGSize, _ opaque: Bool, _ scale: CGFloat)
{
UIGraphicsBeginImageContextWithOptions(size, opaque, scale)
}
#endif
// MARK: - AppKit
#if canImport(AppKit) && !targetEnvironment(macCatalyst)
import AppKit
func NSUIGraphicsGetCurrentContext() -> CGContext?
{
return NSGraphicsContext.current?.cgContext
}
func NSUIGraphicsPushContext(_ context: CGContext)
{
let cx = NSGraphicsContext(cgContext: context, flipped: true)
NSGraphicsContext.saveGraphicsState()
NSGraphicsContext.current = cx
}
func NSUIGraphicsPopContext()
{
NSGraphicsContext.restoreGraphicsState()
}
func NSUIImagePNGRepresentation(_ image: NSUIImage) -> Data?
{
image.lockFocus()
let rep = NSBitmapImageRep(focusedViewRect: NSMakeRect(0, 0, image.size.width, image.size.height))
image.unlockFocus()
return rep?.representation(using: .png, properties: [:])
}
func NSUIImageJPEGRepresentation(_ image: NSUIImage, _ quality: CGFloat = 0.9) -> Data?
{
image.lockFocus()
let rep = NSBitmapImageRep(focusedViewRect: NSMakeRect(0, 0, image.size.width, image.size.height))
image.unlockFocus()
return rep?.representation(using: .jpeg, properties: [NSBitmapImageRep.PropertyKey.compressionFactor: quality])
}
private var imageContextStack: [CGFloat] = []
func NSUIGraphicsBeginImageContextWithOptions(_ size: CGSize, _ opaque: Bool, _ scale: CGFloat)
{
var scale = scale
if scale == 0.0
{
scale = NSScreen.main?.backingScaleFactor ?? 1.0
}
let width = Int(size.width * scale)
let height = Int(size.height * scale)
if width > 0 && height > 0
{
imageContextStack.append(scale)
let colorSpace = CGColorSpaceCreateDeviceRGB()
guard let ctx = CGContext(data: nil, width: width, height: height, bitsPerComponent: 8, bytesPerRow: 4*width, space: colorSpace, bitmapInfo: (opaque ? CGImageAlphaInfo.noneSkipFirst.rawValue : CGImageAlphaInfo.premultipliedFirst.rawValue))
else { return }
ctx.concatenate(CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: CGFloat(height)))
ctx.scaleBy(x: scale, y: scale)
NSUIGraphicsPushContext(ctx)
}
}
func NSUIGraphicsGetImageFromCurrentImageContext() -> NSUIImage?
{
if !imageContextStack.isEmpty
{
guard let ctx = NSUIGraphicsGetCurrentContext()
else { return nil }
let scale = imageContextStack.last!
if let theCGImage = ctx.makeImage()
{
let size = CGSize(width: CGFloat(ctx.width) / scale, height: CGFloat(ctx.height) / scale)
let image = NSImage(cgImage: theCGImage, size: size)
return image
}
}
return nil
}
func NSUIGraphicsEndImageContext()
{
if imageContextStack.last != nil
{
imageContextStack.removeLast()
NSUIGraphicsPopContext()
}
}
#endif