Skip to content

Instantly share code, notes, and snippets.

@NebulaBC
Last active September 9, 2023 17:11
Show Gist options
  • Select an option

  • Save NebulaBC/046cf361c6ea175e0cee34b96f7d69f5 to your computer and use it in GitHub Desktop.

Select an option

Save NebulaBC/046cf361c6ea175e0cee34b96f7d69f5 to your computer and use it in GitHub Desktop.
Generate a fake discord screenshot in Kotlin. Created for use with a JDA moderation bot.
import java.awt.*
import java.awt.geom.AffineTransform
import java.awt.image.BufferedImage
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
object DiscordMessageCreator {
fun generateDiscordScreenshot(
message: String,
name: String,
roleColor: Color,
date: Date,
profilePicture: BufferedImage
): BufferedImage {
val canvasSize = calculateCanvasSize(message)
val width = canvasSize.first
val height = canvasSize.second
val image = BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
val g2d = image.createGraphics()
prepG2d(g2d, width, height)
val nameOffset = drawNameText(g2d, name, roleColor)
drawDatetime(g2d, date, nameOffset)
drawMessageText(g2d, message)
drawProfilePicture(g2d, profilePicture)
g2d.dispose()
return image
}
private fun prepG2d(g2d: Graphics2D, width: Int, height: Int) {
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON
)
g2d.color = Color(54, 57, 63, 255)
g2d.fillRect(0, 0, width, height)
}
private fun drawDatetime(g2d: Graphics2D, date: Date, offset: Int) {
g2d.color = Color(151, 153, 160)
val font = Font.createFont(Font.TRUETYPE_FONT, File("whitneybook.otf")).deriveFont(12F)
g2d.font = font
val x = offset + 5
val y = 18
val sdf = SimpleDateFormat()
sdf.timeZone = SimpleTimeZone(0, "GMT")
sdf.applyPattern("dd MMM yyyy HH:mm:ss z")
g2d.drawString(sdf.format(date), x, y)
}
private fun drawNameText(g2d: Graphics2D, name: String, color: Color): Int {
g2d.color = color
val font = Font.createFont(Font.TRUETYPE_FONT, File("whitneybold.otf")).deriveFont(16F)
g2d.font = font
val x = 65
val y = 18
g2d.drawString(name, x, y)
return x + getTextWidth(g2d, name, font)
}
private fun drawMessageText(g2d: Graphics2D, message: String) {
g2d.color = Color.WHITE
val font = Font.createFont(Font.TRUETYPE_FONT, File("whitneybook.otf")).deriveFont(16F)
g2d.font = font
val x = 65
val y = 40
g2d.drawString(message, x, y)
}
private fun drawProfilePicture(g2d: Graphics2D, overlayImage: BufferedImage) {
val overlayWidth = 48
val overlayHeight = 48
val resizedOverlayImage = BufferedImage(overlayWidth, overlayHeight, BufferedImage.TYPE_INT_ARGB)
val g2dOverlay = resizedOverlayImage.createGraphics()
g2dOverlay.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON
)
val at = AffineTransform.getScaleInstance(
overlayWidth.toDouble() / overlayImage.width,
overlayHeight.toDouble() / overlayImage.height
)
g2dOverlay.drawRenderedImage(overlayImage, at)
val circleImage = createCircular(resizedOverlayImage, overlayWidth)
val overlayX = 0
val overlayY = 0
g2d.drawImage(circleImage, overlayX, overlayY, null)
g2dOverlay.dispose()
}
private fun calculateCanvasSize(text: String): Pair<Int, Int> {
val THUMBNAILSIZE = 48
val MINWIDTH = 250
val FONTSIZE = 25
var deltaWidth = THUMBNAILSIZE + 15
var width = MINWIDTH
for (paragraph in text.split("\n")) {
val paragraphs = paragraph.length * 9
if (paragraphs > width) {
width = paragraphs
}
}
val deltaHeight = THUMBNAILSIZE / 2
val height = text.split("\n").size * FONTSIZE
return Pair(deltaWidth + width, deltaHeight + height)
}
private fun getTextWidth(g2d: Graphics2D, text: String, font: Font): Int {
val fontMetrics: FontMetrics = g2d.getFontMetrics(font)
return fontMetrics.stringWidth(text)
}
private fun createCircular(image: BufferedImage, size: Int): BufferedImage {
val output = BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB)
val g2 = output.createGraphics()
try {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
g2.fillOval(0, 0, size, size)
g2.composite = AlphaComposite.SrcIn
g2.drawImage(image, 0, 0, null)
} finally {
g2.dispose()
}
return output
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment