iOS/WAStickersThirdParty/Sticker.swift (59 lines of code) (raw):

// // Copyright (c) WhatsApp Inc. and its affiliates. // All rights reserved. // // This source code is licensed under the BSD-style license found in the // LICENSE file in the root directory of this source tree. // import UIKit struct StickerEmojis { static func canonicalizedEmojis(rawEmojis: [String]?) throws -> [String]? { guard let rawEmojis = rawEmojis else { return nil } if rawEmojis.count > Limits.MaxEmojisCount { throw StickerPackError.tooManyEmojis } var canonicalizedEmojis: [String] = [] rawEmojis.forEach { rawEmoji in var emojiToAdd = canonicalizedEmoji(emoji: rawEmoji) // If the emoji somehow isn't canonicalized, we'll use the original emoji if emojiToAdd.isEmpty { emojiToAdd = rawEmoji } canonicalizedEmojis.append(emojiToAdd) } return canonicalizedEmojis } private static func canonicalizedEmoji(emoji: String) -> String { var nonExtensionUnicodes: [Character] = [] for scalar in emoji.unicodeScalars { switch scalar.value { case 0x1F600...0x1F64F, // Emoticons 0x1F300...0x1F5FF, // Misc symbols and pictographs 0x1F680...0x1F6FF, // Transport and maps 0x2600...0x26FF, // Misc symbols 0x2700...0x27BF, // Dingbats 0x1F1E6...0x1F1FF, // Flags 0x1F900...0x1F9FF, // Supplemental symbols and pictographs 0x200D: // Zero-width joiner nonExtensionUnicodes.append(Character(UnicodeScalar(scalar.value)!)) default: continue } } var canonicalizedEmoji = "" nonExtensionUnicodes.forEach { canonicalizedEmoji.append($0) } return canonicalizedEmoji } } /** * Main class that deals with each individual sticker. */ class Sticker { let imageData: ImageData let emojis: [String]? var bytesSize: Int64 { return imageData.bytesSize } /** * Initializes a sticker with an image file and emojis. * * - Parameter filename: name of the image in the bundle, including extension. Must be either png or webp. * - Parameter emojis: emojis associated with this sticker. * * - Throws: - .fileNotFound if file has not been found - .unsupportedImageFormat if image is not png or webp - .imageTooBig if the image file size is above the supported limit (100KB for static, 500KB for animated) - .invalidImage if the image file size is 0KB - .incorrectImageSize if the image is not within the allowed size - .tooManyEmojis if there are too many emojis assigned to the sticker - .minFrameDurationTooShort if the minimum frame duration is too short (less than 8ms) - .totalAnimationDurationTooLong if the total animation duration is too long (more than 10s) */ init(contentsOfFile filename: String, emojis: [String]?) throws { self.imageData = try ImageData.imageDataIfCompliant(contentsOfFile: filename, isTray: false) self.emojis = try StickerEmojis.canonicalizedEmojis(rawEmojis: emojis) } /** * Initializes a sticker with image data, type and emojis. * * - Parameter imageData: Data of the image. Must be png or webp encoded data * - Parameter type: format type of the sticker (png or webp) * - Parameter emojis: array of emojis associated with this sticker. * * - Throws: - .imageTooBig if the image file size is above the supported limit (100KB for static, 500KB for animated) - .invalidImage if the image file size is 0KB - .incorrectImageSize if the image is not within the allowed size - .tooManyEmojis if there are too many emojis assigned to the sticker - .minFrameDurationTooShort if the minimum frame duration is too short (less than 8ms) - .totalAnimationDurationTooLong if the total animation duration is too long (more than 10s) */ init(imageData: Data, type: ImageDataExtension, emojis: [String]?) throws { self.imageData = try ImageData.imageDataIfCompliant(rawData:imageData, extensionType: type, isTray: false) self.emojis = try StickerEmojis.canonicalizedEmojis(rawEmojis: emojis) } func copyToPasteboardAsImage() { if let image = imageData.image { Interoperability.copyImageToPasteboard(image: image) } } }