Visual_Novel_iOS/crush/Crush/Src/Modules/Chat/Util/IMImageContainerLogic.swift

154 lines
4.6 KiB
Swift

//
// IMImageContainerLogic.swift
// Crush
//
// Created by Leon on 2025/8/22.
//
import UIKit
/// 稿
struct ImageDisplayConstants {
var W_MAX: CGFloat
var H_MAX: CGFloat
var W_MIN: CGFloat
var H_MIN: CGFloat
var RATIO_MIN: CGFloat
var RATIO_MAX: CGFloat
static let `default` = ImageDisplayConstants(
W_MAX: 372,
H_MAX: 372,
W_MIN: 48,
H_MIN: 48,
RATIO_MIN: 9.0 / 21.0,
RATIO_MAX: 21.0 / 9.0
)
}
///
struct CalculatedImageSize {
var width: CGFloat
var height: CGFloat
var type: ImageType
var ratio: CGFloat
}
///
enum ImageType: String {
case large
case small
case tiny
}
///
class ImageDisplayLogic {
///
private static func clamp(_ value: CGFloat, min: CGFloat, max: CGFloat) -> CGFloat {
return Swift.min(Swift.max(value, min), max)
}
///
static func getImageType(originalWidth: CGFloat,
originalHeight: CGFloat,
constants: ImageDisplayConstants = .default) -> ImageType {
let W_MAX = constants.W_MAX
let H_MAX = constants.H_MAX
let W_MIN = constants.W_MIN
let H_MIN = constants.H_MIN
// A.
let isLargeImage = (
(originalWidth >= W_MAX && originalHeight > (9.0/21.0) * H_MAX) ||
(originalHeight >= H_MAX && originalWidth > (9.0/21.0) * W_MAX)
)
if isLargeImage { return .large }
// C.
let isTinyImage = (originalWidth < W_MIN || originalHeight < H_MIN)
if isTinyImage { return .tiny }
// B.
return .small
}
///
static func calculateDisplayRatio(originalWidth: CGFloat,
originalHeight: CGFloat,
imageType: ImageType,
constants: ImageDisplayConstants = .default) -> CGFloat {
let originalRatio = originalWidth / originalHeight
if imageType == .large {
return clamp(originalRatio, min: constants.RATIO_MIN, max: constants.RATIO_MAX)
} else {
return originalRatio
}
}
///
static func calculateImageDisplaySize(originalWidth: CGFloat,
originalHeight: CGFloat,
constants: ImageDisplayConstants = .default) -> CalculatedImageSize {
let W_MAX = constants.W_MAX
let H_MAX = constants.H_MAX
let W_MIN = constants.W_MIN
let H_MIN = constants.H_MIN
// 1.
let imageType = getImageType(originalWidth: originalWidth, originalHeight: originalHeight, constants: constants)
// 2.
let displayRatio = calculateDisplayRatio(originalWidth: originalWidth, originalHeight: originalHeight, imageType: imageType, constants: constants)
// 3.
var finalWidth: CGFloat = 0
var finalHeight: CGFloat = 0
switch imageType {
case .large:
if displayRatio >= 1 {
//
finalWidth = W_MAX
finalHeight = W_MAX / displayRatio
} else {
//
finalHeight = H_MAX
finalWidth = H_MAX * displayRatio
}
case .small:
if displayRatio >= 1 {
finalHeight = originalHeight
finalWidth = min(originalWidth, W_MAX)
} else {
finalWidth = originalWidth
finalHeight = min(originalHeight, H_MAX)
}
case .tiny:
if displayRatio >= 1 {
finalHeight = H_MIN
finalWidth = min(H_MIN * displayRatio, W_MAX)
} else {
finalWidth = W_MIN
finalHeight = min(W_MIN / displayRatio, H_MAX)
}
}
return CalculatedImageSize(
width: round(finalWidth),
height: round(finalHeight),
type: imageType,
ratio: displayRatio
)
}
///
static func adjustConstants(for containerWidth: CGFloat) -> ImageDisplayConstants {
let maxSize = min(containerWidth * 0.5, 372)
var c = ImageDisplayConstants.default
c.W_MAX = maxSize
c.H_MAX = maxSize
return c
}
}