在RGB圖片源數據上新增中文水印

2020-08-11 20:28:50

一、執行環境介紹

Linux系統: Redhat6.3 (32位元)

gcc 版本 4.4.6 20120305 (Red Hat 4.4.6-4) (GCC)

二、功能介紹

建立一張BMP圖片,將圖片當做畫板,在在圖片的指定位置繪製中文。

三、核心程式碼

可以傳入任意尺寸的圖片進行生成繪製。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#pragma pack(1) //強制1個位元組對齊
//BMP的檔案頭
struct _BMP_HEAD
{
    char type[2]; //圖片的型別 "BM"
    unsigned int size; //檔案大小
    unsigned short  r1; //保留1
    unsigned short  r2; //保留2
    unsigned int seek; //數據偏移位元組(真實畫素點數據)
};

//BMP的參數資訊
struct _BMP_INFO
{
    unsigned int size; //當前結構體大小
    unsigned int w; //寬度
    unsigned int h; //高度
    unsigned short flag; //固定爲1
    unsigned short bit; //畫素點的位數
    unsigned int r1; //壓縮方式  0
    unsigned int r2; //水平解析度
    unsigned int r3; //垂直解析度
    unsigned int r4; //垂直解析度
    unsigned int r5; //參照色彩
    unsigned int r6; //關鍵色彩
};

/*
函數功能: 顯示畫素點
*/
void Display_Point(char *head,int w,int x,int y,int c)
{
    unsigned char *p=(unsigned char *)(head+w*3*y+x*3);
    *(p+0)=(c>>0)&0xFF;
    *(p+1)=(c>>8)&0xFF;
    *(p+2)=(c>>16)&0xFF;
}


/*
函數功能: 顯示一個數據
函數參數:
char *font 取模數據的首地址  (橫向取模--高位在前)
int w  取模字型的寬度
int h  取模字型的高度
*/
void Display_Data(char *font,int w,int h,char *image_head,int image_w,int x,int y)
{
    int i,j;
    int x0=x;
    unsigned char data;
    for(i=0;i<w/8*h;i++)
    {
        data=font[i];
        for(j=0;j<8;j++)
        {
            if(data&0x80)  //畫前景色
            {
                Display_Point(image_head,image_w,x0,y,0xFF0033);
            }
            else //畫背景色
            {
                //Display_Point(image_head,image_w,x0,y,0x0066FF);
            }
            x0++;
            data<<=1;
        }
        if(x0-x==w) //換行
        {
            x0=x;
            y++;
        }
    }
}

unsigned char font[]=
{
    /*--  文字:  錢  --*/
/*--  宋體36;  此字型下對應的點陣爲:寬x高=48x48   --*/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x00,0x3C,
0x00,0x00,0x00,0x78,0x00,0x3F,0x00,0x00,0x00,0x7E,0x00,0x3E,0x78,0x00,0x00,0xFC,
0x00,0x3C,0x3E,0x00,0x00,0xF8,0x00,0x3C,0x1F,0x80,0x00,0xF0,0x00,0x3C,0x0F,0x80,
0x00,0xF0,0x00,0x3C,0x07,0xC0,0x01,0xF0,0x70,0x3E,0x03,0x80,0x01,0xFF,0xF8,0x1E,
0x01,0x80,0x01,0xFF,0xFC,0x1E,0x03,0x00,0x03,0xC0,0x00,0x1E,0x07,0x80,0x03,0xC0,
0x00,0x1F,0xFF,0xC0,0x07,0x80,0x03,0xFF,0xFF,0x80,0x07,0x80,0x1F,0xFE,0x00,0x00,
0x07,0x01,0xCE,0x1E,0x00,0x00,0x0F,0xFF,0xE0,0x1E,0x00,0x00,0x0F,0xFF,0xF0,0x1E,
0x00,0x00,0x1C,0x3C,0x00,0x1F,0x00,0x70,0x38,0x3C,0x00,0x0F,0x00,0xF8,0x38,0x3C,
0x00,0x0F,0x3F,0xFC,0x70,0x3C,0x00,0x1F,0xFF,0xE0,0x20,0x3C,0x1F,0xFF,0xC0,0x00,
0x00,0x3C,0x1F,0xEF,0x01,0x80,0x00,0x3C,0x6C,0x0F,0x81,0xC0,0x1F,0xFF,0xF0,0x07,
0x83,0xE0,0x3F,0xFF,0xF8,0x07,0x87,0xF0,0x1E,0x3C,0x00,0x07,0x87,0xE0,0x00,0x3C,
0x00,0x07,0xCF,0x80,0x00,0x3C,0x00,0x03,0xDF,0x00,0x00,0x3C,0x00,0x03,0xFE,0x00,
0x00,0x3C,0x00,0x03,0xFC,0x00,0x00,0x3C,0x00,0x01,0xF8,0x0C,0x00,0x3C,0x18,0x01,
0xF0,0x0C,0x00,0x3C,0x78,0x03,0xF0,0x1C,0x00,0x3D,0xF0,0x0F,0xF8,0x1C,0x00,0x3F,
0xC0,0x1F,0x7C,0x1C,0x00,0x3F,0x80,0x3E,0x3E,0x3C,0x00,0x7F,0x00,0xFC,0x1F,0x3C,
0x00,0x7E,0x01,0xF0,0x0F,0xBC,0x00,0x7C,0x07,0xC0,0x07,0xFC,0x00,0x38,0x1F,0x00,
0x03,0xFC,0x00,0x10,0x7C,0x00,0x01,0xFC,0x00,0x00,0xE0,0x00,0x00,0xFC,0x00,0x00,
0x00,0x00,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

};

