Files
FancyBot/src/main/kotlin/cn/rtast/fancybot/commands/parse/AsciiArtCommand.kt
T

114 lines
4.4 KiB
Kotlin
Raw Normal View History

2024-09-20 13:30:52 +08:00
/*
* Copyright © 2024 RTAkland
* Author: RTAkland
* Date: 2024/9/20
*/
package cn.rtast.fancybot.commands.parse
import cn.rtast.fancybot.annotations.CommandDescription
2024-09-20 13:30:52 +08:00
import cn.rtast.fancybot.util.str.encodeToBase64
import cn.rtast.fancybot.util.toByteArray
import cn.rtast.rob.entity.GroupMessage
import cn.rtast.rob.enums.ArrayMessageType
import cn.rtast.rob.util.BaseCommand
import cn.rtast.rob.util.ob.MessageChain
import cn.rtast.rob.util.ob.OneBotListener
2024-09-25 18:18:28 +08:00
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
2024-09-20 13:30:52 +08:00
import java.awt.Color
import java.awt.Font
import java.awt.image.BufferedImage
import java.net.URI
import javax.imageio.ImageIO
import kotlin.math.roundToInt
@CommandDescription("将图片转换成ASCII字符画!")
2024-09-20 13:30:52 +08:00
class AsciiArtCommand : BaseCommand() {
2024-09-20 14:05:20 +08:00
override val commandNames = listOf("/ascii", "/asc")
2024-09-20 13:30:52 +08:00
2024-09-20 14:05:20 +08:00
companion object {
private const val FONT_SIZE = 12
private val font = Font("Monospaced", Font.PLAIN, FONT_SIZE)
val waitingList = mutableListOf<Long>()
2024-09-20 13:30:52 +08:00
2024-09-20 14:05:20 +08:00
private fun BufferedImage.convertToAscii(): String {
val width = this.width
val height = this.height
val asciiArt = StringBuilder()
for (y in 0 until height step 2) {
for (x in 0 until width) {
val pixel = Color(this.getRGB(x, y))
val luminance = (0.2126 * pixel.red + 0.7152 * pixel.green + 0.0722 * pixel.blue).roundToInt()
val asciiChar = when (luminance) {
in 0..15 -> ' '
in 16..31 -> '.'
in 32..47 -> ':'
in 48..63 -> '-'
in 64..79 -> '='
in 80..95 -> '+'
in 96..111 -> '*'
in 112..127 -> '#'
in 128..143 -> '%'
in 144..159 -> '@'
in 160..175 -> 'a'
in 176..191 -> 'o'
in 192..207 -> 'e'
in 208..223 -> 'h'
in 224..239 -> 'u'
else -> '$'
}
asciiArt.append(asciiChar)
2024-09-20 13:30:52 +08:00
}
2024-09-20 14:05:20 +08:00
asciiArt.append("\n")
2024-09-20 13:30:52 +08:00
}
2024-09-20 14:05:20 +08:00
return asciiArt.toString()
}
private fun String.saveAsciiArtToImage(width: Int, height: Int): String {
val imgWidth = width * FONT_SIZE / 2
val imgHeight = height * FONT_SIZE / 2
val img = BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB)
val g2d = img.createGraphics()
g2d.color = Color.BLACK
g2d.fillRect(0, 0, imgWidth, imgHeight)
g2d.color = Color.WHITE
g2d.font = font
val lines = this.split("\n")
for ((index, line) in lines.withIndex()) {
g2d.drawString(line, 0, (index + 1) * FONT_SIZE)
}
g2d.dispose()
return img.toByteArray().encodeToBase64()
2024-09-20 13:30:52 +08:00
}
2024-09-20 14:05:20 +08:00
suspend fun callback(message: GroupMessage) {
if (message.sender.userId in waitingList) {
if (message.message.any { it.type == ArrayMessageType.image }) {
val url = message.message.find { it.type == ArrayMessageType.image }!!.data.file!!
2024-09-25 18:23:27 +08:00
val bufferedImage = withContext(Dispatchers.IO) { ImageIO.read(URI(url).toURL()) }
2024-09-20 14:05:20 +08:00
val imageBase64 =
bufferedImage.convertToAscii().saveAsciiArtToImage(bufferedImage.width, bufferedImage.height)
val msg = MessageChain.Builder().addImage(imageBase64, true).build()
message.reply(msg)
} else {
message.reply("回复错误已取消本次操作")
}
waitingList.removeIf { it == message.sender.userId }
}
2024-09-20 13:30:52 +08:00
}
}
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
2024-09-20 14:05:20 +08:00
if (message.sender.userId !in waitingList) {
2024-09-20 14:11:10 +08:00
message.reply("请继续发送一张图片,如果输入错误则取消本次操作")
2024-09-20 14:05:20 +08:00
waitingList.add(message.sender.userId)
2024-09-20 13:30:52 +08:00
return
} else {
2024-09-20 14:05:20 +08:00
message.reply("先发送`/ascii`再继续操作吧~")
return
2024-09-20 13:30:52 +08:00
}
}
}