Skip to content

Commit

Permalink
Unify image extension methods
Browse files Browse the repository at this point in the history
  • Loading branch information
yangKJ committed Mar 1, 2024
1 parent 4c23b2d commit 6239ed0
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 193 deletions.
2 changes: 1 addition & 1 deletion Harbeth.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

Pod::Spec.new do |s|
s.name = 'Harbeth'
s.version = '1.1.0'
s.version = '1.1.1'
s.summary = 'About image and video add filter for metal.'

# This description is used to generate tags and improve search results.
Expand Down
77 changes: 76 additions & 1 deletion Sources/Basic/Extensions/C7Image+Ext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ extension HarbethWrapper where Base: C7Image {
return NSImage.init(size: base.size, flipped: false) { (rect) -> Bool in
color.set()
rect.fill()
base.draw(in: rect, from: imageRect, operation: .destinationIn, fraction: 1.0)
base.draw(in: rect, from: imageRect, operation: .destinationIn, fraction: base.scale)
return true
}
#else
Expand Down Expand Up @@ -188,6 +188,33 @@ extension HarbethWrapper where Base: C7Image {
public func inverting() -> C7Image {
renderer(rect: .init(origin: .zero, size: base.size), inverting: true)
}

/// To ensure image orientation is correct, redraw image if image orientation is not up.
/// See: https://stackoverflow.com/questions/42098390/swift-png-image-being-saved-with-incorrect-orientation
public func flattened(isOpaque: Bool = true) -> C7Image {
#if os(macOS)
//return base.c7.revolve180
return base
#else
if base.imageOrientation == .up {
return base
}
return base.c7.renderer(rect: .init(origin: .zero, size: base.size), isOpaque: isOpaque)
#endif
}

/// Fixed image rotation direction.
public func fixOrientation() -> C7Image {
#if os(macOS)
return base
#else
let imageOrientation = base.imageOrientation
guard imageOrientation != .up, let cgImage = base.cgImage else {
return base
}
return cgImage.c7.fixOrientation(from: imageOrientation).c7.drawing(refImage: base)
#endif
}
}

// MARK: - edit image
Expand Down Expand Up @@ -258,4 +285,52 @@ extension HarbethWrapper where Base: C7Image {
let rect = CGRect(x: -space, y: -space, width: size.width+2*space, height: size.height+2*space)
return base.c7.renderer(rect: rect, canvas: size)
}

/// Rotate the picture.
/// - Parameter degrees: Rotation angle.
/// - Returns: The picture after rotation.
public func rotate(degrees: Float) -> C7Image {
#if os(macOS)
let img = NSImage(size: base.size, flipped: false, drawingHandler: { (rect) -> Bool in
let (width, height) = (rect.size.width, rect.size.height)
let transform = NSAffineTransform()
transform.translateX(by: width / 2, yBy: height / 2)
transform.rotate(byDegrees: CGFloat(degrees))
transform.translateX(by: -width / 2, yBy: -height / 2)
transform.concat()
base.draw(in: rect)
return true
})
img.isTemplate = base.isTemplate // preserve the underlying image's template setting
return img
#else
let radians = CGFloat(degrees) / 180.0 * .pi
let tran = CGAffineTransform(rotationAngle: radians)
var size = CGRect(origin: .zero, size: base.size).applying(tran).size
size.width = floor(size.width)
size.height = floor(size.height)
let rect = CGRect(x: -base.size.width/2, y: -base.size.height/2, width: base.size.width, height: base.size.height)
UIGraphicsBeginImageContext(size)
let context = UIGraphicsGetCurrentContext()
context?.translateBy(x: size.width/2, y: size.height/2)
context?.rotate(by: radians)
base.draw(in: rect)
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return result ?? base
#endif
}

/// Rotation 180.
public var revolve180: C7Image {
#if os(macOS)
//return NSImage(size: base.size, flipped: true, drawingHandler: { _ in true })
return rotate(degrees: 180)
#else
guard let cgImage = base.cgImage else {
return base
}
return C7Image(cgImage: cgImage, scale: base.scale, orientation: .down)
#endif
}
}
203 changes: 52 additions & 151 deletions Sources/Basic/Extensions/C7Image+iOS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,73 +13,6 @@ import UIKit
// https://developer.apple.com/documentation/uikit/uiimage

