我计划将文本转换为表情符号。但是,我不知道如何开始。以下是我正在寻找的一些屏幕截图。
我的想法是,为了达到上述结果,我们应该为每个字符保存字典,但问题是该字典将如何根据字符结构保存表情符号。
答案 0 :(得分:4)
我建议您使用简单的位图技术。在第一步中,您将构建一个黑白位图,其中书写文本的尺寸与您想要的最终图像相同。
在第二步中,您将此图像“划分”为光栅,例如比最终的表情符号字符小20%,以创建重叠效果。
在每个栅格矩形中,您可以计算黑色像素。你得到0-100%黑色像素的百分比。如果这个百分比例如超过40%,则在该矩形的中心放置一个随机表情符号。
您可以通过添加少量随机位移来改善效果。
我实现了这个并且效果很好。我可以通过一些小的优化来进一步改善图像:
例如,如果我得到1000
,我会将其移到左上角。如果我在左边1010
。
以下示例代码演示了所示的方法,没有“最终思考”部分中的调整。它是用Swift编写的Cocoa应用程序。您将看到一个简单应用程序的应用程序委托,该应用程序在主窗口中提供文本字段和图像视图。
您可以完成将文本字段和图片视图添加到主窗口的应用程序,并将值绑定到出口textField
和imageView
。您还必须将文本字段值绑定到parameterText
属性。
应用程序的输出如下所示:
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
@IBOutlet weak var textField: NSTextField!
@IBOutlet weak var imageView: NSImageView!
var updateTimer: NSTimer = NSTimer()
let canvasSize = CGSize(width: 1024, height: 768)
let canvasPadding: CGFloat = 32.0
let emojiSize = 20.0
let emojiSet: [NSString] = ["","","",""]
let emojiJitter = 4.0
var parameterText: NSString = "Hello!" {
didSet {
triggerImageUpdate()
}
}
func applicationDidFinishLaunching(aNotification: NSNotification) {
triggerImageUpdate()
}
func applicationWillTerminate(aNotification: NSNotification) {
}
func triggerImageUpdate() {
updateTimer.invalidate()
updateTimer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: Selector("updateImage"), userInfo: nil, repeats: false);
}
func updateImage() {
imageView.image = createEmojiImage(parameterText, size: canvasSize, padding: canvasPadding)
}
// This function creates a simple bitmap with the given text. The text
// is centered in the bitmap and scaled to the maximum size.
func createTextImage(text: NSString, size: CGSize, padding: CGFloat) -> NSImage {
let canvasRect = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height)
let textRect = CGRectInset(canvasRect, padding, padding)
var textBitmap = NSImage(size: size)
textBitmap.lockFocus()
NSColor.whiteColor().setFill()
NSRectFill(canvasRect)
let textFont = NSFont(name: "Helvetica Bold", size: 100)
var textAttributes: [NSObject: AnyObject] = [
NSFontAttributeName: textFont!,
NSForegroundColorAttributeName: NSColor.blackColor()]
let textSize = text.sizeWithAttributes(textAttributes);
let scaleWidth = textRect.size.width/textSize.width
let scaleHeight = textRect.size.height/textSize.height
let scale: CGFloat
if (scaleWidth < scaleHeight) {
scale = scaleWidth
} else {
scale = scaleHeight
}
let scaledCanvasSize = CGSize(width: size.width/scale, height: size.height/scale)
let offset = CGPoint(x: (scaledCanvasSize.width - textSize.width)/2.0,
y: (scaledCanvasSize.height - textSize.height)/2.0)
CGContextScaleCTM(NSGraphicsContext.currentContext()!.CGContext, scale, scale)
text.drawAtPoint(offset, withAttributes: textAttributes)
textBitmap.unlockFocus()
return textBitmap
}
func createTextBitmap(text: NSString, size: CGSize, padding: CGFloat) -> NSBitmapImageRep {
let textImage = createTextImage(text, size: size, padding: padding)
let tiffImageData = textImage.TIFFRepresentation
return NSBitmapImageRep(data: tiffImageData!)!
}
// This is a class which represents a single field.
class Field {
let center: CGPoint
let black: Double
init(center: CGPoint, black: Double) {
self.center = center
self.black = black
}
}
// A function to get the black value from a certain rectangle in an image.
func blackValue(image: NSBitmapImageRep, rect: CGRect) -> Double {
let pixelInRect = Int(rect.size.width * rect.size.height)
var blackCount = 0;
for (var x = 0; x < Int(rect.size.width); ++x) {
for (var y = 0; y < Int(rect.size.height); ++y) {
var color = image.colorAtX(Int(rect.origin.x), y: Int(rect.origin.y))!
if (color.redComponent < 0.1) {
blackCount++
}
}
}
return Double(blackCount) / Double(pixelInRect)
}
// A function to rasterize the bitmap into single fields.
func rasterizeBitmap(image: NSBitmapImageRep, size: CGFloat) -> (width: Int, fields: [Field]) {
let width = Int(image.size.width/size)
let height = Int(image.size.height/size)
var fields = [Field]()
for (var x = 0; x < width; ++x) {
for (var y = 0; y < height; ++y) {
let rect = CGRect(x: CGFloat(x) * size, y: CGFloat(y) * size, width: size, height: size)
let center = CGPoint(x: floor(CGFloat(x) * size + size/2.0), y: image.size.height - floor(CGFloat(y) * size + size/2.0))
let black = blackValue(image, rect: rect)
var field = Field(center: center, black: black)
fields.append(field)
}
}
return (width, fields)
}
// Function to create the emoji image.
func createEmojiImage(text: NSString, size: CGSize, padding: CGFloat) -> NSImage {
// Create and rasterize the bitmap.
let textBitmap = self.createTextBitmap(text, size: size, padding: padding)
let (fieldsWidth, fields) = self.rasterizeBitmap(textBitmap, size: CGFloat(emojiSize*0.75))
// Create a new image
var result = NSImage(size: size)
result.lockFocus()
NSColor.whiteColor().setFill()
let canvasRect = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height)
NSRectFill(canvasRect)
let textFont = NSFont(name: "Apple Color Emoji", size: CGFloat(self.emojiSize))
var textAttributes: [NSObject: AnyObject] = [NSFontAttributeName: textFont!]
NSColor.blackColor().setFill()
for field in fields {
let jitterX = CGFloat(Double(arc4random_uniform(101))/100.0*self.emojiJitter-self.emojiJitter/2.0)
let jitterY = CGFloat(Double(arc4random_uniform(101))/100.0*self.emojiJitter-self.emojiJitter/2.0)
if field.black > 0.4 {
var randomEmoji = self.emojiSet[Int(arc4random_uniform(UInt32(self.emojiSet.count)))]
var drawingPoint = CGPoint(x: field.center.x - CGFloat(self.emojiSize/2.0) + jitterX, y: field.center.y - CGFloat(self.emojiSize/2.0) + jitterY)
randomEmoji.drawAtPoint(drawingPoint, withAttributes: textAttributes)
}
}
result.unlockFocus()
return result
}
}