2017-02-08 3 views
3

В программе я создаю программу стеганографии, которая скрывает секретное сообщение внутри изображения .ppm, изменяя случайные значения красного пикселя на символы ascii. Программа основана на коде, который находится на stackoverflow для чтения и записи ppm изображений (read PPM file and store it in an array; coded with C), все остальные коды - это моя собственная работа. Я выполнил все необходимые функции, такие как запись, чтение, кодирование и декодирование файлов, но я изо всех сил пытаюсь понять функцию fwrite.C: Написание структур RGB-значений в файл для создания ppm-изображения - преждевременный конец файла

В настоящее время, когда программа кодирует изображение, которое требуется в .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("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"); 
} 
} 
+1

'SizeOf (img-> данные)' не то, что вы хотите. Это дает вам размер * указателя *, а не размер выделенной памяти. У вас есть магические числа в вашем коде, такие как '24' и' 3', что делает неочевидным то, что представляют различные размеры. Поэтому я не уверен, какой размер вам нужен в 'fwrite'. Но это определенно не 'sizeof (img-> data)'. – kaylum

+0

Вы должны отредактировать это, чтобы удалить беседу против моряка с помощью малой скорости, мы пытаемся запустить здесь респектабельный сустав. – samgak

+0

Спасибо за совет забыл, что был там :) –

ответ

0

Проблема на самом деле в коде для чтения в PPM, которые вы модифицированы таким образом, что, как представляется, работает, но на самом деле не потому, что файл формат отличается от того, что вы думаете.

Код, который вы указали для чтения PPM-файлов в формате «raw». Эти файлы начинаются с кода «P6». В этих файлах каждое значение RGB сохраняется как 1 или 2 байта (в зависимости от того, глубина компонента RGB меньше 256). Таким образом, если максимальное значение равно 255, это 1 байт на значение, поэтому размер файла равен ширине * высоте * 3.

Однако вы изменили код, чтобы прочитать «простые» PPM-файлы, которые начинаются с " P3 ", проверив P3 и прочитав больше данных. Эти файлы не сохраняют значения RGB в качестве необработанных двоичных данных, а как текст ASCII, определяющий значение в десятичном формате, разделенное пробелами. Так, например, если у вас было значение 93 в необработанном формате, оно было бы всего 1 байт со значением 93, но в «обычном» формате это было бы 3 (или более) байта: один или несколько байтов со значением ASCII для пробела (или вкладки), тогда значение ASCII для «9» (которое равно 57), то значение ASCII для «3» (что равно 51). Невозможно рассчитать размер файла на основе ширины и высоты, поскольку пробел может быть переменным, и каждое значение может быть представлено от 1 до 3 цифр.

Несмотря на то, что вы не разбор данных в виде ASCII-текста в кодировке, код PPM чтения кажется работать, потому что вы просто читаете в порции данных (необязательно) Изменив несколько случайных байт и затем записывать его снова или полностью или в основном без изменений.

Таким образом, ваши возможные решения:

  • Изменить код getPPM обратно к тому, что это было, и использовать фактический файл P6.
  • Напишите считыватель PPM, который корректно анализирует данные как текст ASCII, содержащий десятичные числа, разделенные пробелами (вы можете записать как P3 или P6).

Подробнее: PPM Format Specification

+0

Спасибо за помощь, я хотел бы изменить программу на чтение/запись изображений P3, чтобы потребовалось изменить читателя, как бы я хотел изменить его на правильные требования. Добавление в пробелы для каждого значения rgb? –

+0

Когда вы его читаете, вызовите 'fscanf (fp,"% d% d% d ", & red, & green, &blue);' внутри цикла, пока не получите значения ширины ширины * или не достигли конца файла (test используя 'feof (fp)'). Прочитайте в int и затем установите 8-битные значения в своих структурах. Чтобы записать это, вы можете просто использовать fprintf. Обратите внимание, что вы можете иметь только 70 значений в каждой строке. . – samgak

+1

Этот код обрабатывает чтение ppm-файлов, но может быть немного сложнее: https://sourceforge.net/p/netpbm/code/HEAD/tree/stable/lib/libppm1.c – samgak

Смежные вопросы