feat: add image bed command

This commit is contained in:
2024-10-09 13:06:43 +08:00
parent b660b504fd
commit 06a385db1a
31 files changed
+113 -63

No files matched your search

@@ -0,0 +1,18 @@
/*
* Copyright © 2024 RTAkland
* Author: RTAkland
* Date: 2024/8/29
*/
package cn.rtast.fancybot.util.misc
import java.time.Instant
import java.time.ZoneId
fun Long.isSameDay(timestamp2: Long): Boolean {
val zoneId = ZoneId.of("Asia/Shanghai")
val date1 = Instant.ofEpochSecond(this).atZone(zoneId).toLocalDate()
val date2 = Instant.ofEpochSecond(timestamp2).atZone(zoneId).toLocalDate()
return date1 == date2
}
@@ -0,0 +1,28 @@
/*
* Copyright © 2024 RTAkland
* Author: RTAkland
* Date: 2024/9/21
*/
package cn.rtast.fancybot.util.misc
import com.madgag.gif.fmsware.AnimatedGifEncoder
import com.madgag.gif.fmsware.GifDecoder
import java.awt.image.BufferedImage
import java.io.ByteArrayOutputStream
fun GifDecoder.makeGif(frames: List<BufferedImage>): ByteArray {
val estimatedSize = frames.size * 50 * 1024
val byteArrayOutputStream = ByteArrayOutputStream(estimatedSize)
val encoder = AnimatedGifEncoder()
encoder.start(byteArrayOutputStream)
encoder.setRepeat(0)
val delays = frames.indices.map { this.getDelay(this.frameCount - it - 1) }
frames.indices.forEach { i ->
encoder.setDelay(delays[i])
encoder.addFrame(frames[i])
}
encoder.finish()
return byteArrayOutputStream.toByteArray()
}
@@ -0,0 +1,131 @@
/*
* Copyright © 2024 RTAkland
* Author: RTAkland
* Date: 2024/9/12
*/
package cn.rtast.fancybot.util.misc
import cn.rtast.fancybot.configManager
import java.awt.Graphics2D
import java.awt.geom.Ellipse2D
import java.awt.geom.RoundRectangle2D
import java.awt.image.BufferedImage
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import javax.imageio.ImageIO
private fun BufferedImage.getScaledWidth(maxWidth: Double, maxHeight: Double): Pair<Int, Int> {
val originalWidth = this.getWidth(null)
val originalHeight = this.getHeight(null)
val widthScale = maxWidth / originalWidth
val heightScale = maxHeight / originalHeight
val scale = minOf(widthScale, heightScale)
val targetWidth = (originalWidth * scale).toInt()
val targetHeight = (originalHeight * scale).toInt()
return targetWidth to targetHeight
}
fun Graphics2D.drawCustomImage(
image: BufferedImage,
x: Int,
y: Int,
maxWidth: Double,
maxHeight: Double,
clip: Boolean = false
) {
val (targetWidth, targetHeight) = image.getScaledWidth(maxWidth, maxHeight)
if (clip) {
this.clip = RoundRectangle2D.Float(
x.toFloat(),
y.toFloat(),
targetWidth.toFloat(),
targetHeight.toFloat(),
30.toFloat(),
30.toFloat()
)
}
this.drawImage(image, x, y, targetWidth, targetHeight, null)
this.clip = null
}
fun Graphics2D.drawCircularImage(
image: BufferedImage,
x: Int,
y: Int,
maxWidth: Double,
maxHeight: Double,
) {
val (targetWidth, targetHeight) = image.getScaledWidth(maxWidth, maxHeight)
val circle = Ellipse2D.Double(x.toDouble(), y.toDouble(), targetWidth.toDouble(), targetHeight.toDouble())
this.clip = circle
this.drawImage(image, x, y, targetWidth, targetHeight, null)
this.clip = null
}
fun BufferedImage.scaleImage(size: Pair<Int, Int>): BufferedImage {
val scaledImage = BufferedImage(size.first, size.second, this.type)
val graphics2d = scaledImage.createGraphics()
graphics2d.drawImage(this, 0, 0, size.first, size.second, null)
graphics2d.dispose()
return scaledImage
}
fun ByteArray.toBufferedImage(): BufferedImage {
ByteArrayInputStream(this).use { inputStream ->
return ImageIO.read(inputStream)
}
}
fun BufferedImage.toByteArray(): ByteArray {
ByteArrayOutputStream().use { outputStream ->
ImageIO.write(this, configManager.imageType.typeName, outputStream)
return outputStream.toByteArray()
}
}
fun Graphics2D.drawCenteredText(text: String, x: Int, y: Int) {
val metrics = this.fontMetrics
val textWidth = metrics.stringWidth(text)
val textHeight = metrics.height
val drawX = x - textWidth / 2
val drawY = y + textHeight / 2
this.drawString(text, drawX, drawY)
}
fun Graphics2D.drawString(text: String, x: Int, y: Int, maxWidth: Int) {
val fm = this.fontMetrics
val lineHeight = fm.height
var curY = y
val words = text.split(" ")
val line = StringBuilder()
for (word in words) {
if (fm.stringWidth("$line$word ") <= maxWidth) {
line.append(word).append(" ")
} else {
this.drawString(line.toString(), x, curY)
curY += lineHeight
line.setLength(0)
line.append(word).append(" ")
}
}
if (line.isNotEmpty()) {
this.drawString(line.toString(), x, curY)
}
}
fun BufferedImage.isFullyTransparent(): Boolean {
val width = this.width
val height = this.height
for (y in 0 until height) {
for (x in 0 until width) {
val pixel = this.getRGB(x, y)
if ((pixel shr 24) != 0x00) {
return false
}
}
}
return true
}
@@ -0,0 +1,32 @@
/*
* Copyright © 2024 RTAkland
* Author: RTAkland
* Date: 2024/10/8
*/
package cn.rtast.fancybot.util.misc
import cn.rtast.fancybot.configManager
import cn.rtast.fancybot.entity.github.UploadContentPayload
import cn.rtast.fancybot.entity.github.UploadContentResponse
import cn.rtast.fancybot.util.Http
import cn.rtast.fancybot.util.str.encodeToBase64
import cn.rtast.fancybot.util.str.proxy
import cn.rtast.fancybot.util.str.toJson
import java.util.UUID
object ImageBed {
private val imageBedUrl =
"https://api.github.com/repos/${configManager.githubUser}/${configManager.githubImageRepo}/contents".proxy
fun upload(file: ByteArray, fileType: String = ""): String {
val body = UploadContentPayload("uploadImage", file.encodeToBase64()).toJson()
val response = Http.put<UploadContentResponse>(
"$imageBedUrl/${UUID.randomUUID()}${if (fileType.isNotBlank()) ".$fileType" else ""}", body,
mapOf("Authorization" to "Bearer ${configManager.githubKey}")
).content.name
return "https://raw.githubusercontent.com/${configManager.githubUser}/${configManager.githubImageRepo}/refs/heads/main/$response".proxy
}
}
@@ -0,0 +1,46 @@
/*
* Copyright © 2024 RTAkland
* Author: RTAkland
* Date: 2024/9/5
*/
package cn.rtast.fancybot.util.misc
import cn.rtast.fancybot.*
import cn.rtast.fancybot.util.Http
import cn.rtast.rob.ROneBotFactory
import cn.rtast.rob.util.ob.OneBotListener
import java.io.File
import kotlin.random.Random
fun randomBooleanWithProbability(probability: Double): Boolean {
val randomValue = Random.nextInt(100)
return randomValue <= (probability * 100)
}
suspend fun OneBotListener.getUserName(groupId: Long, userId: Long): String {
val info = this.getGroupMemberInfo(groupId, userId)
return info.card ?: info.nickname
}
fun initCommandAndItem(rob: ROneBotFactory) {
val commandManager = rob.commandManager
commands.forEach { commandManager.register(it) }
items.forEach { itemManager.register(it) }
tasks.forEach { rob.scheduler.scheduleTask(it.value, 1000L, it.key) }
}
fun initFilesDir() {
File("$ROOT_PATH/caches/images").also { it.mkdirs() }
File("$ROOT_PATH/logs").also { it.mkdirs() }
}
fun initSetuIndex() {
val file = File("$ROOT_PATH/caches/pixiv_index_v3.json")
if (!file.exists()) {
file.createNewFile()
val fileContent = Http.get("$ASSETS_BASE_URL/files/pixiv_index_v3.json")
file.writeText(fileContent)
}
}
@@ -0,0 +1,21 @@
/*
* Copyright © 2024 RTAkland
* Author: RTAkland
* Date: 2024/9/10
*/
package cn.rtast.fancybot.util.misc
import java.io.InputStream
object Resources {
fun loadFromResources(filename: String): InputStream? {
return this::class.java.classLoader.getResourceAsStream(filename)
}
fun loadFromResourcesAsBytes(filename: String): ByteArray? {
val inputStream = this::class.java.classLoader.getResourceAsStream(filename)
return inputStream?.use { it.readBytes() }
}
}
@@ -0,0 +1,19 @@
/*
* Copyright © 2024 RTAkland
* Author: RTAkland
* Date: 2024/10/8
*/
package cn.rtast.fancybot.util.misc
import java.net.URI
import java.net.URL
fun String.toURL(): URL {
return URI(this).toURL()
}
fun String.toURI(): URI {
return URI(this)
}