Instruction

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Enabling Rich Text Input

Instantiate a UITextView or UITextField and do the following:

let textView = UITextView()
// ...
// Enable paste with NSAdaptiveImageGlyphs
textView.pasteConfiguration = UIPasteConfiguration(acceptableTypeIdentifiers: [
  "public.text",
  "public.image",
  "public.heic"   // UTI for NSAdaptiveImageGlyphs
])

Storing Rich Text

To store your rich text, serialize the content of the text view into an RTFD data object and store it in your database.

// Extract contents of text view as an NSAttributedString
let textContents = textView.textStorage

// Serialize as data for storage or transport
let rtfData = try textContents.data(
  from: NSRange(location: 0, length: textContents.length),
  documentAttributes: [.documentType: NSAttributedString.DocumentType.rtfd]
)
// Create attributed string from serialized data
let textFromData = try NSAttributedString(data: rtfData, documentAttributes: nil)

// Set on text view
textView.textStorage.setAttributedString(textFromData)

Plain Text: Inline Image

If you need to transfer your image glyphs to plain text or other non-RTF data stores, handle them the same way you may already support inline images today. For example, store the Unicode attachment character NSAttachmentCharacter 0xFFFC at the appropriate text location along with a reference to the image glyph’s identifier in the plain text data field and add the image to the image store. Because an image glyph’s contentIdentifier is unique and stable, you only need to store it once.

// Decompose an NSAttributedString
func decomposeAttributedString(_ attrStr: NSAttributedString)
  -> (String, [(NSRange, String)], [String: Data]) {

  let string = attrStr.string
  var imageRanges: [(NSRange, String)] = []
  var imageData: [String: Data] = [:]
  attrStr.enumerateAttribute(
    .adaptiveImageGlyph, 
    in: NSMakeRange(0, attrStr.length)) { (value, range, stop) in
    
    if let glyph = value as? NSAdaptiveImageGlyph {
      let id = glyph.contentIdentifier
      imageRanges.append((range, id))
      if imageData[id] == nil {
        imageData[id] = glyph.imageContent
      }
    }
  }
  return (string, imageRanges, imageData)
}

// Recompose an attributed string
func recomposeAttributedString(string: String,
                               imageRanges: [(NSRange, String)],
                               imageData: [String: Data]) -> NSAttributedString {
  let attrStr: NSMutableAttributedString = .init(string: string)
  var images: [String: NSAdaptiveImageGlyph] = [:]
  for (id, data) in imageData {
    images[id] = NSAdaptiveImageGlyph(imageContent: data)
  }
  for (range, id) in imageRanges {
    attrStr.addAttribute(.adaptiveImageGlyph, value: images[id]!, range: range)
  }
  return attrStr
}

Cross-Platform Genmoji Display: HTML

To display an image glyph in HTML, use the same data(from:length:documentAttributes:) that converted textContents to RTFD, but specify the HTML document type:

// Converting NSAttributedString to HTML
let htmlData = try textContent.data(
  from: NSRange(location: 0, length: textContent.length),
  documentAttributes: [.documentType: NSAttributedString.DocumentType.html]
)
See forum comments
Download course materials from Github
Previous: Introduction Next: Foreword