在图片中添加自己的文本信息(PNG及JPEG格式)

本文介绍如何在PNG和JPEG格式的图片中嵌入文本信息,并提供了具体的代码实现细节。通过对图片格式的理解,实现了在图片头部添加文本段的功能。

背景:

PNG格式和JPEG格式的图片都有一个表示文本信息的段,这些信息可以是任意的字符串,或者版权信息,或者工作室信息,或者其它的。本文的程序是在原始图片中添加这个段的信息。由于比较简单,不多说。

对比图片格式,小弟学习过一段时间,由于工作原因,对JPEG了解深一些,但只限于格式,像JPEG的压缩算法还没学习到。

代码如下:

/**************************************************************************

PNG:
段组成:
名称    占用字节      内容
长度       4        数据长度
段名       4       如:'IHDR'
数据       N       数据内容
CRC        4  CRC32值(段名及数据的CRC)

添加文本信息:
长度: strlen(text)
段名:'tEXt'
数据: text(内容自定)
CRC: crc32('tEXt'+text)

放置位置:位于IHDR后面
PNG头8字节,IHDR段25字节(内容13字节,其它12字节),共33字节,
故放置33偏移量处后面。

JPEG:
组成:
名称   占用字节                  内容
段名      2       如:FF D8表示JPEG图片,FF FE表示注释段
长度      2          数据段长度+2(即这里的2字节)
数据      N                  数据内容

添加文件信息:
段名: FF FE
长度: strlen(text_len) + 2
数据: info(text)

放置位置:位于FF E0或FF E1段后面
读0x04、0x05处长度(即FFE0或FFE1的长度),须转换成小端模式

PNG、JPEG图片为大端模式,以字节保存没问题,但数据长度必须转换成大端模式

写新文件方法:
先保存原来的开始部分,再插入文本信息,再保存剩下部分数据
**************************************************************************/


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

const char *text = ">AUTHOR: Late Lee from http://www.latelee.org.\n";

#define little2big32(x) \
        ( (x&0xff000000) >> 24 | (x&0xff0000) >> 8 | (x&0xff00) << 8 | (x&0xff) << 24 )

#define little2big16(x) \
        ( (x&0xff00) >> 8 | (x&0xff) << 8 )

#define HEAD_SIZE 33
int add_text_png(const char *file, const char *new_file)
{
        FILE *in;
        FILE *out;
        int len = 0;
        size_t ret = 0;
        char *buffer;
        char *text_buf;
        size_t text_len = 0;
        size_t text_len_1 = 0;
        char text_type[4] = {'t''E''X''t'};
        int text_crc = 0;

        in = fopen(file, "rb");
        if (in == NULL)
        {
                printf("Can not open file %s\n", file);
                return -1;
        }

        fseek(in, 0, SEEK_END);
        len = ftell(in);
        fseek(in, 0, SEEK_SET);

        printf("file size: %d\n", len);

        buffer = (char *)malloc(sizeof(char) * len);
        if (buffer == NULL)
        {
                return -1;
        }

        // read all to buffer
        ret = fread(buffer, 1, len, in);
        if (ret != len)
        {
                printf("read file failed.\n");
                return -1;
        }

        out = fopen(new_file, "wb");
        if (out == NULL)
        {
                printf("open new file failed.\n");
                return -1;
        }

        // write 'head'
        ret = fwrite(buffer, 1, HEAD_SIZE, out);
        if (ret != HEAD_SIZE)
        {
                printf("write head failed.\n");
                return -1;
        }

        /////////////////////////
        text_len = strlen(text);
        text_buf = (char *)malloc(sizeof(char) * (text_len + 12));
        text_len_1 = little2big32(text_len);
        memcpy(text_buf, &text_len_1, 4);        // big endian
        memcpy(text_buf + 4, text_type, 4);
        memcpy(text_buf + 4 + 4, text, text_len);
        text_crc = crc32((unsigned char *)(text_buf + 4), (u32)text_len + 4);
        memcpy(text_buf + 4 + 4 + text_len, &text_crc, 4);

        printf("text len: %d\n", text_len);

        // write information
        ret = fwrite(text_buf, 1, text_len + 12, out);
        if (ret != text_len + 12)
        {
                printf("write head failed.\n");
                return -1;
        }

        // write 'left'
        ret = fwrite(buffer + HEAD_SIZE, 1, len - HEAD_SIZE, out);
        if (ret != len - HEAD_SIZE)
        {
                printf("write head failed.\n");
                return -1;
        }

        fclose(in);
        fclose(out);

        free(buffer);
        free(text_buf);

        printf("good job.\n");
        
        return 0;
}

int add_text_jpeg(const char *file, const char *new_file)
{
        FILE *in;
        FILE *out;
        int len = 0;
        size_t ret = 0;
        unsigned char *buffer;        // must be unsigned char
        char *text_buf;
        size_t text_len = 0;
        size_t text_len_1 = 0;
        size_t tmp_len = 0;
        unsigned char text_type[2] = {0xFF0xFE};

        in = fopen(file, "rb");
        if (in == NULL)
        {
                printf("Can not open file %s\n", file);
                return -1;
        }

        fseek(in, 0, SEEK_END);
        len = ftell(in);
        fseek(in, 0, SEEK_SET);

        printf("file size: %d\n", len);

        buffer = (unsigned char *)malloc(sizeof(char) * len);
        if (buffer == NULL)
        {
                return -1;
        }

        // read all to buffer
        ret = fread(buffer, 1, len, in);
        if (ret != len)
        {
                printf("read file failed.\n");
                return -1;
        }

        // read tmp_len
        tmp_len = *(buffer + 4) << 8 | *(buffer + 5);
        printf("tmp len: %x\n", tmp_len);

        out = fopen(new_file, "wb");
        if (out == NULL)
        {
                printf("open new file failed.\n");
                return -1;
        }

        // write 'head'
        ret = fwrite(buffer, 1, tmp_len + 4, out);
        if (ret != tmp_len + 4)
        {
                printf("write head failed.\n");
                return -1;
        }

        /////////////////////////
        text_len = strlen(text);
        text_buf = (char *)malloc(sizeof(char) * (text_len + 4));
        text_len_1 = little2big16(text_len + 2);
        memcpy(text_buf, text_type, 2);        // FF FE
        memcpy(text_buf + 2, &text_len_1, 2);        // len
        memcpy(text_buf + 2 + 2, text, text_len);        // text

        printf("text len: %d\n", text_len);

        // write information
        ret = fwrite(text_buf, 1, text_len + 4, out);
        if (ret != text_len + 4)
        {
                printf("write text failed.\n");
                return -1;
        }

        // write 'left'
        ret = fwrite(buffer + tmp_len + 41, len - (tmp_len + 4), out);
        if (ret != len - (tmp_len + 4))
        {
                printf("write file failed.\n");
                return -1;
        }

        fclose(in);
        fclose(out);

        free(buffer);
        free(text_buf);

        printf("good job.\n");
        
        return 0;
}

int my_strnicmp(const char *s1, const char *s2, size_t len)
{
        unsigned char c1, c2;

        const char *tmp1 = s1 + strlen(s1) - 1;
        const char *tmp2 = s2 + strlen(s2) - 1;
        c1 = 0;        c2 = 0;
        if (len) {
                do {
                        c1 = *tmp1; c2 = *tmp2;
                        tmp1--; tmp2--;
                        if (!c1)
                                break;
                        if (!c2)
                                break;
                        if (c1 == c2)
                                continue;
                        c1 = tolower(c1);
                        c2 = tolower(c2);
                        if (c1 != c2)
                                break;
                } while (--len);
        }
        return (int)c1 - (int)c2;
}

// a.exe foo.jpg bar.jpg
// 其中的图片格式需要一致,由用户控制
int main(int argc, char *argv[])
{
        int ret = 0;

        if (argc != 3)
        {
                printf("usage: %s old.jpg|png new.jpg|png.\n", argv[0]);
                return -1;
        }

        if (!my_strnicmp(argv[1], "jpg"3))
                add_text_jpeg(argv[1], argv[2]);

        else if (!my_strnicmp(argv[1], "png"3))
                add_text_png(argv[1], argv[2]);
        else
        {
                printf("not support.\n");
                return -1;
        }
        return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值