Преобразование изображения ---›binary---›image с использованием C

Мы пытаемся преобразовать изображение в двоичные данные и наоборот для проекта с использованием программирования C. Все остальные решения, которые мы нашли в сети, написаны либо на C++, либо на Java. Вот подход, который мы пробовали:

  1. Преобразуйте изображение в текстовый файл, содержащий двоичные данные. Каждые 8 ​​символов соответствуют байту символа, когда изображение открывается с помощью текстового редактора.

  2. Затем мы пытаемся преобразовать двоичные данные в соответствующие символы с помощью программы на языке C.

  3. Затем открываем результат с помощью Picasa Photoviewer. Получаем недопустимое изображение.

Как вернуть исходное изображение? Вот код, который мы использовали для преобразования изображения в текстовый файл:

#include<stdio.h>
#include<conio.h>

void main()
{
  clrscr();
  FILE *fptr;
  FILE *txt;
  int c;

  fptr=fopen("D:\\aa.bmp","r");
  txt=fopen("D:\\test1.txt","w");

  if(fptr==NULL)
  {
    printf("NOTHING In FILE");
    fclose(fptr);
  }
  else
  {
    printf("success");

    do
    {
      c=fgetc(fptr);
      for(int i=0;i<=7;i++)
      {
        if(c&(1<<(7-i)))
        {
          fputc('1',txt);
        }
        else
        {
          fputc('0',txt);
        }
      }
      // fprintf(txt,"\t");
    }while(c!=EOF);

  }

  fclose(fptr);
  fclose(txt);

  printf("writing over");
  getch();
}

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

#include<stdio.h>
#include<conio.h>


\\The following function converts the ones and zeroes in the text file into a character. 
\\For example the text file may have the 8 consecutive characters '1','0','0','0','1','0','0','0'. 
\\This converts it into the character equivalent of the binary \\value 10001000

char bytefromtext(char* text) 
{
  char result=0;
  for(int i=0;i<8;i++)
  {
    if(text[i]=='1')
    {
      result |= (1<< (7-i) );
    }
  }
  return result;
}

void main()
{
  clrscr();
  FILE *pfile;
  FILE *image;
  char buf[8];
  char c;
  int j=0;

  image=fopen("D:\\aa2.bmp","w"); //open an empty .bmp file to
                                  //write characters from the source image file
  pfile=fopen("D:\\test1.txt","r");

  if(pfile==NULL)
    printf("error");
  else
  {
    c=fgetc(pfile);

    while(c!=EOF)
    {
      buf[j++]=c;
      if(j==8)
      {
        fputc(bytefromtext(buf),image);
        j=0;
      }
      c=fgetc(pfile);

    }

    fclose(pfile);
    fclose(image);
  }

  getch();
}

Мы получаем недопустимое изображение, когда символы записываются в файл .bmp. Когда мы открываем этот новый файл с помощью текстового редактора, а также файл изображения с помощью текстового редактора, мы получаем те же символы.


person Arvind Prakash    schedule 11.09.2015    source источник
comment
Обрабатывать как двоичные данные.   -  person Jeyaram    schedule 11.09.2015
comment
Ваш код неверен в отношении обработки данных изображения. Файл Bitmap имеет информационный заголовок в начале файла, который содержит информацию об изображении. Изображение — это не просто набор из 8 байтов, представляющих интенсивность пикселей изображения. en.wikipedia.org/wiki/. Таким образом, вы неправильно изменяете заголовок файла, поэтому файл недействителен. Вам нужно пропустить заголовок, изменить яркость изображения, а затем повторно сохранить изображение с тем же заголовком.   -  person rayryeng    schedule 11.09.2015
comment
Кстати, пожалуйста, прекратите использовать conio.h. Считается плохой практикой: stackoverflow.com/questions/21329485/   -  person rayryeng    schedule 11.09.2015
comment
@rayryeng Ничего не делает с пикселями. Он преобразует каждое 8-битное значение в 8 единиц или нулей, а затем преобразует его обратно. Ничто не изменяется, и не имеет значения, какие данные.   -  person Sami Kuhmonen    schedule 13.09.2015
comment
Использование fgetc неправильно. Вы используете char для хранения возвращаемого значения, когда оно возвращает int. Char не может содержать все 256 значений плюс маркер EOF. Вы должны исправить это. Также проверьте файлы на наличие различий с помощью шестнадцатеричного редактора, текстовый редактор вам не сильно поможет.   -  person Sami Kuhmonen    schedule 13.09.2015
comment
@SamiKuhmonen ах, я слишком быстро прочитал источник. Я думал, что ОП пытается отобразить двоичные пиксели... Не видел, чтобы была попытка реконструкции с использованием того же ошибочного мышления... Так что да, теоретически это должно работать, но использование fgetc здесь неверно. Спасибо!   -  person rayryeng    schedule 13.09.2015


Ответы (3)


Изображение в текстовый файл

fptr=fopen("D:\\aa.bmp","r");

Файл BMP должен открываться в двоичном режиме ("rb"), чтобы обеспечить правильное чтение значений байтов. Режим "r" открывает файл в текстовом режиме, что может привести к преобразованию некоторых символов, что приведет к повреждению вывода.

Например, в Windows (или, по крайней мере, в DOS) окончания строк будут преобразованы из "\r\n" в "\n", а символ "\x1a" может интерпретироваться как индикатор и EOF и обрезать ввод.

С другой стороны, в UNIX-подобных системах нет никакой разницы.


do
{
  c=fgetc(fptr);
  for(int i=0;i<=7;i++)
  {
    /* ... */
  }
  // fprintf(txt,"\t");
}while(c!=EOF);

Эта петля совершенно неверна. Вам нужно проверить наличие EOF в верхней части цикла. Когда fgetc() возвращает EOF, ваш код примет значение EOF (обычно -1) и выведет соответствующие единицы и нули перед выходом из цикла. Это также испортит ваш вывод.

Вместо этого вы должны сделать что-то вроде этого:

while ((c = fgetc (fptr)) != EOF) {
{
  /* ... */
}

Если вам неудобно присваивать и сравнивать в одном и том же выражении, для этого есть исправление:

while (1)
{
  c = fgetc (fptr);
  if (c == EOF)
    break;
  /* ... */
}

Также обратите внимание, что fgetc() также возвращает EOF при ошибке. Вы должны проверить это (if (ferror (fptr))) и сообщить о проблеме пользователю.


fclose(fptr);
fclose(txt);

Вы должны проверить возвращаемое значение fclose() и сообщить пользователю обо всех ошибках, по крайней мере, в выходном потоке. В некоторых файловых системах последний вывод не будет записываться на диск до тех пор, пока поток не будет закрыт, и о любой ошибке записи будет сообщено fclose(). См. Каковы причины проверки ошибок при закрытии()?, чтобы узнать, что может произойти, когда вы не т.

Текстовый файл в изображение

image=fopen("D:\\aa2.bmp","w"); //open an empty .bmp file to

Вы должны использовать двоичный режим ("wb"), как описано выше.


char bytefromtext(char* text) 
{
  char result=0;
  for(int i=0;i<8;i++)
  {
    if(text[i]=='1')
    {
      result |= (1<< (7-i) );
    }
  }
  return result;
}

Вы должны использовать unsigned char при работе с двоичными данными. Обычный char — это либо signed, либо unsigned по выбору разработчика (например, поставщика компилятора).

Если значение, хранящееся в result, не может быть представлено в signed char (например, 1<<7), результатом будет определенная реализация. Теоретически это может повредить ваш вывод. Хотя я думаю, что ваш код, вероятно, будет работать так, как вы предполагали, в большинстве случаев вы все равно должны использовать unsigned char из принципа.

(Это предполагает, конечно, что char не больше 8 бит, что обычно и бывает.)


char c;

/* ... */

c=fgetc(pfile);

while(c!=EOF)
{
  /* ... */

  c=fgetc(pfile);
}

Эта петля неверна по другой причине. Если простое char окажется беззнаковым, c никогда не будет сравниваться с равным EOF, которое всегда имеет отрицательное значение. Вы должны использовать переменную int, протестировать против EOF и только затем использовать значение как символьное значение.


fclose(pfile);
fclose(image);

Вы должны проверить возвращаемые значения, как указано выше.

Другие вопросы

У меня также есть пара других придирок с вашим кодом.

  • В C main() всегда возвращает int, и вы должны вернуть соответствующее значение, указывающее на успех или неудачу. (Это не относится к автономной среде, например к программе C, работающей без операционной системы.)

  • В разделе комментариев во второй программе используется обратная косая черта, а не прямая косая черта. При публикации кода вы всегда должны копировать/вставлять его, чтобы избежать появления новых ошибок.

person Nisse Engström    schedule 18.09.2015

Проверьте свой режим записи для image=fopen("D:\\aa2.bmp","w");, он не в двоичном формате, откройте его в «wb».

person aval    schedule 11.09.2015
comment
Все еще получаю ту же проблему! - person Arvind Prakash; 11.09.2015
comment
Изменил w на wb, но все еще недействительное изображение - person Arvind Prakash; 11.09.2015

Это код, который работает хорошо. Пробовал на raspberryPi3 и gcc.

bmp в текст

#include <stdio.h>

int main(int argc, char*argv[]){

FILE *ptr_bmp_in;
FILE *ptr_text_out;
int c;

ptr_bmp_in=fopen("panda_input.bmp","rb");
ptr_text_out=fopen("panda_to_text.txt","w");

if(!ptr_bmp_in)
{
    printf("Unable to open file\n");
    return 1;
}

while((c=fgetc(ptr_bmp_in)) != EOF)
    {
        for(int i=0;i<=7;i++)
        {
            if(c&(1<<(7-i)))
            {
                fputc('1',ptr_text_out);
            }
            else
            {
                fputc('0',ptr_text_out);
            }
        }
    }


    fclose(ptr_bmp_in);
    fclose(ptr_text_out);
    printf("Writing done\n");

    return 0;
}

и текст в bmp

#include <stdio.h>


char bytefromtext(unsigned char* text)
{   
    char result = 0;
    for(int i=0;i<8;i++)
    {
        if(text[i]=='1')
        {
            result |= (1 << (7-i));
        }
    }
    return result;
}

int main(int argc, char*argv[]){

FILE *ptr_txt_in;
FILE *ptr_bmp_out;
unsigned char buf[8];
int c;
int j = 0;


ptr_txt_in=fopen("panda_to_text.txt","r");
ptr_bmp_out=fopen("panda_output.bmp","wb");


if(!ptr_txt_in)
{
    printf("Unable to open file\n");
    return 1;
}

while((c=fgetc(ptr_txt_in)) != EOF)
    {
        buf[j++] = c;
        if(j==8)
        {
            fputc(bytefromtext(buf),ptr_bmp_out);
            j=0;
        }
    }


    fclose(ptr_txt_in);
    fclose(ptr_bmp_out);
    printf("Writing done\n");

    return 0;
}
person SmartST    schedule 03.10.2018