C:将RGB值的结构写入文件以创建ppm图像 – 文件的过早结束
我正在创建一个隐写术程序,通过将随机红色像素值更改为ascii字符,在.ppm图像中隐藏秘密消息.
该程序基于stackoverflow上用于读取和写入ppm图像的代码( read PPM file and store it in an array; coded with 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("P3n"); } //alloc memory form image img = (PPMImage *)malloc(sizeof(PPMImage)); if (!img) { fprintf(stderr,"Unable to allocate memoryn"); 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: %dn",img->x); printf("Width: %dn",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("%dn",rgb_comp_color ); } //check rgb component depth if (rgb_comp_color!= 255) { fprintf(stderr,"'%s' does not have 8-bits componentsn",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 memoryn"); 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: %dn",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: %dn ",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,"P3n"); //comments //need to store comments to be outputted fprintf(fp,"# Created by Sean n"); //image size fprintf(fp,"%d %dn",img->x,img->y); // rgb component depth fprintf(fp,"%dn",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: %dn",i); printf("R: %d ",img->data[i].red ); printf("G: %d ",img->data[i].green ); printf("B: %dn ",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: %dn",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"); } } 解决方法
问题实际上在PPM中的读取代码中,您已经以一种看似有效的方式进行了修改,但实际上并不是因为文件格式与您的想法不同.
您链接的代码用于以“原始”格式读取PPM文件.这些文件以“P6”代码开头.在这些文件中,每个RGB值都存储为1或2个字节(取决于RGB组件深度是否小于256).因此,如果最大值为255,则每个值为1个字节,因此文件大小为width * height * 3. 但是,您已修改代码以读取“普通”PPM文件,该文件以“P3”代码开头,检查P3并读取更多数据.这些文件不将RGB值存储为原始二进制数据,而是将ASCII文本存储为十进制格式,以空格分隔.因此,例如,如果您使用原始格式的值为93,则它只是1字节,值为93,但在“普通”格式中,它将是3(或更多)字节:具有ASCII值的一个或多个字节对于空格(或制表符),则为“9”的ASCII值(即57),然后是“3”的ASCII值(即51).根据宽度和高度计算文件的大小是不可能的,因为空白可以是可变的,每个值可以表示在1到3位之间. 尽管您没有将数据解析为ASCII编码文本,但您的PPM读取代码似乎有效,因为您只是读取一大块数据,(可选)修改一些随机字节然后再将其写出来完全或大部分未变. 那么,您可能的解决方案是: >将getPPM代码更改回原来的版本并使用实际的P6文件. 更多信息:PPM Format Specification (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |