加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

C:将RGB值的结构写入文件以创建ppm图像 – 文件的过早结束

发布时间:2020-12-16 06:53:09 所属栏目:百科 来源:网络整理
导读:我正在创建一个隐写术程序,通过将随机红色像素值更改为ascii字符,在.ppm图像中隐藏秘密消息. 该程序基于stackoverflow上用于读取和写入ppm图像的代码( read PPM file and store it in an array; coded with C),所有其他代码都是我自己的工作.我已经完成了所
我正在创建一个隐写术程序,通过将随机红色像素值更改为ascii字符,在.ppm图像中隐藏秘密消息.
该程序基于stackoverflow上用于读取和写入ppm图像的代码( read PPM file and store it in an array; coded with C),所有其他代码都是我自己的工作.我已经完成了所有必要的功能,如写入,读取,编码和解码文件,但我正在努力掌握fwrite功能.

目前,当程序对图像进行编码时,它会将.ppm转换为结构中的rgb值.然后它通过将红色值编辑为ascii字符来隐藏秘密消息.当将图像“打印”到文件时会出现问题.程序完成后,产生的图像大约是打印的90%.示例如下:
Example of the unfinished image

我检查过它是通过打印所有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阅读器,将数据正确解析为包含空格分隔十进制数的ASCII文本(可以写成P3或P6).

更多信息:PPM Format Specification

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读