一、 概述

  将RGB图片打在YUV上需要注意的是, 字体之外应该透明, 否则背景也会被覆盖不好看,  所以RGB必须有透明度,  本测试格式为BMP ARGB8888(也即B是最低字节, A是最高字节),

YUV格式为NV21(YUV420SP), 第一步是将ARGB转换成NV21, 然后小NV21打在打NV21上即可, 最后保存图片, 用7yuv.exe软件查看!

二、 示例代码

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <linux/types.h>
#include <linux/videodev2.h>
#include <malloc.h>
#include <math.h>
#include <string.h>
#include <sys/mman.h>
#include <errno.h>
#include <assert.h> #define MAX_ICON_NUM 42 #define SAVE_IMG_PATH "./save_1280x720_nv21.yuv"
#define WATERMARK_BMP_DIR "./watermark" struct wm_icon
{
int id;
int width;
int height;
unsigned char *y;
unsigned char *c;
unsigned char *alph;
}; struct wm_icon icon_arry[MAX_ICON_NUM]; struct disp_content{
int x;
int y;
#define MAX_CONTENT_LEN 32
char content[MAX_CONTENT_LEN];
}; struct backgroud_info
{
int width;
int height;
unsigned char *y;
unsigned char *c;
}; static void argb8888toyuv420sp(unsigned char *src_p, int width, int height, unsigned char *dest_y, unsigned char *dest_c, unsigned char *dest_alph)
{
int i,j; for(i = ; i < (int)height; i++) {
if((i&) == ) {
for(j= ; j< (int)width; j++) {
*dest_y = (*src_p[]+*src_p[]+*src_p[])/; if((j&) == )
*dest_c++ = +(*(src_p[]-*dest_y)/); //cb else
*dest_c++ = +(*(src_p[]-*dest_y)/); //cr *dest_alph++ = src_p[];
src_p +=;
dest_y++;
}
} else {
for(j= ; j< (int)width; j++) {
*dest_y = (*src_p[]+*src_p[]+*src_p[])/;
*dest_alph++ = src_p[];
src_p +=;
dest_y++;
}
}
} return;
} int init_watermark()
{
FILE *fp = NULL;
int i;
int pic_width = , pic_height = ;
char filename[];
unsigned char *argb_buf = NULL; for(i = ; i < MAX_ICON_NUM; i++) {
sprintf(filename, "%s/argb8888_24x32_%d.bmp", WATERMARK_BMP_DIR, i);
printf("open file %s\n", filename);
fp = fopen(filename, "r");
if(NULL == fp) {
printf("Fail to open file %s(%s)!", filename, strerror(errno));
goto OPEN_FILE_ERR;
}
icon_arry[i].id = i; /* BMP格式解析说明: https://www.cnblogs.com/vedic/p/13608566.html */
fseek(fp, , SEEK_SET);
fread(&pic_width, , , fp);
fread(&pic_height, , , fp);
icon_arry[i].width = abs(pic_width);
icon_arry[i].height = abs(pic_height);
printf("real width=%d(%d), height=%d(%d)\n", icon_arry[i].width, pic_width, icon_arry[i].height, pic_height); icon_arry[i].y = (unsigned char*)malloc(icon_arry[i].width * icon_arry[i].height*/);
if(NULL == icon_arry[i].y) {
printf("malloc picture yuv fail !\n");
fclose(fp);
goto ALLOC_Y_ERR;
}
memset(icon_arry[i].y, 0xff, (icon_arry[i].width * icon_arry[i].height*/));
icon_arry[i].alph = icon_arry[i].y + icon_arry[i].width * icon_arry[i].height;
icon_arry[i].c = icon_arry[i].alph + icon_arry[i].width * icon_arry[i].height; argb_buf = (unsigned char *)malloc(icon_arry[i].width * icon_arry[i].height * );
if (NULL == argb_buf) {
printf("malloc bmp buf fail !\n");
fclose(fp);
goto ALLOC_BUF_ERR;
} fseek(fp, , SEEK_SET);
fread(argb_buf, icon_arry[i].width * icon_arry[i].height * , , fp); argb8888toyuv420sp(argb_buf, icon_arry[i].width, icon_arry[i].height,
icon_arry[i].y, icon_arry[i].c, icon_arry[i].alph); fclose(fp);
free(argb_buf);
} return ; ALLOC_BUF_ERR:
ALLOC_Y_ERR:
OPEN_FILE_ERR: for(i = ; i < MAX_ICON_NUM; ++i) {
if(icon_arry[i].y != NULL) {
free(icon_arry[i].y);
icon_arry[i].y = NULL;
}
}
return -;
} static int get_word_num(char val)
{
int i;
int cnt = ; for(i=; i>=; i--) {
if(!(val & (<<i)))
break;
else
cnt++;
} if (cnt == )
return ; return cnt;
} #define DEFAULT_NUM 36
static int get_word_index(char *data, int wordlen)
{
int index = DEFAULT_NUM; if(wordlen == ) {
if (*data >= '' && *data <= '') {
printf("choose numben 0 ~ 9\n");
index = (*data - ); //落在数组下标0开始
} else if (*data >= 'A' && *data <= 'Z') {
printf("choose A~Z\n");
index = (*data - ); //落在数组下标10开始
} else if (*data == ' ') {
printf("choose kong\n");
index = ;
} else if (*data == '-') {
printf("choose -\n");
index = ;
} else if (*data == '.') {
printf("choose .\n");
index = DEFAULT_NUM;
} else if (*data == ':') {
printf("choose eng :\n");
index = ;
} else if (*data == '/') {
printf("choose /\n");
index = ;
} else {
printf("not match %s , use DEFAULT_NUM\n", data);
index = DEFAULT_NUM;
}
} else if (wordlen == ) {
if(!memcmp(data, "京", )) {
printf("choose %s\n", "京");
index = ;
} else if (!memcmp(data, "沪", )) {
printf("choose %s\n", "沪");
index = ;
} else if (!memcmp(data, ":", )) {
printf("choose chn :\n");
index = ;
} else {
printf("choose DEFAULT_NUM\n");
index = DEFAULT_NUM;
}
} printf("\twordlen -> %d, index -> %d\n", wordlen, index);
return index;
} void yuv420sp_blending(unsigned char *bg_y, unsigned char *bg_c, int bg_width, int bg_height, int left, unsigned int top, int fg_width, int fg_height,
unsigned char *fg_y, unsigned char *fg_c, unsigned char *alph)
{
unsigned char *bg_y_p = NULL;
unsigned char *bg_c_p = NULL;
int i = ;
int j = ; bg_y_p = bg_y + top * bg_width + left;
bg_c_p = bg_c + (top >>)*bg_width + left; for(i = ; i<(int)fg_height; i++) {
if((i&) == ) {
for(j=; j< (int)fg_width; j++) {
*bg_y_p = (( - *alph)*(*bg_y_p) + (*fg_y++)*(*alph))>>;
*bg_c_p = (( - *alph)*(*bg_c_p) + (*fg_c++)*(*alph))>>; alph++;
bg_y_p++;
bg_c_p++;
}
bg_c_p = bg_c_p + bg_width - fg_width;
} else {
for(j=; j< (int)fg_width; j++) {
*bg_y_p = (( - *alph)*(*bg_y_p) + (*fg_y++)*(*alph))>>;
alph++;
bg_y_p++;
}
}
bg_y_p = bg_y_p + bg_width - fg_width;
}
} int save_image(void *addr, int length)
{
FILE *fp = fopen(SAVE_IMG_PATH, "w"); if(fp == NULL) {
printf("Fail to fopen %s\n", SAVE_IMG_PATH);
exit(-);
}
fwrite(addr, length, , fp);
fflush(fp);
usleep();
fclose(fp);
return ;
} int push_wm2bg(unsigned char *bg_yuv_buf, int bg_width, int bg_height, struct disp_content *single_wm)
{
int pos_x;
struct backgroud_info bg_info;
int buflen, wordlen;
char *p_content;
int pic_index;
int i; bg_info.width = bg_width;
bg_info.height = bg_height;
bg_info.y = bg_yuv_buf;
bg_info.c = bg_yuv_buf + bg_width * bg_height; p_content = single_wm->content;
buflen = strlen(single_wm->content);
pos_x = single_wm->x;
printf("\nshow: %s(%d Bytes):\n", p_content, buflen);
for (i = ; i < strlen(single_wm->content); i++) {
wordlen = get_word_num(p_content[]);
buflen -= wordlen;
if(buflen < ) break;
pic_index = get_word_index(p_content, wordlen); yuv420sp_blending(bg_info.y, bg_info.c, bg_info.width, bg_info.height, pos_x, single_wm->y,
icon_arry[pic_index].width, icon_arry[pic_index].height,
icon_arry[pic_index].y, icon_arry[pic_index].c,
icon_arry[pic_index].alph); pos_x += icon_arry[pic_index].width;
p_content += wordlen;
} return ;
} /* Note:
* input file 1280*720 NV21 format
* watermark ARGB8888
*/
int main(int argc, char **argv)
{
unsigned int bg_width = ;
unsigned int bg_height = ;
unsigned int bg_nv21_size = bg_width * bg_height * /;
FILE *fp;
char *bg_file = argv[];
unsigned char *bg_yuv_buf;
/* 汉字编码用UTF-8, 建议用UTF-8编码 */
struct disp_content single_wm = {, , "0 123456789ABC京沪:-/"}; if(bg_file == NULL) {
printf("Pls input backgroud file !\n");
printf("\t eg: %s 1280x720_nv21.yuv\n", argv[]);
exit(-);
} fp = fopen(bg_file, "rb");
if(fp == NULL) {
printf("open backgroud file(%s) fail !\n", bg_file);
exit(-);
} bg_yuv_buf = (unsigned char *)malloc(bg_nv21_size);
if(bg_yuv_buf == NULL){
printf("malloc bg_yuv_buf fail!\n");
exit(-);
}
fread(bg_yuv_buf, , bg_nv21_size, fp); init_watermark();
push_wm2bg(bg_yuv_buf, bg_width, bg_height, &single_wm);
save_image(bg_yuv_buf, bg_nv21_size); return ;
}

