mirror of
https://github.com/laosb/CropImage.git
synced 2025-04-30 23:51:08 +00:00
feat: Initial image size.
This commit is contained in:
parent
b42b532ddb
commit
edc6a5c17b
2 changed files with 29 additions and 5 deletions
|
@ -37,6 +37,8 @@ public struct CropImageView<Controls: View>: View {
|
||||||
|
|
||||||
/// The image to crop.
|
/// The image to crop.
|
||||||
public var image: PlatformImage
|
public var image: PlatformImage
|
||||||
|
/// The region in which the image is initially fitted in, in points.
|
||||||
|
public var initialImageSize: CGSize
|
||||||
/// The intended size of the cropped image, in points.
|
/// The intended size of the cropped image, in points.
|
||||||
public var targetSize: CGSize
|
public var targetSize: CGSize
|
||||||
/// The intended scale of the cropped image.
|
/// The intended scale of the cropped image.
|
||||||
|
@ -56,12 +58,14 @@ public struct CropImageView<Controls: View>: View {
|
||||||
/// Create a ``CropImageView`` with a custom ``controls`` view.
|
/// Create a ``CropImageView`` with a custom ``controls`` view.
|
||||||
public init(
|
public init(
|
||||||
image: PlatformImage,
|
image: PlatformImage,
|
||||||
|
initialImageSize: CGSize,
|
||||||
targetSize: CGSize,
|
targetSize: CGSize,
|
||||||
targetScale: CGFloat = 1,
|
targetScale: CGFloat = 1,
|
||||||
onCrop: @escaping (Result<PlatformImage, Error>) -> Void,
|
onCrop: @escaping (Result<PlatformImage, Error>) -> Void,
|
||||||
@ViewBuilder controls: @escaping ControlClosure<Controls>
|
@ViewBuilder controls: @escaping ControlClosure<Controls>
|
||||||
) {
|
) {
|
||||||
self.image = image
|
self.image = image
|
||||||
|
self.initialImageSize = initialImageSize
|
||||||
self.targetSize = targetSize
|
self.targetSize = targetSize
|
||||||
self.targetScale = targetScale
|
self.targetScale = targetScale
|
||||||
self.onCrop = onCrop
|
self.onCrop = onCrop
|
||||||
|
@ -72,11 +76,13 @@ public struct CropImageView<Controls: View>: View {
|
||||||
/// The default ``controls`` view is a simple overlay with a checkmark icon on the bottom-trailing corner to trigger crop action.
|
/// The default ``controls`` view is a simple overlay with a checkmark icon on the bottom-trailing corner to trigger crop action.
|
||||||
public init(
|
public init(
|
||||||
image: PlatformImage,
|
image: PlatformImage,
|
||||||
|
initialImageSize: CGSize,
|
||||||
targetSize: CGSize,
|
targetSize: CGSize,
|
||||||
targetScale: CGFloat = 1,
|
targetScale: CGFloat = 1,
|
||||||
onCrop: @escaping (Result<PlatformImage, Error>) -> Void
|
onCrop: @escaping (Result<PlatformImage, Error>) -> Void
|
||||||
) where Controls == DefaultControlsView {
|
) where Controls == DefaultControlsView {
|
||||||
self.image = image
|
self.image = image
|
||||||
|
self.initialImageSize = initialImageSize
|
||||||
self.targetSize = targetSize
|
self.targetSize = targetSize
|
||||||
self.targetScale = targetScale
|
self.targetScale = targetScale
|
||||||
self.onCrop = onCrop
|
self.onCrop = onCrop
|
||||||
|
@ -95,7 +101,8 @@ public struct CropImageView<Controls: View>: View {
|
||||||
offset: $offset,
|
offset: $offset,
|
||||||
scale: $scale,
|
scale: $scale,
|
||||||
rotation: $rotation,
|
rotation: $rotation,
|
||||||
image: image
|
image: image,
|
||||||
|
initialImageSize: initialImageSize
|
||||||
)
|
)
|
||||||
.frame(width: targetSize.width, height: targetSize.height)
|
.frame(width: targetSize.width, height: targetSize.height)
|
||||||
if #available(iOS 16.0, macOS 13.0, *) {
|
if #available(iOS 16.0, macOS 13.0, *) {
|
||||||
|
@ -143,7 +150,8 @@ public struct CropImageView<Controls: View>: View {
|
||||||
offset: $offset,
|
offset: $offset,
|
||||||
scale: $scale,
|
scale: $scale,
|
||||||
rotation: $rotation,
|
rotation: $rotation,
|
||||||
image: image
|
image: image,
|
||||||
|
initialImageSize: initialImageSize
|
||||||
)
|
)
|
||||||
RectHoleShape(size: targetSize)
|
RectHoleShape(size: targetSize)
|
||||||
.fill(style: FillStyle(eoFill: true))
|
.fill(style: FillStyle(eoFill: true))
|
||||||
|
@ -163,6 +171,7 @@ public struct CropImageView<Controls: View>: View {
|
||||||
|
|
||||||
struct CropImageView_Previews: PreviewProvider {
|
struct CropImageView_Previews: PreviewProvider {
|
||||||
struct PreviewView: View {
|
struct PreviewView: View {
|
||||||
|
@State private var initialImageSize: CGSize = .init(width: 200, height: 200)
|
||||||
@State private var targetSize: CGSize = .init(width: 100, height: 100)
|
@State private var targetSize: CGSize = .init(width: 100, height: 100)
|
||||||
@State private var result: Result<PlatformImage, Error>? = nil
|
@State private var result: Result<PlatformImage, Error>? = nil
|
||||||
|
|
||||||
|
@ -170,9 +179,17 @@ struct CropImageView_Previews: PreviewProvider {
|
||||||
VStack {
|
VStack {
|
||||||
CropImageView(
|
CropImageView(
|
||||||
image: .init(contentsOfFile: "/Users/laosb/Downloads/png.png")!,
|
image: .init(contentsOfFile: "/Users/laosb/Downloads/png.png")!,
|
||||||
|
initialImageSize: initialImageSize,
|
||||||
targetSize: targetSize
|
targetSize: targetSize
|
||||||
) { result = $0 }
|
) { result = $0 }
|
||||||
Form {
|
Form {
|
||||||
|
Section {
|
||||||
|
TextField("Width", value: $initialImageSize.width, formatter: NumberFormatter())
|
||||||
|
TextField("Height", value: $initialImageSize.height, formatter: NumberFormatter())
|
||||||
|
} header: {
|
||||||
|
Text("Initial Image Size")
|
||||||
|
Text("The image will be fitted into this region.")
|
||||||
|
}
|
||||||
Section {
|
Section {
|
||||||
TextField("Width", value: $targetSize.width, formatter: NumberFormatter())
|
TextField("Width", value: $targetSize.width, formatter: NumberFormatter())
|
||||||
TextField("Height", value: $targetSize.height, formatter: NumberFormatter())
|
TextField("Height", value: $targetSize.height, formatter: NumberFormatter())
|
||||||
|
@ -205,7 +222,8 @@ struct CropImageView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
PreviewView()
|
PreviewView()
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
.frame(minHeight: 750)
|
.frame(width: 500)
|
||||||
|
.frame(minHeight: 770)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ struct UnderlyingImageView: View {
|
||||||
@Binding var scale: CGFloat
|
@Binding var scale: CGFloat
|
||||||
@Binding var rotation: Angle
|
@Binding var rotation: Angle
|
||||||
var image: PlatformImage
|
var image: PlatformImage
|
||||||
|
var initialImageSize: CGSize
|
||||||
|
|
||||||
@State private var tempOffset: CGSize = .zero
|
@State private var tempOffset: CGSize = .zero
|
||||||
@State private var tempScale: CGFloat = 1
|
@State private var tempScale: CGFloat = 1
|
||||||
|
@ -34,6 +35,10 @@ struct UnderlyingImageView: View {
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
imageView
|
imageView
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: initialImageSize.width, height: initialImageSize.height)
|
||||||
|
.animation(.default, value: initialImageSize)
|
||||||
.scaleEffect(scale * tempScale)
|
.scaleEffect(scale * tempScale)
|
||||||
.offset(offset + tempOffset)
|
.offset(offset + tempOffset)
|
||||||
.rotationEffect(rotation + tempRotation)
|
.rotationEffect(rotation + tempRotation)
|
||||||
|
@ -54,7 +59,7 @@ struct UnderlyingImageView: View {
|
||||||
tempScale = value
|
tempScale = value
|
||||||
}
|
}
|
||||||
.onEnded { value in
|
.onEnded { value in
|
||||||
scale = scale * tempScale
|
scale = max(scale * tempScale, 0.01)
|
||||||
tempScale = 1
|
tempScale = 1
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -83,7 +88,8 @@ struct MoveAndScalableImageView_Previews: PreviewProvider {
|
||||||
offset: $offset,
|
offset: $offset,
|
||||||
scale: $scale,
|
scale: $scale,
|
||||||
rotation: $rotation,
|
rotation: $rotation,
|
||||||
image: .init(contentsOfFile: "/Users/laosb/Downloads/png.png")!
|
image: .init(contentsOfFile: "/Users/laosb/Downloads/png.png")!,
|
||||||
|
initialImageSize: .init(width: 200, height: 200)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue