该程序我正在创建一个隐写术程序,通过将随机红色像素值更改为 ascii 字符来隐藏 .ppm 图像中的秘密消息。该程序基于 stackoverflow 上用于读取和写入 ppm 图像的代码(读取 PPM 文件并将其存储在数组中;用 C 编码),所有其他代码都是我自己的工作。我已经完成了所有必要的功能,例如写入、读取、编码和解码文件,但我正在努力掌握 fwrite 功能。
当前,当程序对图像进行编码时,它会在 .ppm 中将其转换为结构中的 rgb 值。然后它通过将红色值编辑为 ascii 字符来隐藏秘密消息。将图像“打印”到文件时会出现问题。程序完成后,生成的图像大约是应打印图像的 90%。示例如下: 未完成图像示例
我已经检查过它是否通过打印所有 rgb 值来存储所有值都被正确存储,并且确实如此。(使用 showPPM 方法)。是否没有足够的内存来写入图像?写入功能的图像是否过大?这些是我的猜测。
关于我应该如何更改 writePPM 函数以便我将 100% 的图像正确打印到文件的任何信息都会很棒。
这是下面的代码:
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<time.h>
typedef struct {
unsigned char red,green,blue;
} PPMPixel;
typedef struct {
int x, y;
PPMPixel *data;
} PPMImage;
void writePPM(PPMImage *img);
static PPMImage *getPPM(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] != '3') {
fprintf(stderr, "Invalid image format (must be 'P3')\n");
exit(1);
}else{
printf("P3\n");
}
//alloc memory form image
img = (PPMImage *)malloc(sizeof(PPMImage));
if (!img) {
fprintf(stderr, "Unable to allocate memory\n");
exit(1);
}
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);
}else{
printf("Height: %d\n",img->x);
printf("Width: %d\n",img->y);
}
//read rgb component
if (fscanf(fp, "%d", &rgb_comp_color) != 1) {
fprintf(stderr, "Invalid rgb component (error loading '%s')\n", filename);
exit(1);
}else{
printf("%d\n",rgb_comp_color );
}
//check rgb component depth
if (rgb_comp_color!= 255) {
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(24*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, 10*img->x, img->y, fp) != img->y) {
fprintf(stderr, "Error loading image '%s'\n", filename);
exit(1);
}
fclose(fp);
return img;
}
struct PPMImage * encode(char * text, PPMImage * img)
{
//convert secret message to ascii code
int i,ascii,height,width;
int total = 0;
int rolling = 0;
int original = 0;
time_t t;
srand((unsigned) time(&t));
height=img->y;
width=img->x;
for(i = 0; text[i]; i++){
ascii = text[i];
//create random number between 0 and max the width
total = total + rand() % width;
original = total;
//printf("Random Number: %d\n",total);
if(total >= width){
rolling = rolling + 1;
total = total - width;
}
//printf("Before R: %d \n",img->data[0].red );
img->x=rolling;
img->y=total;
printf("X: %d ",rolling );
printf("Y: %d ",total );
//set img position
//at position random we set the red bit equal to ascii number
printf("Old R: %d ",img->data[i].red );
img->data[i].red=ascii;
printf("New R: %d\n ",img->data[i].red );
}
//take img then print it out
//setting the img values again for printing
img->x=width;
img->y=height;
writePPM(img);
}
void writePPM(PPMImage *img)
{
FILE *fp;
//open file to be written
fp = fopen("encoded.ppm", "wb");
if (!fp) {
fprintf(stderr, "Unable to open file \n");
exit(1);
}
//image format
fprintf(fp, "P3\n");
//comments
//need to store comments to be outputted
fprintf(fp, "# Created by Sean \n");
//image size
fprintf(fp,"%d %d\n",img->x,img->y);
// rgb component depth
fprintf(fp, "%d\n",255);
//write pixels currently not fully working
fwrite(img->data, sizeof(img->data), 3*img->y*img->x, fp);
//close file stream
fclose(fp);
}
void showPPM(PPMImage *img)
{
int i;
if(img){
for(i=-1;i<img->x*img->y;i++){
printf("Number: %d\n",i);
printf("R: %d ",img->data[i].red );
printf("G: %d ",img->data[i].green );
printf("B: %d\n ",img->data[i].blue );
}
}
}
char * decode(PPMImage * i1,PPMImage * i2){
//compare difference in number of bits in red pixels
//if there is a different then take the red pixel value from the encrypted image
//then translate it from ascii to chars then print.
printf("Decoding......\n");
int i;
for(i=-1;i<i1->x*i1->y;i++){
if(i1->data[i].red != i2->data[i].red){
printf("%c",i1->data[i].red );
}
}
//to be able to test and finish this need to write code for encoding
}
int main(int argc, char *argv[]){
//input statements
if(argc == 3){
PPMImage *image;
image = getPPM(argv[2]);
//uncomment the showPPM to display all rgb values in the encoded files
//showPPM(image);
if(argv[1] = "e"){
printf("Please enter your secret message to be encoded estimated max characters: %d\n",image->y);
//need to add user input
encode("test output!",image);
}
}else if(argc == 4){
PPMImage *i1;
PPMImage *i2;
i1 = getPPM(argv[2]);
i2 = getPPM(argv[3]);
if(argv[1] = "d"){
decode(i1,i2);
}
}else{
printf("Wrong arguments");
}
}
Run Code Online (Sandbox Code Playgroud)
问题实际上出在用于读取 PPM 的代码中,您已经以看似有效的方式对其进行了修改,但实际上却不起作用,因为文件格式与您想象的不同。
您链接到的代码用于读取“原始”格式的 PPM 文件。这些文件以“P6”代码开头。在这些文件中,每个 RGB 值存储为 1 或 2 个字节(取决于 RGB 分量深度是否小于 256)。因此,如果最大值为 255,则每个值 1 个字节,因此文件大小为宽度 * 高度 * 3。
但是,您已修改代码以通过检查 P3 并读取更多数据来读取以“P3”代码开头的“普通”PPM 文件。这些文件不将 RGB 值存储为原始二进制数据,而是存储为 ASCII 文本,以十进制格式指定值,并以空格分隔。例如,如果原始格式的值是 93,那么它只是 1 个字节,值为 93,但在“普通”格式中,它将是 3 个(或更多)字节:一个或多个带有 ASCII 值的字节对于空格(或制表符),则为“9”的 ASCII 值(即 57),然后为“3”的 ASCII 值(即 51)。无法根据宽度和高度计算文件的大小,因为空格可以变化,并且每个值可以表示 1 到 3 位数字。
尽管您没有将数据解析为 ASCII 编码文本,但您的 PPM 读取代码似乎可以工作,因为您只是读取一块数据,(可选)修改一些随机字节,然后再次将其写出完全或大部分不变。
因此,您可能的解决方案是:
详细信息:PPM 格式规范
| 归档时间: |
|
| 查看次数: |
4967 次 |
| 最近记录: |