361 lines
12 KiB
Swift
361 lines
12 KiB
Swift
//
|
||
// ZLEditImageConfiguration.swift
|
||
// ZLPhotoBrowser
|
||
//
|
||
// Created by long on 2021/12/17.
|
||
//
|
||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
// of this software and associated documentation files (the "Software"), to deal
|
||
// in the Software without restriction, including without limitation the rights
|
||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
// copies of the Software, and to permit persons to whom the Software is
|
||
// furnished to do so, subject to the following conditions:
|
||
//
|
||
// The above copyright notice and this permission notice shall be included in
|
||
// all copies or substantial portions of the Software.
|
||
//
|
||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||
// THE SOFTWARE.
|
||
|
||
import UIKit
|
||
|
||
/// Provide an image sticker container view that conform to this protocol must be a subclass of UIView
|
||
/// 必须是UIView的子类遵循这个协议
|
||
@objc public protocol ZLImageStickerContainerDelegate {
|
||
@objc var selectImageBlock: ((UIImage) -> Void)? { get set }
|
||
|
||
@objc var hideBlock: (() -> Void)? { get set }
|
||
|
||
@objc func show(in view: UIView)
|
||
}
|
||
|
||
@objcMembers
|
||
public class ZLEditImageConfiguration: NSObject {
|
||
private var pri_tools: [ZLEditImageConfiguration.EditTool] = ZLEditImageConfiguration.EditTool.allCases
|
||
/// Edit image tools. (Default order is draw, clip, imageSticker, textSticker, mosaic, filtter)
|
||
/// Because Objective-C Array can't contain Enum styles, so this property is invalid in Objective-C.
|
||
/// - warning: If you want to use the image sticker feature, you must provide a view that implements ZLImageStickerContainerDelegate.
|
||
public var tools: [ZLEditImageConfiguration.EditTool] {
|
||
get {
|
||
if pri_tools.isEmpty {
|
||
return ZLEditImageConfiguration.EditTool.allCases
|
||
} else {
|
||
return pri_tools
|
||
}
|
||
}
|
||
set {
|
||
pri_tools = newValue
|
||
}
|
||
}
|
||
|
||
/// Edit image tools. (This property is only for objc).
|
||
/// - warning: If you want to use the image sticker feature, you must provide a view that implements ZLImageStickerContainerDelegate.
|
||
public var tools_objc: [Int] = [] {
|
||
didSet {
|
||
tools = tools_objc.compactMap { ZLEditImageConfiguration.EditTool(rawValue: $0) }
|
||
}
|
||
}
|
||
|
||
private static let defaultDrawColors: [UIColor] = [
|
||
.white,
|
||
.black,
|
||
.zl.rgba(249, 80, 81),
|
||
.zl.rgba(248, 156, 59),
|
||
.zl.rgba(255, 195, 0),
|
||
.zl.rgba(145, 211, 0),
|
||
.zl.rgba(0, 193, 94),
|
||
.zl.rgba(16, 173, 254),
|
||
.zl.rgba(16, 132, 236),
|
||
.zl.rgba(99, 103, 240),
|
||
.zl.rgba(127, 127, 127)
|
||
]
|
||
|
||
private var pri_drawColors = ZLEditImageConfiguration.defaultDrawColors
|
||
/// Draw colors for image editor.
|
||
public var drawColors: [UIColor] {
|
||
get {
|
||
if pri_drawColors.isEmpty {
|
||
return ZLEditImageConfiguration.defaultDrawColors
|
||
} else {
|
||
return pri_drawColors
|
||
}
|
||
}
|
||
set {
|
||
pri_drawColors = newValue
|
||
}
|
||
}
|
||
|
||
/// The default draw color. If this color not in editImageDrawColors, will pick the first color in editImageDrawColors as the default.
|
||
public var defaultDrawColor: UIColor = .zl.rgba(249, 80, 81)
|
||
|
||
private var pri_clipRatios: [ZLImageClipRatio] = [.custom]
|
||
/// Edit ratios for image editor.
|
||
public var clipRatios: [ZLImageClipRatio] {
|
||
get {
|
||
if pri_clipRatios.isEmpty {
|
||
return [.custom]
|
||
} else {
|
||
return pri_clipRatios
|
||
}
|
||
}
|
||
set {
|
||
pri_clipRatios = newValue
|
||
}
|
||
}
|
||
|
||
private static let defaultTextStickerTextColors: [UIColor] = [
|
||
.white,
|
||
.black,
|
||
.zl.rgba(249, 80, 81),
|
||
.zl.rgba(248, 156, 59),
|
||
.zl.rgba(255, 195, 0),
|
||
.zl.rgba(145, 211, 0),
|
||
.zl.rgba(0, 193, 94),
|
||
.zl.rgba(16, 173, 254),
|
||
.zl.rgba(16, 132, 236),
|
||
.zl.rgba(99, 103, 240),
|
||
.zl.rgba(127, 127, 127)
|
||
]
|
||
|
||
private var pri_textStickerTextColors: [UIColor] = ZLEditImageConfiguration.defaultTextStickerTextColors
|
||
/// Text sticker colors for image editor.
|
||
public var textStickerTextColors: [UIColor] {
|
||
get {
|
||
if pri_textStickerTextColors.isEmpty {
|
||
return ZLEditImageConfiguration.defaultTextStickerTextColors
|
||
} else {
|
||
return pri_textStickerTextColors
|
||
}
|
||
}
|
||
set {
|
||
pri_textStickerTextColors = newValue
|
||
}
|
||
}
|
||
|
||
/// The default text sticker color. If this color not in textStickerTextColors, will pick the first color in textStickerTextColors as the default.
|
||
public var textStickerDefaultTextColor = UIColor.white
|
||
|
||
private var pri_filters: [ZLFilter] = ZLFilter.all
|
||
/// Filters for image editor.
|
||
public var filters: [ZLFilter] {
|
||
get {
|
||
if pri_filters.isEmpty {
|
||
return ZLFilter.all
|
||
} else {
|
||
return pri_filters
|
||
}
|
||
}
|
||
set {
|
||
pri_filters = newValue
|
||
}
|
||
}
|
||
|
||
public var imageStickerContainerView: (UIView & ZLImageStickerContainerDelegate)?
|
||
|
||
private var pri_adjustTools: [ZLEditImageConfiguration.AdjustTool] = ZLEditImageConfiguration.AdjustTool.allCases
|
||
/// Adjust image tools. (Default order is brightness, contrast, saturation)
|
||
/// Valid when the tools contain EditTool.adjust
|
||
/// Because Objective-C Array can't contain Enum styles, so this property is invalid in Objective-C.
|
||
public var adjustTools: [ZLEditImageConfiguration.AdjustTool] {
|
||
get {
|
||
if pri_adjustTools.isEmpty {
|
||
return ZLEditImageConfiguration.AdjustTool.allCases
|
||
} else {
|
||
return pri_adjustTools
|
||
}
|
||
}
|
||
set {
|
||
pri_adjustTools = newValue
|
||
}
|
||
}
|
||
|
||
/// Adjust image tools. (This property is only for objc).
|
||
/// Valid when the tools contain EditTool.adjust
|
||
public var adjustTools_objc: [Int] = [] {
|
||
didSet {
|
||
adjustTools = adjustTools_objc.compactMap { ZLEditImageConfiguration.AdjustTool(rawValue: $0) }
|
||
}
|
||
}
|
||
|
||
/// Give an impact feedback when the adjust slider value is zero. Defaults to true.
|
||
public var impactFeedbackWhenAdjustSliderValueIsZero = true
|
||
|
||
/// Impact feedback style. Defaults to .medium
|
||
public var impactFeedbackStyle: UIImpactFeedbackGenerator.FeedbackStyle = .medium
|
||
|
||
/// Whether to support redo in graffiti and mosaic tools. Defaults to false
|
||
public var canRedo = false
|
||
}
|
||
|
||
public extension ZLEditImageConfiguration {
|
||
@objc enum EditTool: Int, CaseIterable {
|
||
case draw
|
||
case clip
|
||
case imageSticker
|
||
case textSticker
|
||
case mosaic
|
||
case filter
|
||
case adjust
|
||
}
|
||
|
||
@objc enum AdjustTool: Int, CaseIterable {
|
||
case brightness
|
||
case contrast
|
||
case saturation
|
||
|
||
var key: String {
|
||
switch self {
|
||
case .brightness:
|
||
return kCIInputBrightnessKey
|
||
case .contrast:
|
||
return kCIInputContrastKey
|
||
case .saturation:
|
||
return kCIInputSaturationKey
|
||
}
|
||
}
|
||
|
||
func filterValue(_ value: Float) -> Float {
|
||
switch self {
|
||
case .brightness:
|
||
// 亮度范围-1---1,默认0,这里除以3,取 -0.33---0.33
|
||
return value / 3
|
||
case .contrast:
|
||
// 对比度范围0---4,默认1,这里计算下取0.5---2.5
|
||
let v: Float
|
||
if value < 0 {
|
||
v = 1 + value * (1 / 2)
|
||
} else {
|
||
v = 1 + value * (3 / 2)
|
||
}
|
||
return v
|
||
case .saturation:
|
||
// 饱和度范围0---2,默认1
|
||
return value + 1
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// MARK: chaining
|
||
|
||
public extension ZLEditImageConfiguration {
|
||
@discardableResult
|
||
func tools(_ tools: [ZLEditImageConfiguration.EditTool]) -> ZLEditImageConfiguration {
|
||
self.tools = tools
|
||
return self
|
||
}
|
||
|
||
@discardableResult
|
||
func drawColors(_ colors: [UIColor]) -> ZLEditImageConfiguration {
|
||
drawColors = colors
|
||
return self
|
||
}
|
||
|
||
func defaultDrawColor(_ color: UIColor) -> ZLEditImageConfiguration {
|
||
defaultDrawColor = color
|
||
return self
|
||
}
|
||
|
||
@discardableResult
|
||
func clipRatios(_ ratios: [ZLImageClipRatio]) -> ZLEditImageConfiguration {
|
||
clipRatios = ratios
|
||
return self
|
||
}
|
||
|
||
@discardableResult
|
||
func textStickerTextColors(_ colors: [UIColor]) -> ZLEditImageConfiguration {
|
||
textStickerTextColors = colors
|
||
return self
|
||
}
|
||
|
||
@discardableResult
|
||
func textStickerDefaultTextColor(_ color: UIColor) -> ZLEditImageConfiguration {
|
||
textStickerDefaultTextColor = color
|
||
return self
|
||
}
|
||
|
||
@discardableResult
|
||
func filters(_ filters: [ZLFilter]) -> ZLEditImageConfiguration {
|
||
self.filters = filters
|
||
return self
|
||
}
|
||
|
||
@discardableResult
|
||
func imageStickerContainerView(_ view: (UIView & ZLImageStickerContainerDelegate)?) -> ZLEditImageConfiguration {
|
||
imageStickerContainerView = view
|
||
return self
|
||
}
|
||
|
||
@discardableResult
|
||
func adjustTools(_ tools: [ZLEditImageConfiguration.AdjustTool]) -> ZLEditImageConfiguration {
|
||
adjustTools = tools
|
||
return self
|
||
}
|
||
|
||
@discardableResult
|
||
func impactFeedbackWhenAdjustSliderValueIsZero(_ value: Bool) -> ZLEditImageConfiguration {
|
||
impactFeedbackWhenAdjustSliderValueIsZero = value
|
||
return self
|
||
}
|
||
|
||
@discardableResult
|
||
func impactFeedbackStyle(_ style: UIImpactFeedbackGenerator.FeedbackStyle) -> ZLEditImageConfiguration {
|
||
impactFeedbackStyle = style
|
||
return self
|
||
}
|
||
|
||
@discardableResult
|
||
func canRedo(_ value: Bool) -> ZLEditImageConfiguration {
|
||
canRedo = value
|
||
return self
|
||
}
|
||
}
|
||
|
||
// MARK: 裁剪比例
|
||
|
||
public class ZLImageClipRatio: NSObject {
|
||
@objc public var title: String
|
||
|
||
@objc public let whRatio: CGFloat
|
||
|
||
@objc public let isCircle: Bool
|
||
|
||
@objc public init(title: String, whRatio: CGFloat, isCircle: Bool = false) {
|
||
self.title = title
|
||
self.whRatio = isCircle ? 1 : whRatio
|
||
self.isCircle = isCircle
|
||
super.init()
|
||
}
|
||
}
|
||
|
||
extension ZLImageClipRatio {
|
||
static func == (lhs: ZLImageClipRatio, rhs: ZLImageClipRatio) -> Bool {
|
||
return lhs.whRatio == rhs.whRatio && lhs.title == rhs.title
|
||
}
|
||
}
|
||
|
||
public extension ZLImageClipRatio {
|
||
@objc static let custom = ZLImageClipRatio(title: "custom", whRatio: 0)
|
||
|
||
@objc static let circle = ZLImageClipRatio(title: "circle", whRatio: 1, isCircle: true)
|
||
|
||
@objc static let wh1x1 = ZLImageClipRatio(title: "1 : 1", whRatio: 1)
|
||
|
||
@objc static let wh3x4 = ZLImageClipRatio(title: "3 : 4", whRatio: 3.0 / 4.0)
|
||
|
||
@objc static let wh4x3 = ZLImageClipRatio(title: "4 : 3", whRatio: 4.0 / 3.0)
|
||
|
||
@objc static let wh2x3 = ZLImageClipRatio(title: "2 : 3", whRatio: 2.0 / 3.0)
|
||
|
||
@objc static let wh3x2 = ZLImageClipRatio(title: "3 : 2", whRatio: 3.0 / 2.0)
|
||
|
||
@objc static let wh9x16 = ZLImageClipRatio(title: "9 : 16", whRatio: 9.0 / 16.0)
|
||
|
||
@objc static let wh16x9 = ZLImageClipRatio(title: "16 : 9", whRatio: 16.0 / 9.0)
|
||
}
|