在 C 语言中给 BMP 格式的图片添加水印的代码实现
时间: 2024-03-02 22:51:09 浏览: 114
以下是在 C 语言中给 BMP 格式的图片添加水印的代码实现,仅供参考:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma pack(1) // 设置 BMP 文件头和信息头的对齐方式为 1 字节
// BMP 文件头结构体
typedef struct {
char bfType[2];
int bfSize;
short bfReserved1;
short bfReserved2;
int bfOffBits;
} BMPFileHeader;
// BMP 信息头结构体
typedef struct {
int biSize;
int biWidth;
int biHeight;
short biPlanes;
short biBitCount;
int biCompression;
int biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
int biClrUsed;
int biClrImportant;
} BMPInfoHeader;
// 像素结构体
typedef struct {
unsigned char b;
unsigned char g;
unsigned char r;
} Pixel;
// 水印结构体
typedef struct {
char text[20]; // 文本水印
Pixel color; // 颜色水印
} Watermark;
// 给 BMP 图片添加文本水印
void addTextWatermark(BMPFileHeader fileHeader, BMPInfoHeader infoHeader, Pixel** pixels, Watermark watermark) {
int x, y;
int textLength = strlen(watermark.text);
int fontSize = textLength * 8; // 字体大小
int startX = (infoHeader.biWidth - fontSize) / 2; // 水印起始横坐标
int startY = infoHeader.biHeight - 20; // 水印起始纵坐标
Pixel white = { 255, 255, 255 };
Pixel black = { 0, 0, 0 };
Pixel color = watermark.color.r == 0 && watermark.color.g == 0 && watermark.color.b == 0 ? white : watermark.color; // 如果颜色为黑色,则使用白色
for (y = startY; y < startY + 16; y++) { // 16 行,每行 8 个像素
for (x = startX; x < startX + fontSize; x++) {
if (x < 0 || x >= infoHeader.biWidth || y < 0 || y >= infoHeader.biHeight) { // 判断是否越界
continue;
}
if ((x - startX) % 8 == 0) { // 每个字符间隔 1 像素
if (watermark.text[(x - startX) / 8] == '1') { // 1 为黑色,0 为白色
pixels[y][x] = color;
} else {
pixels[y][x] = black;
}
} else {
pixels[y][x] = black;
}
}
}
}
// 给 BMP 图片添加颜色水印
void addColorWatermark(BMPFileHeader fileHeader, BMPInfoHeader infoHeader, Pixel** pixels, Watermark watermark) {
int x, y;
int startX = infoHeader.biWidth - 20; // 水印起始横坐标
int startY = infoHeader.biHeight - 20; // 水印起始纵坐标
for (y = startY; y < startY + 16; y++) {
for (x = startX; x < startX + 16; x++) { // 16 * 16 的正方形
if (x < 0 || x >= infoHeader.biWidth || y < 0 || y >= infoHeader.biHeight) {
continue;
}
pixels[y][x] = watermark.color;
}
}
}
int main() {
FILE* fp = NULL;
BMPFileHeader fileHeader;
BMPInfoHeader infoHeader;
Pixel** pixels = NULL;
char* fileName = "test.bmp"; // BMP 图片文件名
Watermark watermark = { "0101010101010101", { 0, 0, 0 } }; // 水印:文本水印 "0101010101010101",颜色水印黑色
int x, y;
// 打开 BMP 文件
fp = fopen(fileName, "rb+");
if (fp == NULL) {
printf("Error: Failed to open file %s\n", fileName);
return -1;
}
// 读取 BMP 文件头
fread(&fileHeader, sizeof(BMPFileHeader), 1, fp);
if (fileHeader.bfType[0] != 'B' || fileHeader.bfType[1] != 'M') {
printf("Error: Invalid BMP file format\n");
fclose(fp);
return -1;
}
// 读取 BMP 信息头
fread(&infoHeader, sizeof(BMPInfoHeader), 1, fp);
if (infoHeader.biBitCount != 24) {
printf("Error: Unsupported BMP pixel format\n");
fclose(fp);
return -1;
}
// 申请像素矩阵内存
pixels = (Pixel**)malloc(infoHeader.biHeight * sizeof(Pixel*));
for (y = 0; y < infoHeader.biHeight; y++) {
pixels[y] = (Pixel*)malloc(infoHeader.biWidth * sizeof(Pixel));
}
// 读取 BMP 数据部分,生成像素矩阵
fseek(fp, fileHeader.bfOffBits, SEEK_SET);
for (y = 0; y < infoHeader.biHeight; y++) {
for (x = 0; x < infoHeader.biWidth; x++) {
fread(&pixels[y][x], sizeof(Pixel), 1, fp);
}
}
// 添加水印
addTextWatermark(fileHeader, infoHeader, pixels, watermark);
addColorWatermark(fileHeader, infoHeader, pixels, watermark);
// 将像素矩阵转换回 BMP 数据部分
fseek(fp, fileHeader.bfOffBits, SEEK_SET);
for (y = 0; y < infoHeader.biHeight; y++) {
for (x = 0; x < infoHeader.biWidth; x++) {
fwrite(&pixels[y][x], sizeof(Pixel), 1, fp);
}
}
// 释放内存
for (y = 0; y < infoHeader.biHeight; y++) {
free(pixels[y]);
}
free(pixels);
// 关闭文件
fclose(fp);
return 0;
}
```
需要注意的是,上述代码仅演示了如何给 BMP 图片添加文本水印和颜色水印,并未考虑水印的透明度和鲁棒性等问题。实际上,水印算法的设计需要考虑到多方面因素,应根据具体需求进行合理设计。
阅读全文