fzk@mdvr:push_wm2yuv$ ./a.out 1280x720_nv21.yuv
open file ./watermark/argb8888_24x32_0.bmp
real width=(), height=()
open file ./watermark/argb8888_24x32_1.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_2.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_3.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_4.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_5.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_6.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_7.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_8.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_9.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_10.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_11.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_12.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_13.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_14.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_15.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_16.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_17.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_18.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_19.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_20.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_21.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_22.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_23.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_24.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_25.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_26.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_27.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_28.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_29.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_30.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_31.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_32.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_33.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_34.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_35.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_36.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_37.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_38.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_39.bmp
real width=(), height=(-)
open file ./watermark/argb8888_24x32_40.bmp
real width=(), height=()
open file ./watermark/argb8888_24x32_41.bmp
real width=(), height=() show: 123456789ABC京沪:-/( Bytes):
choose numben ~
wordlen -> , index ->
choose kong
wordlen -> , index ->
choose numben ~
wordlen -> , index ->
choose numben ~
wordlen -> , index ->
choose numben ~
wordlen -> , index ->
choose numben ~
wordlen -> , index ->
choose numben ~
wordlen -> , index ->
choose numben ~
wordlen -> , index ->
choose numben ~
wordlen -> , index ->
choose numben ~
wordlen -> , index ->
choose numben ~
wordlen -> , index ->
choose A~Z
wordlen -> , index ->
choose A~Z
wordlen -> , index ->
choose A~Z
wordlen -> , index ->
choose 京
wordlen -> , index ->
choose 沪
wordlen -> , index ->
choose chn :
wordlen -> , index ->
choose -
wordlen -> , index ->
choose /
wordlen -> , index ->

