我们常常会遇到为图像加水印或logo的需求,一般可以通过三方库或者软件实现,但其实加水印非常简单,仅用一个函数即可实现。
实现思路,逐一计算水印和原图重叠部分的像素点的RGBA分量:
float percent = watermarkA / 255.0f
dstR = srcR * (1 - percent) + watermarkR * percent;
dstG = srcG * (1 - percent) + watermarkG * percent;
dstB = srcB * (1 - percent) + watermarkB * percent;
dstA = srcA * (1 - percent) + watermarkA * percent;
JNI实现:
extern "C" JNIEXPORT void JNICALL
Java_com_qxt_watermark_WatermarkUtils_add(JNIEnv *env, jclass clazz, jbyteArray src, jint srcWidth,
jint srcHeight, jbyteArray watermark, jint watermarkWidth, jint watermarkHeight,
jint x, jint y) {
uint8_t *_src = (uint8_t *) env->GetByteArrayElements(src, nullptr);
uint8_t *_watermark = (uint8_t *) env->GetByteArrayElements(watermark, nullptr);
int positionX;
if (x < 0) {
positionX = 0;
} else if (x > srcWidth - watermarkWidth) {
positionX = srcWidth - watermarkWidth;
} else {
positionX = x;
}
int positionY;
if (y < 0) {
positionY = 0;
} else if (y > srcHeight - watermarkHeight) {
positionY = srcHeight - watermarkHeight;
} else {
positionY = y;
}
for (int h = 0; h < watermarkHeight; h++) {
for (int w = 0; w < watermarkWidth; w++) {
/*int srcPosition = ((srcHeight - watermarkHeight + y) * srcWidth
+ srcWidth - watermarkWidth + x) * 4;*/
int srcPosition = ((positionY + h) * srcWidth
+ positionX + w) * 4;
int position = (h * watermarkWidth + w) * 4;
float watermarkAlpha = _watermark[position + 3] / 255.0f;
float dstR = _src[srcPosition] * (1.0f - watermarkAlpha)
+ _watermark[position] * watermarkAlpha;
_src[srcPosition] = (uint8_t) dstR;
float dstG = _src[srcPosition + 1] * (1.0f - watermarkAlpha)
+ _watermark[position + 1] * watermarkAlpha;
_src[srcPosition + 1] = (uint8_t) dstG;
float dstB = _src[srcPosition + 2] * (1.0f - watermarkAlpha)
+ _watermark[position + 2] * watermarkAlpha;
_src[srcPosition + 2] = (uint8_t) dstB;
float dstA = _src[srcPosition + 3] * (1.0f - watermarkAlpha)
+ _watermark[position + 3] * watermarkAlpha;
_src[srcPosition + 3] = (uint8_t) dstA;
}
}
env->ReleaseByteArrayElements(watermark, (jbyte *) _watermark, JNI_ABORT);
env->ReleaseByteArrayElements(src, (jbyte *) _src, 0);
}
java函数及参数说明:
/**
*
* @param image, src image byte array
* @param imageWidth, src image width
* @param imageHeight, src image height
* @param watermark, watermark image byte array
* @param watermarkWidth, watermark image width
* @param watermarkHeight, watermark image height
* @param x, watermark coordinate x, x >= 0 && x <= imageWidth - watermarkWidth
* @param y, watermark coordinate y, y >= 0 && y <= imageHeight - watermarkHeight
*/
public static native void add(byte[] image, int imageWidth, int imageHeight,
byte[] watermark, int watermarkWidth, int watermarkHeight,
int x, int y);
可以通过x, y坐标控制水印或者logo图片的位置,最终实现效果:
以上仅是一个demo,在实际项目中,我们可以结合人脸检测,用类似的方法轻松地实现在相机的预览帧中加个兔子耳朵、络腮胡子之类的效果。
最后,本文demo代码已上传至github:https://github.com/qiuxintai/Watermark