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)
}
}
}