当前位置: 首页 > 我的程序代码 > 正文

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

背景:

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

对比图片格式,小弟学习过一段时间,由于工作原因,对JPEG了解深一些,但只限于格式,像JPEG的压缩算法还没学习到。
代码放到github上了,地址:https://github.com/latelee/picture_info
下面给出关键代码,如下:

/**************************************************************************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 %sn”, file);

return -1;

}

fseek(in, 0, SEEK_END);

len = ftell(in);

fseek(in, 0, SEEK_SET);

printf(“file size: %dn”, 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: %dn”, 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 %sn”, file);

return -1;

}

fseek(in, 0, SEEK_END);

len = ftell(in);

fseek(in, 0, SEEK_SET);

printf(“file size: %dn”, 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: %xn”, 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: %dn”, text_len);

// write information

ret = fwrite(text_buf, 1, text_len + 4, out);

if (ret != text_len + 4)

{

printf(“write head 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 head 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], 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;

}

本文固定链接: http://www.latelee.org/my-library/making-my-info-in-png-jpeg.html

在图片中添加自己的文本信息(PNG及JPEG格式):目前有4 条留言

  1. 2楼
    yy:

    在读出添加的信息的时候,怎么解析信息长度?能给个例子吗?

    2015-08-24 下午3:26 [回复]
    • 这个倒没研究过,我觉得可以根据标识符来判断。

      2015-08-24 下午4:34 [回复]
  2. 1楼
    cc:

    ‘u32’ undeclared (first use in this function)
    报错啊!还有其他一些。有源程序下载吗?谢谢了

    2015-08-19 下午5:11 [回复]
    • u32即无符号32位类型,可以用unsigned int或uint32_t代替。crc代码网络上有很多。源代码我放到我的github上了。见原文。

      2015-08-20 上午8:32 [回复]

发表评论

*

快捷键:Ctrl+Enter