NSAttributedString: Fit image to container

后端 未结 3 1175
误落风尘
误落风尘 2020-12-31 19:04

I have a NSAttributedString which is made from HTML and it displays some images. The problem is that the images are bigger than the container and I wonder how to fit them in

相关标签:
3条回答
  • 2020-12-31 19:44

    Swift 4.2 : Using the approach of @Nic Hubbard

    let htmlString = "Put Your YourHTML String Here"
    
    let setHeightUsingCSS = "<head><style type=\"text/css\"> img{ max-height: 100%; max-width: \(self.textView.frame.size.width) !important; width: auto; height: auto;} </style> </head><body> \(htmlString) </body>"
    
    self.textView.attributedText = setHeightUsingCSS.html2AttributedString
    
    
    extension Data {
        var html2AttributedString: NSAttributedString? {
            do {
                return try NSAttributedString(data: self, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)
            } catch {
                print("error:", error)
                return  nil
            }
        }
        var html2String: String {
            return html2AttributedString?.string ?? ""
        }
    }
    
    extension String {
        var html2AttributedString: NSAttributedString? {
            return Data(utf8).html2AttributedString
        }
        var html2String: String {
            return html2AttributedString?.string ?? ""
        }
    }
    

    extension reference

    0 讨论(0)
  • 2020-12-31 19:51

    I finally found how to do that:

    content.enumerateAttribute(NSAttachmentAttributeName, inRange: NSMakeRange(0, content.length), options: NSAttributedStringEnumerationOptions(0)) { (value, range, stop) -> Void in
        if let attachement = value as? NSTextAttachment {
            let image = attachement.imageForBounds(attachement.bounds, textContainer: NSTextContainer(), characterIndex: range.location)
            let screenSize: CGRect = UIScreen.mainScreen().bounds
            if image.size.width > screenSize.width-2 {
                let newImage = image.resizeImage((screenSize.width-2)/image.size.width)
                let newAttribut = NSTextAttachment()
                newAttribut.image = newImage
                content.addAttribute(NSAttachmentAttributeName, value: newAttribut, range: range)
            }
        }
    }
    

    The function resizeImage() is defined like that:

    extension UIImage {
        func resizeImage(scale: CGFloat) -> UIImage {
            let newSize = CGSizeMake(self.size.width*scale, self.size.height*scale)
            let rect = CGRectMake(0, 0, newSize.width, newSize.height)
    
            UIGraphicsBeginImageContext(newSize)
            self.drawInRect(rect)
            let newImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return newImage
        }
    }
    

    Swift 3 version

    text.enumerateAttribute(NSAttachmentAttributeName, in: NSMakeRange(0, text.length), options: .init(rawValue: 0), using: { (value, range, stop) in
        if let attachement = value as? NSTextAttachment {
            let image = attachement.image(forBounds: attachement.bounds, textContainer: NSTextContainer(), characterIndex: range.location)!
            let screenSize: CGRect = UIScreen.main.bounds
            if image.size.width > screenSize.width-20 {
                let newImage = image.resizeImage(scale: (screenSize.width-2)/image.size.width)
                let newAttribut = NSTextAttachment()
                newAttribut.image = newImage
                text.addAttribute(NSAttachmentAttributeName, value: newAttribut, range: range)
            }
        }
    })
    

    The function resizeImage() is defined like that:

    func resizeImage(scale: CGFloat) -> UIImage {
        let newSize = CGSize(width: self.size.width*scale, height: self.size.height*scale)
        let rect = CGRect(origin: CGPoint.zero, size: newSize)
    
        UIGraphicsBeginImageContext(newSize)
        self.draw(in: rect)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage!
    }
    

    Swift 4 version + Extension and customisable max width for image

    extension NSAttributedString {
        func attributedStringWithResizedImages(with maxWidth: CGFloat) -> NSAttributedString {
            let text = NSMutableAttributedString(attributedString: self)
            text.enumerateAttribute(NSAttributedStringKey.attachment, in: NSMakeRange(0, text.length), options: .init(rawValue: 0), using: { (value, range, stop) in
                if let attachement = value as? NSTextAttachment {
                    let image = attachement.image(forBounds: attachement.bounds, textContainer: NSTextContainer(), characterIndex: range.location)!
                    if image.size.width > maxWidth {
                        let newImage = image.resizeImage(scale: maxWidth/image.size.width)
                        let newAttribut = NSTextAttachment()
                        newAttribut.image = newImage
                        text.addAttribute(NSAttributedStringKey.attachment, value: newAttribut, range: range)
                    }
                }
            })
            return text
        }
    }
    
    extension UIImage {
        func resizeImage(scale: CGFloat) -> UIImage {
            let newSize = CGSize(width: self.size.width*scale, height: self.size.height*scale)
            let rect = CGRect(origin: CGPoint.zero, size: newSize)
    
            UIGraphicsBeginImageContext(newSize)
            self.draw(in: rect)
            let newImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return newImage!
        }
    }
    
    0 讨论(0)
  • 2020-12-31 19:55

    You can also wrap the string in a full HTML document and use CSS for the image sizing.

    0 讨论(0)
提交回复
热议问题