Image Resize & Watermark — Java 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 Java implementation — the same logic the interactive tool runs, in a shareable, citable form.
// Image Resize & Watermark — Java (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.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
public final class ImageResizeAndWatermark {
// 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.
public static BufferedImage run(BufferedImage src, int targetWidth, String watermark) {
int h = (int) Math.round((double) src.getHeight() / src.getWidth() * targetWidth);
BufferedImage img = new BufferedImage(targetWidth, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g = img.createGraphics();
try {
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC); // imageSmoothingQuality 'high'
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.drawImage(src, 0, 0, targetWidth, h, null);
int fs = (int) Math.round(Math.min(targetWidth, h) * 6 / 100.0);
g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, fs)); // Bold ≈ the TS 600 weight
FontRenderContext frc = g.getFontRenderContext();
GlyphVector glyphs = g.getFont().createGlyphVector(frc, watermark);
Rectangle b = glyphs.getPixelBounds(frc, 0, 0); // measureText analogue
float x = targetWidth - b.width - 8;
float y = h - 8; // baseline anchored 8 px above the bottom, as in the TS code
Shape outline = glyphs.getOutline(x, y);
g.setComposite(AlphaComposite.SrcOver.derive(0.7f)); // the TS globalAlpha = 0.7
g.setStroke(new BasicStroke(Math.max(1f, fs / 14f),
BasicStroke.JOIN_ROUND, BasicStroke.CAP_ROUND));
g.setColor(new Color(0f, 0f, 0f, 0.55f)); // 0.55-alpha stroke
g.draw(outline); // strokeText
g.setColor(new Color(1f, 1f, 1f, 0.7f)); // 0.7-alpha white fill
g.fill(outline); // fillText
} finally {
g.dispose();
}
return img;
}
public static void main(String[] args) throws Exception {
BufferedImage out = run(ImageIO.read(new File("input.jpg")), 1280, "CosmoDev");
ImageIO.write(out, "jpg", new 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 →