Image Resize & Watermark — C++ 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 C++ implementation — the same logic the interactive tool runs, in a shareable, citable form.
// Image Resize & Watermark — C++ (17, OpenCV) port of the image-resize-and-watermark tool.
#include <opencv2/opencv.hpp>
#include <string>
#include <vector>
// Mirrors the TS resizeAndWatermark: aspect-preserving resize, then a
// bottom-right watermark — white text at 70% alpha over a dark outline (the
// strokeText/fillText pair), drawn on a transparent layer and alpha-composited
// so both passes keep their opacity.
cv::Mat resizeAndWatermark(const cv::Mat& src, int targetWidth, const std::string& text) {
int h = cvRound(static_cast<double>(src.rows) / src.cols * targetWidth);
cv::Mat img;
// INTER_AREA is OpenCV's high-quality downscaler — imageSmoothingQuality 'high'.
cv::resize(src, img, cv::Size(targetWidth, h), 0, 0, cv::INTER_AREA);
int fs = cvRound(cv::min(targetWidth, h) * 6.0 / 100.0);
double fscale = fs / 22.0; // HERSHEY glyphs are ~22 px tall at scale 1
int baseline = 0;
cv::Size box = cv::getTextSize(text, cv::FONT_HERSHEY_DUPLEX, fscale, 2, &baseline);
cv::Point org(targetWidth - box.width - 8, h - 8);
cv::Mat layer = cv::Mat::zeros(img.size(), CV_8UC4);
cv::Scalar dark(0, 0, 0, 255 * 0.55), white(255, 255, 255, 255 * 0.7);
// strokeText: outline via 8 offset draws, then the fillText on top.
for (int dx = -2; dx <= 2; dx += 2)
for (int dy = -2; dy <= 2; dy += 2)
cv::putText(layer, text, org + cv::Point(dx, dy),
cv::FONT_HERSHEY_DUPLEX, fscale, dark, 2, cv::LINE_AA);
cv::putText(layer, text, org, cv::FONT_HERSHEY_DUPLEX, fscale, white, 2, cv::LINE_AA);
// Composite the BGRA layer over the image using its alpha channel.
std::vector<cv::Mat> lch, ich;
cv::split(layer, lch);
cv::split(img, ich);
cv::Mat a, inv;
lch[3].convertTo(a, CV_32F, 1.0 / 255);
cv::subtract(cv::Scalar(1.0), a, inv);
for (int i = 0; i < 3; i++) {
cv::Mat f, lf;
ich[i].convertTo(f, CV_32F);
lch[i].convertTo(lf, CV_32F);
f = f.mul(inv) + lf.mul(a);
f.convertTo(ich[i], CV_8U);
}
cv::merge(ich, img);
return img;
}
int main() {
cv::Mat out = resizeAndWatermark(cv::imread("input.jpg"), 1280, "CosmoDev");
std::vector<int> webp{cv::IMWRITE_WEBP_QUALITY, 92}; // TS encodes WebP at 0.92
cv::imwrite("output.webp", out, webp);
}
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 →