Image Resize & Watermark — Kotlin source
Batch-resize images by width, height or percentage and stamp a text watermark with position, opacity and size control — entirely in your browser, nothing uploaded.
This is the Kotlin implementation — the same logic the interactive tool runs, in a shareable, citable form.
// Image Resize & Watermark — Kotlin (JVM 17, java.awt) port of the image-resize-and-watermark tool.
import java.awt.AlphaComposite
import java.awt.BasicStroke
import java.awt.Color
import java.awt.Font
import java.awt.RenderingHints
import java.awt.image.BufferedImage
import java.io.File
import javax.imageio.ImageIO
// Mirrors the TS resizeAndWatermark: aspect-preserving resize, then a
// bottom-right watermark — white fill at 70% alpha over a dark outline
// (strokeText + fillText), both from one GlyphVector outline.
fun resizeAndWatermark(src: BufferedImage, targetWidth: Int, watermark: String): BufferedImage {
val h = Math.round(src.height.toDouble() / src.width * targetWidth).toInt()
val img = BufferedImage(targetWidth, h, BufferedImage.TYPE_INT_RGB)
img.createGraphics().apply {
setRenderingHint(
RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC, // imageSmoothingQuality 'high'
)
setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON)
drawImage(src, 0, 0, targetWidth, h, null)
val fs = Math.round(minOf(targetWidth, h) * 6 / 100.0).toInt()
font = Font(Font.SANS_SERIF, Font.BOLD, fs) // Bold ≈ the TS 600 weight
val width = fontMetrics.stringWidth(watermark) // measureText analogue
val outline = font.createGlyphVector(fontRenderContext, watermark)
.getOutline((targetWidth - width - 8).toFloat(), (h - 8).toFloat()) // baseline at h-8
composite = AlphaComposite.SrcOver.derive(0.7f) // the TS globalAlpha = 0.7
stroke = BasicStroke(maxOf(1f, fs / 14f), BasicStroke.JOIN_ROUND, BasicStroke.CAP_ROUND)
color = Color(0f, 0f, 0f, 0.55f) // 0.55-alpha stroke
draw(outline) // strokeText
color = Color(1f, 1f, 1f, 0.7f) // 0.7-alpha white fill
fill(outline) // fillText
dispose()
}
return img
}
fun main() {
val out = resizeAndWatermark(ImageIO.read(File("input.jpg")), 1280, "CosmoDev")
ImageIO.write(out, "jpg", File("output.jpg")) // WebP needs a plugin (e.g. TwelveMonkeys)
}
Also available in 8 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →