ios - UIImageView को 'पहलू भरण' मोड में एक नए UIImage में कैसे क्रॉप करें?



objective-c iphone (1)

आइए समस्या को दो भागों में विभाजित करते हैं:

  1. UIImageView के आकार और उसके UIImage के आकार को देखते हुए, यदि UIImageView का कंटेंट मोड Aspect Fill है, तो UIImageView में फिट होने वाले UIImage का क्या हिस्सा है? UIImageView वास्तव में प्रदर्शित हो रहा है या नहीं, इसके लिए हमें मूल छवि को क्रॉप करने की आवश्यकता है।

  2. UIImageView के भीतर एक मनमानी परिभाषा को देखते हुए, क्रॉप्ड इमेज (भाग 1 में प्राप्त) का कौन सा हिस्सा इसके अनुरूप है?

पहला भाग दिलचस्प हिस्सा है, तो चलिए इसे आज़माते हैं। (फिर दूसरा भाग तुच्छ होगा।)

यहाँ मूल छवि का उपयोग करूँगा:

https://static1.squarespace.com/static/54e8ba93e4b07c3f655b452e/t/56c2a04520c64707756f4267/1455596221531/

वह चित्र 1000x611 है। यहां बताया गया है कि यह नीचे की ओर कैसा दिखता है (लेकिन ध्यान रखें कि मैं मूल छवि का उपयोग करने जा रहा हूं):

हालाँकि, मेरा चित्र दृश्य 139x182 होगा, और इसे एस्पेक्ट फिल में सेट किया गया है। जब यह छवि प्रदर्शित करता है, तो यह इस तरह दिखता है:

जिस समस्या को हम हल करना चाहते हैं वह है: मेरी छवि दृश्य में मूल छवि का कौन सा भाग प्रदर्शित किया जा रहा है, यदि मेरी छवि दृश्य पहलू भरण के लिए सेट है?

ये रहा। मान लें कि iv छवि दृश्य है:

let imsize = iv.image!.size
let ivsize = iv.bounds.size

var scale : CGFloat = ivsize.width / imsize.width
if imsize.height * scale < ivsize.height {
    scale = ivsize.height / imsize.height
}

let croppedImsize = CGSize(width:ivsize.width/scale, height:ivsize.height/scale)
let croppedImrect =
    CGRect(origin: CGPoint(x: (imsize.width-croppedImsize.width)/2.0,
                           y: (imsize.height-croppedImsize.height)/2.0),
           size: croppedImsize)

तो अब हमने इस समस्या को हल कर लिया है: croppedImrect मूल छवि का क्षेत्र है जो छवि दृश्य में दिखाई दे रहा है। आइए अपने ज्ञान का उपयोग करने के लिए आगे बढ़ें, वास्तव में छवि को एक नई छवि से मिलान करते हुए जो छवि दृश्य में दिखाया गया है:

let r = UIGraphicsImageRenderer(size:croppedImsize)
let croppedIm = r.image { _ in
    iv.image!.draw(at: CGPoint(x:-croppedImrect.origin.x, y:-croppedImrect.origin.y))
}

परिणाम इस छवि है (ग्रे बॉर्डर की उपेक्षा):

लेकिन लो और निहारना, यह सही जवाब है! मैंने मूल छवि से निकाला है बिल्कुल छवि दृश्य के इंटीरियर में चित्रित क्षेत्र।

तो अब आपके पास वो सारी जानकारी है जो आपको चाहिए। croppedIm , UIImage है जो वास्तव में छवि दृश्य के क्लिप्ड क्षेत्र में प्रदर्शित होता है। scale इमेज व्यू और उस इमेज के बीच का scale है। इसलिए, आप मूल रूप से प्रस्तावित समस्या को आसानी से हल कर सकते हैं! छवि दृश्य पर लगाए गए किसी भी आयत को देखते हुए, छवि दृश्य की सीमा में निर्देशांक, आप बस स्केल लागू करते हैं (यानी इसके चारों विशेषताओं को scale से विभाजित करते हैं) - और अब आपके पास croppedIm एक हिस्से के रूप में एक ही आयत है।

(ध्यान दें कि हमें वास्तव में फसल की मूल छवि प्राप्त करने की आवश्यकता नहीं थी; यह पर्याप्त था, वास्तविकता में, यह जानने के लिए कि उस फसल को कैसे किया जाए। महत्वपूर्ण जानकारी फसल की origin के साथ scale पर है। यह जानकारी दी गई है; आप छवि दृश्य पर लगाए गए आयत को ले सकते हैं, इसे स्केल कर सकते हैं, और मूल छवि के वांछित आयत को प्राप्त करने के लिए इसे ऑफसेट कर सकते हैं।)

EDIT मैंने केवल यह दर्शाने के लिए एक छोटा सा पेंच जोड़ा कि मेरा दृष्टिकोण अवधारणा के प्रमाण के रूप में काम करता है:

EDIT ने यहां एक डाउनलोड करने योग्य उदाहरण परियोजना भी बनाई:

https://github.com/mattneub/Programming-iOS-Book-Examples/blob/39cc800d18aa484d17c26ffcbab8bbe51c614573/bk2ch02p058cropImageView/Cropper/ViewController.swift

लेकिन ध्यान दें कि मैं गारंटी नहीं दे सकता कि URL हमेशा के लिए रहेगा, इसलिए कृपया उपयोग किए गए दृष्टिकोण को समझने के लिए ऊपर चर्चा पढ़ें।

मैं एक ओवरले UIView का उपयोग करके एक छवि दृश्य की उप-छवि को क्रॉप करने की कोशिश कर रहा हूं जो कि UIImageView में कहीं भी तैनात किया जा सकता है। जब UIImageView सामग्री मोड 'Aspect Fit' हो, तो इसे कैसे हल किया जाए, इसी तरह की पोस्ट से मैं एक समाधान उधार ले रहा हूं। यह प्रस्तावित समाधान है:

  func computeCropRect(for sourceFrame : CGRect) -> CGRect {

        let widthScale = bounds.size.width / image!.size.width
        let heightScale = bounds.size.height / image!.size.height

        var x : CGFloat = 0
        var y : CGFloat = 0
        var width : CGFloat = 0
        var height : CGFloat = 0
        var offSet : CGFloat = 0

        if widthScale < heightScale {
            offSet = (bounds.size.height - (image!.size.height * widthScale))/2
            x = sourceFrame.origin.x / widthScale
            y = (sourceFrame.origin.y - offSet) / widthScale
            width = sourceFrame.size.width / widthScale
            height = sourceFrame.size.height / widthScale
        } else {
            offSet = (bounds.size.width - (image!.size.width * heightScale))/2
            x = (sourceFrame.origin.x - offSet) / heightScale
            y = sourceFrame.origin.y / heightScale
            width = sourceFrame.size.width / heightScale
            height = sourceFrame.size.height / heightScale
        }

        return CGRect(x: x, y: y, width: width, height: height)
    }

समस्या यह है कि इस समाधान का उपयोग करते समय जब छवि दृश्य पहलू भर जाती है, तो क्रॉप्ड सेगमेंट ठीक उसी तरह से लाइन नहीं होता है, जहां ओवरले UIView तैनात था। मुझे पूरा यकीन नहीं है कि एस्पेक्ट फिल के लिए समायोजित करने के लिए इस कोड को कैसे अनुकूलित किया जाए या मेरे ओवरले UIView जाए, ताकि मैं उस फसल के साथ 1: 1 तक की पंक्तियों के साथ काम कर सकूं।

नीचे दिए गए मैट के उत्तर का उपयोग कर अद्यतन किया

class ViewController: UIViewController {

    @IBOutlet weak var catImageView: UIImageView!
    private var cropView : CropView!

    override func viewDidLoad() {
        super.viewDidLoad()

        cropView = CropView(frame: CGRect(x: 0, y: 0, width: 45, height: 45))

        catImageView.image = UIImage(named: "cat")
        catImageView.clipsToBounds = true

        catImageView.layer.borderColor = UIColor.purple.cgColor
        catImageView.layer.borderWidth = 2.0
        catImageView.backgroundColor = UIColor.yellow

        catImageView.addSubview(cropView)

        let imageSize = catImageView.image!.size
        let imageViewSize = catImageView.bounds.size

        var scale : CGFloat = imageViewSize.width / imageSize.width

        if imageSize.height * scale < imageViewSize.height {
            scale = imageViewSize.height / imageSize.height
        }

        let croppedImageSize = CGSize(width: imageViewSize.width/scale, height: imageViewSize.height/scale)

        let croppedImrect =
            CGRect(origin: CGPoint(x: (imageSize.width-croppedImageSize.width)/2.0,
                                   y: (imageSize.height-croppedImageSize.height)/2.0),
                   size: croppedImageSize)

        let renderer = UIGraphicsImageRenderer(size:croppedImageSize)

        let _ = renderer.image { _ in
            catImageView.image!.draw(at: CGPoint(x:-croppedImrect.origin.x, y:-croppedImrect.origin.y))
        }
    }


    @IBAction func performCrop(_ sender: Any) {
        let cropFrame = catImageView.computeCropRect(for: cropView.frame)
        if let imageRef = catImageView.image?.cgImage?.cropping(to: cropFrame) {
            catImageView.image = UIImage(cgImage: imageRef)
        }
    }

    @IBAction func resetCrop(_ sender: Any) {
        catImageView.image = UIImage(named: "cat")
    }
}

अंतिम परिणाम





uiimageview