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 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
