SwiftUI তে ইমেজ ক্রপ

ইমেজ ক্রপ করা সহজ। যেমন নিচের কোড দেখিঃ

import SwiftUI

struct ContentView: View {
    @State private var image = UIImage(named: "image")! // Replace with your image
    @State private var croppedImage: UIImage?
    let cropSize = CGSize(width: 500, height: 500) //  crop size

    var body: some View {
        VStack {
            if let croppedImage {
                // Display the cropped image
                Image(uiImage: croppedImage)
                    .resizable()
                    .scaledToFit()
                    .frame(width: cropSize.width, height: cropSize.height)
                    .border(Color.green, width: 2)
                    .padding()

                Text("Cropped Image Size: \(Int(croppedImage.size.width)) x \(Int(croppedImage.size.height))")
            } else {
                // Display the original image
                Image(uiImage: image)
                    .resizable()
                    .scaledToFit()
                    .frame(width: 300, height: 300)
                    .padding()
            }

            // Crop button
            Button("Crop Image") {
                let cropRect = CGRect(
                    x: (image.size.width - cropSize.width) / 2, // Center the crop rectangle
                    y: (image.size.height - cropSize.height) / 2,
                    width: cropSize.width,
                    height: cropSize.height
                )
                croppedImage = cropImage(image, to: cropRect)
            }
            .buttonStyle(.borderedProminent)
            .padding()

            // Undo button
            Button("Undo") {
                croppedImage = nil
            }
            .buttonStyle(.bordered)
        }
        .padding()
    }

    func cropImage(_ image: UIImage, to cropRect: CGRect) -> UIImage? {
        guard let cgImage = image.cgImage,
              let croppedCGImage = cgImage.cropping(to: cropRect) else {
            print("Cropping failed. Invalid crop rectangle: \(cropRect)")
            return nil
        }

        return UIImage(cgImage: croppedCGImage)
    }
}

এটি আমাদের একটা ইমেজকে নির্দিষ্ট সাইজে ইমেজ ক্রপ করে দিবে। যেটা ইমেজের সেন্টার থেকে ইমেজকে নির্দিষ্ট সাইজে ক্রপ করে দিবে। নির্দিষ্ট এসপেক্ট রেশিও অনুযায়ী ইমেজ ক্রপ করতে চাইলে নিচের মত করে ইমপ্লিমেন্ট করতে পারিঃ

import SwiftUI

struct ContentView: View {
    @State private var image = UIImage(named: "image")! // Replace with your image
    @State private var croppedImage: UIImage?
    let cropRatio: CGFloat = 1.0 // Aspect ratio: 1:1 (square)

    var body: some View {
        VStack {
            if let croppedImage {
                // Display the cropped image
                Image(uiImage: croppedImage)
                    .resizable()
                    .scaledToFit()
                    .frame(width: 200, height: 200 / cropRatio)
                    .border(Color.green, width: 2)
                    .padding()

                Text("Cropped Image Size: \(Int(croppedImage.size.width)) x \(Int(croppedImage.size.height))")
            } else {
                // Display the original image
                Image(uiImage: image)
                    .resizable()
                    .scaledToFit()
                    .frame(width: 300, height: 300)
                    .padding()
            }

            // Crop button
            Button("Crop Image") {
                croppedImage = cropImageToRatio(image, cropRatio: cropRatio)
            }
            .buttonStyle(.borderedProminent)
            .padding()

            // Undo button
            Button("Undo") {
                croppedImage = nil
            }
            .buttonStyle(.bordered)
        }
        .padding()
    }


