Замена изображения в NSAttributedString - PullRequest
2 голосов
/ 06 января 2020

Я пытаюсь заменить изображение в NSAttributedString его уменьшенной копией (чтобы соответствовать ширине UITextView), однако во многих (не во всех) случаях замененное изображение представляет собой маску оригинал. Я предполагаю, что есть что-то в других атрибутах строки, которые делают это, так как и извлечение изображения, и создание новой атрибутной строки из изображения работают отлично.

Примечание: ответы, подобные этому как изменить размер изображения или сделать как NSAttributedString NSTextAttachment (или установить его начальный размер) показать, как создать строку с изображениями (что я могу сделать) или как изменить размер текстового вложения (опять же, я могу сделать это) до создания строки, но не как изменить вместо .

Обновление Благодаря предложениям комментатора @Larme я теперь решил свою первоначальную проблему изменения размера изображения на месте путем изменения исходного NSTextAttachment.bounds - обратите внимание, не заменяя его, изменив его in situ . Я не собираюсь публиковать это как ответ на свой вопрос, так как он не отвечает на более широкий вопрос о замене изображения.

Любые советы о том, как действовать с благодарностью, приняты.

Вот основа:

extension NSAttributedString {
    func resizeAttachments(maxWidth: CGFloat) -> NSAttributedString {

        var replacement = NSMutableAttributedString(attributedString: self)

        func replace(_ image: UIImage, in range: NSRange, dict: [NSAttributedString.Key : Any]) {
            // ... see below for variants of this
        }

        self.enumerateAttributes(in: NSMakeRange(0, self.length),
                                 options: [],
                                 using: {dict, range, stop in
            for (key, value) in dict {
                if key == .attachment, let attachment = value as? NSTextAttachment {
                    if
                        let fw = attachment.fileWrapper, fw.isRegularFile,
                        let d = fw.regularFileContents,
                        let image = UIImage(data: d)?.resized(toWidth: maxWidth) { 
                        // removing the resize above makes no difference to the issue
                        // i.e. replacing the image with itself still causes the same problem
                        replace(image, in: range, dict: dict)
                        return // Exit the block. Can't have 2 .attachments.
                    }
                }
            }
        })
        return replacement
    }
}

Пока что прямое перечисление self изменяет изменяемый скопировать строку replacement при обнаружении изображения. Вот что я получаю:

enter image description here

Из этого немасштабированного оригинала:

enter image description here

Итак, что я попробовал в функции замены?

    func replace(_ image: UIImage, in range: NSRange, dict: [NSAttributedString.Key : Any]) {
        let newAttachment = NSTextAttachment(image: image)
        let newCharacter = NSMutableAttributedString(attachment: newAttachment)
        // NB if I replace the entire string with `newCharacter` the image is perfect (but obviously the rest of the string has gone)

        // Option 1
        replacement.replaceCharacters(in: range, with: newCharacter)

        // Option 2
        var newDict: [NSAttributedString.Key : Any] = dict
        newDict[.attachment] = newAttachment
        replacement.addAttributes(newDict, range: range)

        // Option 3
        replacement.removeAttribute(.attachment, range: range)
        replacement.addAttribute(.attachment, value: newAttachment, range: range)

    }

Я ничего не могу найти о фактической замене изображений. Как я уже сказал, извлечение изображения работает нормально - если я просто верну новую атрибутивную строку только с извлеченным изображением, то это идеально. Если я добавлю изображение до конца, это работает. Это модифицирует это в месте, которое, кажется, проблема. Кто-нибудь когда-нибудь делал это успешно?

...