去水印程序(C语言版本)

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

#pragma pack(push, 1) // 确保结构体紧凑排列
typedef struct {
    char signature[2];
    int file_size;
    short reserved1;
    short reserved2;
    int data_offset;
} BmpHeader;

typedef struct {
    int header_size;
    int width;
    int height;
    short planes;
    short bits_per_pixel;
    int compression;
    int image_size;
    int x_pixels_per_m;
    int y_pixels_per_m;
    int colors_used;
    int colors_important;
} BmpInfoHeader;
#pragma pack(pop)

// 简单的5x7点阵字体(只包含0-9和A-Z)
const unsigned char font[][5] = {
    {0x3E,0x51,0x49,0x45,0x3E}, // A
    {0x7F,0x49,0x49,0x49,0x36}, // B
    {0x3E,0x41,0x41,0x41,0x22}, // C
    // 可继续添加其他字符...
};

void add_watermark(unsigned char* pixels, int width, int height, const char* text) {
    int text_len = strlen(text);
    int char_width = 6;
    int char_height = 8;
    
    // 从右下角开始计算起始位置
    int start_x = width - (text_len * char_width) - 10;
    int start_y = height - char_height - 10;
    
    for (int i = 0; i < text_len; ++i) {
        int char_index = toupper(text[i]) - 'A';
        if (char_index < 0 || char_index > 25) continue;

        // 绘制每个字符
        for (int y = 0; y < 7; ++y) {
            for (int x = 0; x < 5; ++x) {
                if (font[char_index][x] & (1 << (6 - y))) {
                    int px = start_x + x + i * char_width;
                    int py = start_y + y;
                    
                    if (px < width && py < height) {
                        int offset = (py * width + px) * 3;
                        // 设置为白色 (255,255,255)
                        pixels[offset] = 255;     // B
                        pixels[offset + 1] = 255; // G
                        pixels[offset + 2] = 255; // R
                    }
                }
            }
        }
    }
}

int main(int argc, char* argv[]) {
    if (argc != 4) {
        printf("Usage: %s <input.bmp> <output.bmp> \"<watermark text>\"\n", argv[0]);
        return 1;
    }

    FILE* fp_in = fopen(argv[1], "rb");
    FILE* fp_out = fopen(argv[2], "wb");
    const char* watermark = argv[3];

    if (!fp_in || !fp_out) {
        perror("Error opening file");
        return 1;
    }

    // 读取文件头
    BmpHeader header;
    fread(&header, sizeof(BmpHeader), 1, fp_in);
    
    // 验证BMP文件
    if (memcmp(header.signature, "BM", 2) != 0) {
        printf("Not a valid BMP file\n");
        return 1;
    }

    // 读取信息头
    BmpInfoHeader info_header;
    fread(&info_header, sizeof(BmpInfoHeader), 1, fp_in);
    
    // 仅支持24位BMP
    if (info_header.bits_per_pixel != 24) {
        printf("Only 24-bit BMP supported\n");
        return 1;
    }

    // 分配像素内存
    int width = info_header.width;
    int height = info_header.height;
    int pixel_data_size = width * height * 3;
    unsigned char* pixels = malloc(pixel_data_size);
    
    // 读取像素数据
    fseek(fp_in, header.data_offset, SEEK_SET);
    fread(pixels, 1, pixel_data_size, fp_in);
    
    // 添加水印
    add_watermark(pixels, width, height, watermark);
    
    // 写入输出文件
    fwrite(&header, sizeof(BmpHeader), 1, fp_out);
    fwrite(&info_header, sizeof(BmpInfoHeader), 1, fp_out);
    fseek(fp_out, header.data_offset, SEEK_SET);
    fwrite(pixels, 1, pixel_data_size, fp_out);
    
    // 清理资源
    free(pixels);
    fclose(fp_in);
    fclose(fp_out);
    
    printf("Watermark added successfully!\n");
    return 0;
}

使用方法:

  1. 将代码保存为 watermark.c

  2. 编译:gcc watermark.c -o watermark

  3. 运行:./watermark input.bmp output.bmp "WATERMARK"

注意事项:

  1. 仅支持24位未压缩的BMP格式

  2. 水印会添加在图片右下角

  3. 当前版本只支持大写英文字母

  4. 需要自行补充完整的点阵字体数据(示例中只实现了A-C)

扩展建议:

  1. 添加错误处理(文件验证、内存分配检查)

  2. 支持更多字符和符号

  3. 实现透明效果(Alpha混合)

  4. 支持命令行参数自定义水印位置、颜色

  5. 添加抗锯齿功能

如果需要处理其他格式(如PNG/JPEG),建议使用第三方库(如libpng、libjpeg)来处理图像解码/编码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

myxixilovek

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值