    func cropImageToRatio(_ image: UIImage, cropRatio: CGFloat) -> UIImage? {
        let originalSize = image.size
        let originalRatio = originalSize.width / originalSize.height

        var cropRect: CGRect

        if originalRatio > cropRatio {
            // Image is wider than the desired ratio, crop the width
            let newWidth = originalSize.height * cropRatio
            cropRect = CGRect(
                x: (originalSize.width - newWidth) / 2,
                y: 0,
                width: newWidth,
                height: originalSize.height
            )
        } else {
            // Image is taller than the desired ratio, crop the height
            let newHeight = originalSize.width / cropRatio
            cropRect = CGRect(
                x: 0,
                y: (originalSize.height - newHeight) / 2,
                width: originalSize.width,
                height: newHeight
            )
        }

        // Perform the cropping
        guard let cgImage = image.cgImage?.cropping(to: cropRect) else {
            print("Cropping failed. Invalid crop rectangle: \(cropRect)")
            return nil
        }

        return UIImage(cgImage: cgImage)
    }
}

কাস্টম এসপেক্ট রেশিও অনুযায়ীও আমরা চাইলে ক্রপ করে নিতে পারি। তার জন্য এভাবে কোড লিখতে পারিঃ

import SwiftUI

struct ContentView: View {
    @State private var originalImage = UIImage(named: "image")! // Replace with your image
    @State private var croppedImage: UIImage?
    let aspectRatio = CGSize(width: 200, height: 250)

    var body: some View {
        VStack {
            if let croppedImage {
                // Display the cropped image
                Image(uiImage: croppedImage)
                    .resizable()
                    .scaledToFit()
                    .frame(height: 300)
                    .border(Color.green, width: 2)

                Text("Cropped Image Size: \(Int(croppedImage.size.width)) x \(Int(croppedImage.size.height))")
            } else {
                // Display the original image
                Image(uiImage: originalImage)
                    .resizable()
                    .scaledToFit()
                    .frame(height: 300)
                    .border(Color.blue, width: 2)
            }

            // Crop button
            Button("Crop") {
                croppedImage = cropImageToAspectRatio(image: originalImage, aspectRatio: aspectRatio)
            }
            .padding()

            // Undo button
            Button("Undo") {
                croppedImage = nil
            }
            .padding()
        }
        .padding()
    }

    /// Crops an image to a given aspect ratio
    func cropImageToAspectRatio(image: UIImage, aspectRatio: CGSize) -> UIImage? {
        let originalSize = image.size
        let originalAspect = originalSize.width / originalSize.height
        let targetAspect = aspectRatio.width / aspectRatio.height

        var cropRect: CGRect

        if originalAspect > targetAspect {
            // Image is wider than target aspect ratio
            let newWidth = originalSize.height * targetAspect
            let xOffset = (originalSize.width - newWidth) / 2
            cropRect = CGRect(x: xOffset, y: 0, width: newWidth, height: originalSize.height)
        } else {
            // Image is taller than target aspect ratio
            let newHeight = originalSize.width / targetAspect
            let yOffset = (originalSize.height - newHeight) / 2
            cropRect = CGRect(x: 0, y: yOffset, width: originalSize.width, height: newHeight)
        }

        guard let cgImage = image.cgImage?.cropping(to: cropRect) else {
            print("Cropping failed")
            return nil
        }

        return UIImage(cgImage: cgImage)
    }
}

উপরের কোড গুলতে ইমেজকে সেন্টার ক্রপ করবে। যখন আমাদের ইমেজের একটা নির্দিষ্ট অংশ ক্রপ করতে হবে, তখন ইমেজকে ড্র্যাগ করা এবং জুম করার ফাংশনালিটি যোগ করতে হবে। এবং নির্দিষ্ট মাস্কিং সাইজ অনুযায়ী ইমেজকে পরে ক্রপ করতে হবে। তার জন্য এভাবে কোড লিখতে পারিঃ

import SwiftUI

struct ContentView: View {
    @State private var croppedImage: UIImage?
 

    var body: some View {
        VStack {
            if let croppedImage {
                Image(uiImage: croppedImage)
                    .resizable()
                    .scaledToFit()
                    .frame(width: 200, height: 200)
                    .border(Color.gray, width: 1)
                
     Text("Cropped Image Size: \(Int(croppedImage.size.width)) x \(Int(croppedImage.size.height))")
            } else {
       
                    ZoomableImageView(image: UIImage(named: "image")!, croppingSize: CGSize(width: 200, height: 200))
                        .clipShape(Rectangle())
                        .frame(width: 200, height: 200)
                        .border(Color.blue, width: 1)
                
            }
            
            HStack(spacing: 20){
                Button("Crop") {
                    ZoomableImageView.sharedCrop { image in
                        croppedImage = image
                    }
                }
            
                Button("Undo") {
                    croppedImage = nil
                }
            }
        }
    }
}

struct ZoomableImageView: UIViewRepresentable {
    static var sharedView: ZoomableImageViewCoordinator?

    var image: UIImage
    var croppingSize: CGSize

    func makeCoordinator() -> ZoomableImageViewCoordinator {
        let coordinator = ZoomableImageViewCoordinator(image: image, croppingSize: croppingSize)
        ZoomableImageView.sharedView = coordinator
        return coordinator
    }

    func makeUIView(context: Context) -> UIScrollView {
        let scrollView = UIScrollView()
        scrollView.delegate = context.coordinator
        scrollView.showsHorizontalScrollIndicator = false
        scrollView.showsVerticalScrollIndicator = false
        scrollView.bounces = false
        scrollView.minimumZoomScale = 1.0
        scrollView.maximumZoomScale = 5.0

        // Add the image view to the scroll view
        let imageView = context.coordinator.imageView
        scrollView.addSubview(imageView)

        // Set the content size based on the image
        scrollView.contentSize = imageView.bounds.size
        scrollView.zoomScale = scrollView.minimumZoomScale
        return scrollView
    }

    func updateUIView(_ uiView: UIScrollView, context: Context) {}

    static func sharedCrop(completion: @escaping (UIImage?) -> Void) {
        sharedView?.cropImage(completion: completion)
    }

    class ZoomableImageViewCoordinator: NSObject, UIScrollViewDelegate {
        let imageView: UIImageView
        let croppingSize: CGSize
        let originalImage: UIImage

        init(image: UIImage, croppingSize: CGSize) {
            self.imageView = UIImageView(image: image)
            self.croppingSize = croppingSize
            self.originalImage = image

            super.init()

            // Configure the image view to fit the original ratio
            let aspectRatio = image.size.width / image.size.height
            let maskAspectRatio = croppingSize.width / croppingSize.height

            if aspectRatio > maskAspectRatio {
                let height = croppingSize.height
                let width = height * aspectRatio
                self.imageView.frame = CGRect(x: 0, y: 0, width: width, height: height)
            } else {
                let width = croppingSize.width
                let height = width / aspectRatio
                self.imageView.frame = CGRect(x: 0, y: 0, width: width, height: height)
            }

            self.imageView.contentMode = .scaleAspectFill
        }

        func viewForZooming(in scrollView: UIScrollView) -> UIView? {
            return imageView
        }

        func cropImage(completion: @escaping (UIImage?) -> Void) {
            guard let scrollView = imageView.superview as? UIScrollView else {
                completion(nil)
                return
            }

            // Calculate the scale factor between the original image and the displayed image
            let imageViewScale = originalImage.size.width / imageView.bounds.width

            // Adjust visible rect for the zoom scale
            let zoomScale = scrollView.zoomScale
            let offset = scrollView.contentOffset

            // Calculate the visible rect in the image view's coordinate space
            let visibleRect = CGRect(
                x: offset.x * imageViewScale / zoomScale,
                y: offset.y * imageViewScale / zoomScale,
                width: croppingSize.width * imageViewScale / zoomScale,
                height: croppingSize.height * imageViewScale / zoomScale
            )

            // Perform cropping
            guard let croppedCGImage = originalImage.cgImage?.cropping(to: visibleRect) else {
                completion(nil)
                return
            }

            // Convert the cropped CGImage back to UIImage
            let croppedUIImage = UIImage(cgImage: croppedCGImage)
            completion(croppedUIImage)
        }
    }
}

এখানে ইমেজকে জুম করার পাশাপাশি ড্র্যাগ করা যাবে। এরপর মাস্কিং সাইজ অনুযায়ী ইমেজ ক্রপ করে দিবে।

Leave a Reply