extension HarbethWrapper where Base: C7Image {
/// To ensure image orientation is correct, redraw image if image orientation is not up.
/// See: https://stackoverflow.com/questions/42098390/swift-png-image-being-saved-with-incorrect-orientation
public func flattened(isOpaque: Bool = true) -> C7Image {
if base.imageOrientation == .up {
return base
}
return base.c7.renderer(rect: .init(origin: .zero, size: base.size), isOpaque: isOpaque)
}

/// Fixed image rotation direction.
public func fixOrientation() -> C7Image {
if base.imageOrientation == .up {
return base
}
let width = base.size.width
let height = base.size.height
var transform = CGAffineTransform.identity

switch base.imageOrientation {
case .down, .downMirrored:
transform = CGAffineTransform(translationX: width, y: height)
transform = transform.rotated(by: .pi)
case .left, .leftMirrored:
transform = CGAffineTransform(translationX: width, y: 0)
transform = transform.rotated(by: CGFloat.pi / 2)
case .right, .rightMirrored:
transform = CGAffineTransform(translationX: 0, y: height)
transform = transform.rotated(by: -CGFloat.pi / 2)
default:
break
}

switch base.imageOrientation {
case .upMirrored, .downMirrored:
transform = transform.translatedBy(x: width, y: 0)
transform = transform.scaledBy(x: -1, y: 1)
case .leftMirrored, .rightMirrored:
transform = transform.translatedBy(x: height, y: 0)
transform = transform.scaledBy(x: -1, y: 1)
default:
break
}

guard let cgImage = base.cgImage, let colorSpace = cgImage.colorSpace else {
return base
}
let context = CGContext(data: nil,
width: Int(width),
height: Int(height),
bitsPerComponent: cgImage.bitsPerComponent,
bytesPerRow: 0,
space: colorSpace,
bitmapInfo: cgImage.bitmapInfo.rawValue)
context?.concatenate(transform)
switch base.imageOrientation {
case .left, .leftMirrored, .right, .rightMirrored:
context?.draw(cgImage, in: CGRect(x: 0, y: 0, width: height, height: width))
default:
context?.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height))
}

guard let cgImage_ = context?.makeImage() else {
return base
}
return cgImage_.c7.toC7Image()
}

/// Compressed image data.
/// - Parameter maxCount: Maximum compression ratio.
/// - Returns: Compressed content data.
Expand All @@ -92,9 +25,6 @@ extension HarbethWrapper where Base: C7Image {
}
return jpegData
}
}

