C语言中的隐写术

7
尝试在PPM图像上进行基本隐写术。
我已经完成了基本算法。读取文件,检查标题是否以P6开头,获取图像宽度和高度以及像素数据。
我需要总共四个方法:ReadPPM、WritePPM、WriteMsg和ReadMsg。
我已经完成了ReadImg和WriteImg方法,但是我的WriteMsg方法出现了问题。这是一种基本的隐写术,只需将字符串的每个位写入到每个字节的最后一位即可。前8个字节应该包含要隐藏的字符串大小,然后每个字节都可以开始隐藏信息。
我的想法是创建一个大数组,其中包含字符串大小的二进制代码,然后是字符串本身的二进制代码。我正在努力弄清楚如何将该数组添加到图像中的每个字节中。
任何帮助都非常感谢。下面是我的当前代码:
#include<stdio.h>
#include<stdlib.h>

typedef struct {
     unsigned char red,green,blue;
} PPMPixel;

typedef struct {
     int x, y;
     PPMPixel *data;
} PPMImage;

#define CREATOR "RPFELGUEIRAS"
#define RGB_COMPONENT_COLOR 255

static PPMImage *readPPM(const char *filename)
{
    char buff[16];
    PPMImage *img;
    FILE *fp;
    int c, rgb_comp_color;
    //open PPM file for reading
    fp = fopen(filename, "rb");
    if (!fp) {
         fprintf(stderr, "Unable to open file '%s'\n", filename);
         exit(1);
    }

    //read image format
    if (!fgets(buff, sizeof(buff), fp)) {
         perror(filename);
         exit(1);
    }

    //check the image format
    if (buff[0] != 'P' || buff[1] != '6') {
         fprintf(stderr, "Invalid image format (must be 'P6')\n");
         exit(1);
    }

    //alloc memory form image
    img = (PPMImage *)malloc(sizeof(PPMImage));
    if (!img) {
         fprintf(stderr, "Unable to allocate memory\n");
         exit(1);
    }

    //check for comments
    c = getc(fp);
    while (c == '#') {
    while (getc(fp) != '\n') ;
         c = getc(fp);
    }

    ungetc(c, fp);
    //read image size information
    if (fscanf(fp, "%d %d", &img->x, &img->y) != 2) {
         fprintf(stderr, "Invalid image size (error loading '%s')\n", filename);
         exit(1);
    }

    //read rgb component
    if (fscanf(fp, "%d", &rgb_comp_color) != 1) {
         fprintf(stderr, "Invalid rgb component (error loading '%s')\n", filename);
         exit(1);
    }

    //check rgb component depth
    if (rgb_comp_color!= RGB_COMPONENT_COLOR) {
         fprintf(stderr, "'%s' does not have 8-bits components\n", filename);
         exit(1);
    }

    while (fgetc(fp) != '\n') ;
    //memory allocation for pixel data
    img->data = (PPMPixel*)malloc(img->x * img->y * sizeof(PPMPixel));

    if (!img) {
         fprintf(stderr, "Unable to allocate memory\n");
         exit(1);
    }

    //read pixel data from file
    if (fread(img->data, 3 * img->x, img->y, fp) != img->y) {
         fprintf(stderr, "Error loading image '%s'\n", filename);
         exit(1);
    }

    fclose(fp);
    return img;
}

void writePPM(const char *filename, PPMImage *img)
{
    FILE *fp;
    //open file for output
    fp = fopen(filename, "wb");
    if (!fp) {
         fprintf(stderr, "Unable to open file '%s'\n", filename);
         exit(1);
    }

    //write the header file
    //image format
    fprintf(fp, "P6\n");

    //comments
    fprintf(fp, "# Created by %s\n",CREATOR);

    //image size
    fprintf(fp, "%d %d\n",img->x,img->y);

    // rgb component depth
    fprintf(fp, "%d\n",RGB_COMPONENT_COLOR);

    // pixel data
    fwrite(img->data, 3 * img->x, img->y, fp);
    fclose(fp);
}

void writeMsg(PPMImage *img, char *s)
{   

    int i;
    int len;
    len = sizeof(s);

    if (img)
    {
         j = 0;
         for (i=0; i < img->x * img->y; i++)
         {
              while(j < 8)
              {
                   if(len & 0x80)   
                   {
                        img->data[i].red= img->data[i].red | 0x01;
                   }
                   else 
                   {
                        img->data[i].red= img->data[i].red & 0xFE;
                   }

                   len=len << 1;
                   j++;

                   if (len & 0x80)  
                   {
                        img->data[i].green= img->data[i].green | 0x01;
                   }
                   else
                   {
                        img->data[i].green= img->data[i].green & 0xFE;
                   }


                   len = len << 1;
                   j++;

                   if (len & 0x80)  
                   {
                        img->data[i].blue= img->data[i].blue | 0x01;
                   }
                   else
                   {
                        img->data[i].blue= img->data[i].blue & 0xFE;
                   }
                   j++;
              }
         }
    }
}

你的代码格式大部分都还好...除了你真正需要帮助的那个函数!请修复它。它现在完全无法阅读。 - MatthewD
你需要两个循环:一个按长度循环,另一个按每个字符的位循环,只在第二个循环中写入数据,就像@Patashu所说的那样,或者按相反的顺序(byte << i & 0x80)。不要滚动长度变量! - Eddy_Em
len = sizeof(s) 会返回指针的大小。如果你想要字符串的长度,请使用 strlen() - MatthewD
1个回答

2
要从一个字节中提取单个位,可以这样做: bit(i) = byte >> i & 0x1 这将字节的位向右移动i次,然后与0000 0001进行“and”操作(使除最低位之外的所有位都为零,并且最低位为0或1)。
对于16位短整型、32位整型、64位长整型等,您也可以类似地操作。甚至可以对字符串的char进行操作。您可以使用sizeof(char)来查看char中有多少个字节。
但是,您当然会从多个char(或long或int等)中提取位。要决定从哪个元素中提取位:
如果您想获取第i位并且元素宽度为x位,则从元素[i/x]中获取第i%x位
现在,您已经获得了这个位,要将其放置在字节(或int或char等)中,请执行以下操作: steganographybyte = originalbyte&(~0x1) + bit 这意味着,您取出数字... 0000 0001,反转其位以得到... 1111 1110,将其与原始字节进行“and”操作,以保留其所有位EXCEPT最低位,然后只需添加您的位即可。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接