执行log

三、注意事项

  1. BMP具体解析请查看上一篇博客: https://www.cnblogs.com/vedic/p/13608566.html

  2. 请用UTF-8格式查看, 否则中文会乱码

  3. 代码自动解析BMP头部图片的宽高, 所以不只是支持32x24

  4. 黑白图片没问题, 彩色会有问题

  5. 测试用的背景图片: https://files-cdn.cnblogs.com/files/vedic/1280x720_nv21.bmp  注意将后缀改成.yuv

  6. 测试用的水印图标: https://files.cnblogs.com/files/vedic/watermark.rar

  7. 最后展示:

RGB打水印在YUV图片上的更多相关文章

  1. Photoshop去图片水印——适用复杂图片上有水印

    该方法适合复杂图片上有水印的,不过这个只适合水印只是文字而没有背景的那种.不是所有的水印图片都适合处理.下面是处理前后的对照   工具/原料   photoshop8.0 方法/步骤   1 打开需要 ...

  2. php文字水印和php图片水印实现代码

    本文章向码农们介绍php文字水印和php图片水印实现代码,需要的码农可以参考一下. php 文字水印 文字水印就是在图片上加上文字,主要使用gd库的imagefttext方法,并且需要字体文件. 实现 ...

  3. php文字水印和php图片水印实现代码(二种加水印方法)

    文字水印 文字水印就是在图片上加上文字,主要使用gd库的imagefttext方法,并且需要字体文件.效果图如下: $dst_path = 'dst.jpg';//创建图片的实例$dst = imag ...

  4. java多图片上传--前端实现预览--图片压缩 、图片缩放,区域裁剪,水印,旋转,保持比例。

    java多图片上传--前端实现预览 前端代码: https://pan.baidu.com/s/1cqKbmjBSXOhFX4HR1XGkyQ 解压后: java后台: <!--文件上传--&g ...

  5. [原创]超强C#图片上传,加水印,自动生成缩略图源代码

    <%@ Page Language=“C#“ AutoEventWireup=“true“ %> <%@ Import Namespace=“System“ %> <%@ ...

  6. yii php 图片上传与生成缩略图

    今天需要做图片上传与生成缩略图的功能,把代码进行记录如下: html 视图              ($pic_action_url = $this->createAbsoluteUrl('h ...

  7. 基于WebImage的图片上传工具类

    支持缩略图和水印. using System; using System.IO; using System.Linq; using System.Web; using System.Web.Helpe ...

  8. 包含修改字体,图片上传等功能的文本输入框-Bootstrap

    通过jQuery Bootstrap小插件,框任何一个div转换变成一个富文本编辑框,主要特色: 在Mac和window平台下自动针对常用操作绑定热键 可以拖拽插入图片,支持图片上传(也可以获取移动设 ...

  9. 火车头dede采集接口,图片加水印,远程图片本地化,远程无后缀的无图片本地化

    <?php /* [LocoySpider] (C)2005-2010 Lewell Inc. 火车采集器 DedeCMS 5.7 UTF8 文章发布接口 Update content: 图片加 ...

随机推荐

  1. 我给这个Python库打101分!

    日志在开发过程中是一种被很多程序员 不重视 ,但是却 至关重要 的一项功能. 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很多已经做案 ...

  2. 入门python有什么好的书籍推荐?纯干货推荐,你值得一看 python基础,爬虫,数据分析

    Python入门书籍不用看太多,看一本就够.重要的是你要学习Python的哪个方向,或者说你对什么方向感兴趣,因为Python这门语言的应用领域比较广泛,比如说可以用来做数据分析.机器学习,也可以用来 ...

  3. UIAutomator环境Android8.0 环境异常解决

    个人PC环境 ANDROID_HOME:F:\1Study\Andriod\51zxw_2018-0102\Sdk ANT_HOME:D:\ant\apache-ant-1.10.5\ CLASSPA ...

  4. 微信小程序 progress 进度条 内部圆角及内部条渐变色

    微信小程序progress进度条内部圆角及渐变色 <view class="progress-box"> <progress percent="80&q ...

  5. springboot中使用定时器

    springboot使用注解注册定时器 @Configuration @EnableScheduling public class WeatherDataTask implements Schedul ...

  6. C#LeetCode刷题之#383-赎金信(Ransom Note)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3937 访问. 给定一个赎金信 (ransom) 字符串和一个杂志 ...

  7. CPU:别再拿我当搬砖工了!

    数据搬运工 Hi,我是CPU一号车间的阿Q,有段日子没见面了. 还记得上回说到咱们厂里用上了DMA技术(太慢不能忍!CPU又拿硬盘和网卡开刀了!)之后,我们总算解放了,再也不用奔波于网卡.硬盘与内存之 ...

  8. 火题小战 C. 情侣?给我烧了!

    火题小战 C. 情侣?给我烧了! 题目描述 有 \(n\) 对情侣来到电影院观看电影.在电影院,恰好留有 \(n\) 排座位,每排包含 \(2\) 个座位,共 \(2×n\) 个座位. 现在,每个人将 ...

  9. HBA卡常用命令

    HBA卡信息查看 查看对应的PCI设备lspci | grep LSI 如下:对应的HBA卡命令为sas3ircu 如下:对应的HBA卡使用sas2ircu 查看LSI控制器类型和型号 sas2irc ...

  10. 你真的会做 2 Sum 吗?| 含双重好礼

    小预告:文末有两份福利,记得看到最后哦- 2 Sum 这题是 Leetcode 的第一题,相信大部分小伙伴都听过的吧. 作为一道标着 Easy 难度的题,它真的这么简单吗? 我在之前的刷题视频里说过, ...