extension HarbethWrapper where Base: C7Image {

public var original: C7Image {
base.withRenderingMode(.alwaysOriginal)
Expand Down Expand Up @@ -139,49 +69,6 @@ extension HarbethWrapper where Base: C7Image {
return result
}

/// Rotate the picture.
/// - Parameter degrees: Rotation angle.
/// - Returns: The picture after rotation.
public func rotate(degrees: Float) -> C7Image {
let radians = CGFloat(degrees) / 180.0 * .pi
let tran = CGAffineTransform(rotationAngle: radians)
var size = CGRect(origin: .zero, size: base.size).applying(tran).size
size.width = floor(size.width)
size.height = floor(size.height)
let rect = CGRect(x: -base.size.width/2, y: -base.size.height/2, width: base.size.width, height: base.size.height)
UIGraphicsBeginImageContext(size)
let context = UIGraphicsGetCurrentContext()
context?.translateBy(x: size.width/2, y: size.height/2)
context?.rotate(by: radians)
base.draw(in: rect)
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return result ?? base
}

/// Rotation 180.
public var revolve180: C7Image {
guard let cgImage = base.cgImage else {
return base
}
return C7Image(cgImage: cgImage, scale: base.scale, orientation: .down)
}

/// Round image.
public var circle: C7Image {
let min = min(base.size.width, base.size.height)
let size = CGSize(width: min, height: min)
UIGraphicsBeginImageContextWithOptions(size, false, base.scale)
let context = UIGraphicsGetCurrentContext()
context?.addEllipse(in: .init(origin: .zero, size: size))
context?.clip()
base.draw(in: .init(origin: .zero, size: base.size))
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return result ?? base
}


/// Modify the line color of the picture.
/// - Parameter color: Line color.
public func line(color: C7Color) -> C7Image {
Expand All @@ -202,49 +89,23 @@ extension HarbethWrapper where Base: C7Image {
UIGraphicsEndImageContext()
return tintedImage ?? base
}

/// Fill the image on the basis that the image is not deformed.
/// - Parameters:
/// - width: Fill image width, Keep the original size at zero.
/// - height: Fill image height, Keep the original size at zero.
public func fitFixed(width: CGFloat = 0, height: CGFloat = 0) -> C7Image {
guard let cgImage = base.cgImage else {
return base
}
var rect = CGRect(origin: .zero, size: base.size)
switch (width, height) {
case (0.0, 0.0):
return base
case (0.0, 0.0000002...):
rect.size.width = base.size.width * (height / base.size.height)
rect.size.height = height
case (0.0000002..., 0.0):
rect.size.width = width
rect.size.height = base.size.height * (width / base.size.width)
default:
if base.size.width/base.size.height < width/height {
rect.size.height = height
rect.size.width = base.size.width * height / base.size.height
rect.origin.x = (width - rect.size.width) * 0.5
} else {
rect.size.width = width
rect.size.height = base.size.height * width / base.size.width
rect.origin.y = -(height - rect.size.height) * 0.5
}
}
UIGraphicsBeginImageContextWithOptions(rect.size, false, base.scale)
}

extension HarbethWrapper where Base: C7Image {
/// Round image.
public var circle: C7Image {
let min = min(base.size.width, base.size.height)
let size = CGSize(width: min, height: min)
UIGraphicsBeginImageContextWithOptions(size, false, base.scale)
let context = UIGraphicsGetCurrentContext()
context?.translateBy(x: 0.0, y: rect.size.height)
context?.scaleBy(x: 1.0, y: -1.0)
context?.setBlendMode(.copy)
context?.draw(cgImage, in: rect)
context?.addEllipse(in: .init(origin: .zero, size: size))
context?.clip()
base.draw(in: .init(origin: .zero, size: base.size))
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return result ?? base
}
}

extension HarbethWrapper where Base: C7Image {

/// Image path cropping, cropping path outside part.
/// - Parameter bezierPath: Crop path.
public func cropOuter(bezierPath: UIBezierPath) -> C7Image {
Expand Down Expand Up @@ -283,6 +144,46 @@ extension HarbethWrapper where Base: C7Image {
UIGraphicsEndImageContext()
return result ?? base
}

/// Fill the image on the basis that the image is not deformed.
/// - Parameters:
/// - width: Fill image width, Keep the original size at zero.
/// - height: Fill image height, Keep the original size at zero.
public func fitFixed(width: CGFloat = 0, height: CGFloat = 0) -> C7Image {
guard let cgImage = base.cgImage else {
return base
}
var rect = CGRect(origin: .zero, size: base.size)
switch (width, height) {
case (0.0, 0.0):
return base
case (0.0, 0.0000002...):
rect.size.width = base.size.width * (height / base.size.height)
rect.size.height = height
case (0.0000002..., 0.0):
rect.size.width = width
rect.size.height = base.size.height * (width / base.size.width)
default:
if base.size.width/base.size.height < width/height {
rect.size.height = height
rect.size.width = base.size.width * height / base.size.height
rect.origin.x = (width - rect.size.width) * 0.5
} else {
rect.size.width = width
rect.size.height = base.size.height * width / base.size.width
rect.origin.y = -(height - rect.size.height) * 0.5
}
}
UIGraphicsBeginImageContextWithOptions(rect.size, false, base.scale)
let context = UIGraphicsGetCurrentContext()
context?.translateBy(x: 0.0, y: rect.size.height)
context?.scaleBy(x: 1.0, y: -1.0)
context?.setBlendMode(.copy)
context?.draw(cgImage, in: rect)
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return result ?? base
}
}

#endif
12 changes: 1 addition & 11 deletions Sources/Basic/Extensions/C7Image+macOS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ extension C7Image {
}

public func pngData() -> Data? {
guard let representation = tiffRepresentation,
let bitmap = NSBitmapImageRep(data: representation) else {
guard let rep = tiffRepresentation, let bitmap = NSBitmapImageRep(data: rep) else {
return nil
}
return bitmap.representation(using: .png, properties: [:])
Expand All @@ -57,15 +56,6 @@ extension HarbethWrapper where Base: C7Image {
}
}

/// Fixed image rotation direction.
public func fixOrientation() -> C7Image {
base
}

public var flattened: C7Image {
base
}

/// Flip image, Need to be used in `base.lockFocus()`
///
/// Example:
Expand Down

0 comments on commit 6239ed0

Please sign in to comment.