Arvind Prakash
Arvind Prakash

Reputation: 49

Conversion of Image--->binary--->image using C

We are trying to convert an image into binary data and vice-versa for a project using C programming. All the other solutions we found on the net are either in C++ or Java. Here is the approach we tried:

  1. Convert the image into a text file containing binary data. Each 8 characters corresponds to the character byte when the image is opened using a text editor.

  2. Then we try to reconvert the binary data into its respective characters using a C program.

  3. Then we open the result using Picasa Photoviewer. We get an invalid image.

How do we get back the original image? Here is the code we used to convert the image into a text file:

#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();
}

Here is the code to convert the resulting text file to image file full of binary characters, i.e. a text file with only ones and zeroes.

#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();
}

We get an invalid image when the characters are written into the .bmp file. When we open this new file using a text editor and also the image file using a text editor we get the same characters.

Upvotes: 0

Views: 25288

Answers (3)

SmartST
SmartST

Reputation: 33

This is code that works good. Tryed on raspberryPi3 and gcc.

bmp to text

#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;
}

and text to 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;
}

Upvotes: 1

Nisse Engstr&#246;m
Nisse Engstr&#246;m

Reputation: 4752

Image to text file

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

The BMP file must be opened in binary mode ("rb") to ensure that the bytes values are read correctly. The "r" mode opens the file in text mode which may cause some characters to be converted, resulting in corrupted output.

For example, on Windows (or at least DOS), line endings will be converted from "\r\n" to "\n" and the character "\x1a" might be interpreted as and EOF indicator and truncate your input.

On UNIX-like systems, on the other hand, there is no difference.


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

This loop is completely wrong. You need to check for EOF at the top of the loop. When fgetc() returns EOF, your code will take the EOF value (typically -1), and output the corresponding ones and zeroes, before exiting the loop. This will also corrupt your output.

Instead, you should do something like this:

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

If you're uncomfortable with assignment and comparison in the same expression, there is a fix for that:

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

Note also that fgetc() also returns EOF on error. You should test for this (if (ferror (fptr))) and report the problem to the user.


fclose(fptr);
fclose(txt);

You should check the return value of fclose() and report any error back to the user, at least on the output stream. On some file systems, the last output will not be written to disc until the stream is closed, and any error writing it will be reported by fclose(). See "What are the reasons to check for error on close()?" for a illuminating tale of what can happen when you don't.

Text file to image

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

You must use binary mode ("wb") as explained above.


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

You should use unsigned char when dealing with binary data. Plain char is either signed or unsigned at the choice of the implementor (eg. compiler vendor).

If the value stored in result cannot be represented in a signed char (such as 1<<7), the result is implementation defined. This could theoretically corrupt your output. Although I think your code will probably work as you intended in most cases, you should still use unsigned char as a matter of principle.

(This assumes, of course, that char is not larger than 8 bits which is usually the case.)


char c;

/* ... */

c=fgetc(pfile);

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

  c=fgetc(pfile);
}

This loop is wrong for another reason. If plain char happens to be unsigned, c will never compare equal to EOF which always has a negative value. You should use an int variable, test against EOF, and only then use the value as a character value.


fclose(pfile);
fclose(image);

You should check the return values as mentioned above.

Other issues

I also have a couple of other quibbles with your code.

  • In C, main() always returns int, and you should return an appropriate value to indicate success or failure. (This does not apply to a freestanding environment, eg. a C program running without an operating system.)

  • The comment section in the second program has backslashes instead of forward slashes. When posting code, you should always copy/paste it to avoid introducing new errors.

Upvotes: 2

aval
aval

Reputation: 57

Check your write mode for image=fopen("D:\\aa2.bmp","w"); its not in binary, open it in "wb".

Upvotes: 1

Related Questions