int main(int argc,char **argv)
{
    if(argc!=4)
    {
        printf("傳入的參數格式: ./a.out <新圖片寬度> <新圖片高度> <新圖片的名稱>\n");
        printf("例如: ./a.out 80 80 test.bmp");
        printf("傳入的寬度和高度需要>=48\n");
        return 0;
    }
    
    /*1. 建立一張BMP圖片*/
    FILE *fp=fopen(argv[3],"wb");
    if(fp==NULL)
    {
        printf("%s 檔案建立失敗.\n",argv[1]);
        return 0;
    }
    /*2. 建立BMP的檔案頭*/
    int cnt;
    struct _BMP_HEAD bmp_head;
    memset(&bmp_head,0,sizeof(struct _BMP_HEAD));
    //圖片的型別
    bmp_head.type[0]='B';
    bmp_head.type[1]='M';
    //檔案大小
    bmp_head.size=54+800*480*3;
    //數據偏移量
    bmp_head.seek=54;
    //寫檔案頭
    cnt=fwrite(&bmp_head,1,sizeof(struct _BMP_HEAD),fp);
    printf("成功寫入:%d 位元組.\n",cnt);

    /*3. 寫檔案參數資訊*/
    struct _BMP_INFO bmp_info;
    memset(&bmp_info,0,sizeof(struct _BMP_INFO));
    //當前結構體大小
    bmp_info.size=sizeof(struct _BMP_INFO);
    //圖片的寬度和高度
    bmp_info.w=atoi(argv[1]);
    bmp_info.h=atoi(argv[2]);
    //圖片的顏色位數
    bmp_info.bit=24;
    //標誌位
    bmp_info.flag=1;
    //寫入檔案參數資訊
    cnt=fwrite(&bmp_info,1,sizeof(struct _BMP_INFO),fp);
    printf("成功寫入:%d 位元組.\n",cnt);

    /*4.新增水印: 製作圖片的數據*/
    int one_line_byte=bmp_info.w*3; //BMP圖片一行的位元組數
    while(one_line_byte%4!=0) //補齊4的倍數
    {
        one_line_byte++;
    }
    one_line_byte=one_line_byte-bmp_info.w*3; //得到需要補齊的位元組數量

    //申請一個存放圖片顏色數據的緩衝區
    char *head_p=malloc(bmp_info.w*3*bmp_info.h);
    //將緩衝區初始化
    memset(head_p,0xFF,sizeof(bmp_info.w*3*bmp_info.h));

    //繪製水印
    Display_Data(font,48,48,head_p,bmp_info.w,10,10);

    /*5. 寫入點陣圖數據*/
    int w,h;
    char *tmp_p;
    for(h=bmp_info.h-1;h>=0;h--)
    {
        tmp_p=head_p+h*bmp_info.w*3;     //從緩衝區的最後一行開始讀取
        fwrite(tmp_p,1,bmp_info.w*3,fp); //寫一行數據
        if(one_line_byte) //判斷是否需要補齊
        fwrite(tmp_p,1,one_line_byte,fp); //寫補齊的數據(佔位而已--沒有顯示作用)
    }
    /*6. 關閉檔案*/
    fclose(fp);
    free(head_p);
    return 0;
}

四、執行效果

[wbyq@wbyq linux_c]$ gcc app.c 
[wbyq@wbyq linux_c]$ ./a.out 81 81 1.bmp 
成功寫入:14 位元組.
成功寫入:40 位元組.
[wbyq@wbyq linux_c]$ eog 1.bmp

 

 

下面 下麪公衆號有全套C語言、C++、微控制器、Python、QT、物聯網的教學歡迎關注。