Hey,

I'm trying to do some compression on an ascii saved file, and running into problems.

The original file starts off as such:

7+'Y2+'J0-B)#0

I can read this in, and I get it as:

6 1 55
32 32 41
85 80 120
5 2 33
85 81 104
17 14 31
68 64 79

But when I try to resave this, it gives different ascii:

7  )UPx!UQhD

Not sure if I'm saving this wrong (Pure dumb to text file), or if I'm just being stupid here, Any ideas?

Thanks Lilly

Recommended Answers

All 12 Replies

1. try opening the file in binary and see if you still experience the same type of behavior

2. without seeing your code, i am not sure what you are using.. but you may have problems with these ascii values exceeding the 8bit capacity of the char data type.

the default signed char will allow ascii values up to 127 without experiencing overflow. an unsigned char will allow ascii values up to 255.

most unicode implementations allow use of a WORD type that will support 16bits which I believe is capable of handling all char sets.

one solution if you want to stick to native c++ types, would be to use a wchar_t which is 2 or 4 bytes, depending on your operating system.

This is the original code for loading the PPM image

_ppm::_ppm()
{
loaded = false;
}

_ppm::~_ppm()
{
if(loaded)
	clear();
}


int _ppm::save_ppm(const char* filename)
{
  if(!loaded)
	  return -1;

  FILE * fi;
  int x, y, rgb;

  int x1 = 0;
  int y1 = 0;
  int x2 = width;
  int y2 = height;
	
  if((fi = fopen(filename,"w+b"))==0)
	  return -2;
  
  if (x1 < 0 || x1 > width || y1 < 0 || y1 > height ||
      x2 < 0 || x2 > width || y2 < 0 || y2 > height)
		return -1;
  
  

  fprintf(fi, "P6\n %d %d\n%d\n", x2 - x1, y2 - y1, depth);
  

  
  for (y = y1; y < y2; y++)
    for (x = x1; x < x2; x++)
      for (rgb = 0; rgb < 3; rgb++)
			fputc(data[((y*width+x)*3)+rgb], fi);
  
  return 0;
}


int _ppm::load_ppm(const char* filename, int xx, int yy)
{
  if(loaded)
	  clear();

  FILE * fi;
  char temp[10240];
  int x, y, rgb, m; 

  if((fi=fopen(filename,"rb"))==0)
	  return -1;
  
  
  fscanf(fi, "%s %d %d %d", &temp, &width, &height, &m); 
  depth = m;


  data = new int[(width*height)*3];


    fgetc(fi);


  for (y = 0; y < height; y++)
	{
	for (x = 0; x < width; x++)
		{
		for (rgb = 0; rgb < 3; rgb++)
			{
			data[((y*width+x)*3)+rgb] = fgetc(fi);
			}
		}
	}

  loaded = true;
  return 1;
}

int _ppm::set_pixel(int x, int y, int channel, int value)
{
if(!loaded)
	return -1;

if (x < 0 || x > width || y < 0 || y > height)
	return -1;

if(channel > 2 || channel < 0)
	return -1;

if(value < 0 || value > 255)
	return -1;

data[(((y*width)+x)*3)+channel] = value;

return 0;
}

int _ppm::get_pixel(int x, int y, int channel)
{
if(!loaded)
	return -1;

if (x < 0 || x > width || y < 0 || y > height)
	return -1;

return data[(((y*width)+x)*3)+channel];
}

void _ppm::clear()
{
delete[] data;
height = 0;
width = 0;
depth = 0;
loaded = false;

From this I'm loading each pixel value with RGB using:

ofstream myfile;
  myfile.open ("Images\\test.steph");

  
for(int x=0;x<ppm.get_image_width()-1;x++)
	{
	for(int y=0;y<ppm.get_image_height()-1;y++) 	
	{
		r = ppm.get_pixel(x,y,RED);
		g = ppm.get_pixel(x,y,GREEN);
		b = ppm.get_pixel(x,y,BLUE);
		
		myfile << char(r) << char(g) << char(b) ;   
	
	}
}
myfile.close();
}

And in this example just writing them directly to the text file. There are other functions for the compression, but those are obvious breaking as the ascii values are wrong :P

Thanks Lil

I can't read this C style file i/o.

If it's a text file, and apparently PPM is [edit]or is it?[/edit], don't mess with binary mode. Also, don't write "little integers" that happen to be characters as characters -- that is, don't use fputc; write these little integers as integers using *printf and read with *scanf.

If it's a text file, and apparently PPM is [edit]or is it?[/edit], don't mess with binary mode. Also, don't write "little integers" that happen to be characters as characters -- that is, don't use fputc; write these little integers as integers using *printf and read with *scanf.

PPM is part of the PNM (Portable Anymap Format) file type. i.e. Coloured Image, but it's competely uncompressed, so it pretty much is plain text file in that sense.

In terms of "little integers" what do you include in that phrase, as currently only using a single write method as you can see.

Thanks Lilly

If it's a text file, and apparently PPM is [edit]or is it?[/edit], don't mess with binary mode. Also, don't write "little integers" that happen to be characters as characters -- that is, don't use fputc; write these little integers as integers using *printf and read with *scanf.

PPM is part of the PNM (Portable Anymap Format) file type. i.e. Coloured Image, but it's competely uncompressed, so it pretty much is plain text file in that sense.

In terms of "little integers" what do you include in that phrase, as currently only using a single write method as you can see.

Thanks Lilly

I am sort of thinking this:

I'm looking at this in "C mode". And I'd missed the type of rgb being an int.

But I mentioned earlier -- don't use fputc . It would, for example, write something with an integer value of 55 as '7'. Write the integers as integers is what I'm trying to say, and use a function that will write 55 as 55.

But then I look at your original post and see that indeed the "text" file you are reading from appears to be a binary. So I'd say I've been way off the mark here. My bad.

Could you attach the input file? It would be nice if I had enough of your code to compile and attempt to see the same results you see, but I can putter along with writing my own code too.

Simply reading in and writing out, I get equivalent files:

#include <iostream>
#include <cstdio>

int main()
{
   FILE *out, *in = fopen("in.dat", "rb");
   if ( in )
   {
      int value[100];
      int i = 0, j;
      for ( ;; )
      {
         int c = fgetc(in);
         if ( c == EOF )
         {
            break;
         }
         printf("%02X ", (unsigned)c);
         value[i++] = c;
      }
      putchar('\n');
      fclose(in);
      out = fopen("out.dat", "wb");
      if ( out )
      {
         for ( j = 0; j < i; ++j )
         {
            fputc(value[j], out);
         }
         fclose(out);
      }
   }
   return 0;
}

/* my output
06 01 37 2B 27 59 0C 06 32 2B 27 4A 05 01 1C 30 2D 42 1A 12 29 23 1B 30 
*/

Hmm.

I am sort of thinking this:
But then I look at your original post and see that indeed the "text" file you are reading from appears to be a binary. So I'd say I've been way off the mark here. My bad.

Could you attach the input file? It would be nice if I had enough of your code to compile and attempt to see the same results you see, but I can putter along with writing my own code too.

Included in the zip are the 3 source files, and a test image.
The text file is the output from the program, which is what I'm comparing to the original image (I'd suggest wordpad if you're on windows, notepad has a fit at it :P)

Hope that helps,

Lilly

Peeking at the index, I get a little confused with the x and y and your index calculation. But, does reversing the loop order give you more of an expected result? That is, from

for ( int x=0;x<ppm.get_image_width()-1;x++ )
   {
      for ( int y=0;y<ppm.get_image_height()-1;y++ )

to

for ( int y=0;y<ppm.get_image_height()-1;y++ )
   {
      for ( int x=0;x<ppm.get_image_width()-1;x++ )

?

[edit]Doing so, I see in my hex editor that the initial sequences match:

06 01 37 2B 27 59

Whereas with the opposite loop order, I see an initial sequence of

06 01 37 20 20 29

Peeking at the index, I get a little confused with the x and y and your index calculation. But, does reversing the loop order give you more of an expected result? That is, from

for ( int x=0;x<ppm.get_image_width()-1;x++ )
   {
      for ( int y=0;y<ppm.get_image_height()-1;y++ )

to

for ( int y=0;y<ppm.get_image_height()-1;y++ )
   {
      for ( int x=0;x<ppm.get_image_width()-1;x++ )

?

[edit]Doing so, I see in my hex editor that the initial sequences match:

Whereas with the opposite loop order, I see an initial sequence of

mmm actually yes that does lol >.<

Only thing that occurs now is the saved file seems slightly bigger, 2.27 vs 2.25MB, Opening both files in wordpad shows the new one has slightly more on the end. But that might just be something stupid I did again :P Will check it hehe.

Thanks Lilly

Are you opening the output file in binary mode?

[edit]Another curiosity that I did no investigation of...

ofstream myfile("foo.txt", std::ios::binary);
   for ( int x = 0; x < ppm.get_image_width()-1; x++ )
   {
      for ( int y = 0; y < ppm.get_image_height()-1; y++ )
      {
         r = ppm.get_pixel(x,y,RED);
         g = ppm.get_pixel(x,y,GREEN);
         b = ppm.get_pixel(x,y,BLUE);
         myfile << (unsigned char)r << (unsigned char)g << (unsigned char)b;
      }
   }
   cout<<"DONE!"<<endl<<endl;

Why the -1? The usual idiom for an array of size N is

for ( int i = 0; i < N: ++i) { /* ... */ }
commented: Great help overall, ty +1

Are you opening the output file in binary mode?

[edit]Another curiosity that I did no investigation of...

ofstream myfile("foo.txt", std::ios::binary);
   for ( int x = 0; x < ppm.get_image_width()-1; x++ )
   {
      for ( int y = 0; y < ppm.get_image_height()-1; y++ )
      {
         r = ppm.get_pixel(x,y,RED);
         g = ppm.get_pixel(x,y,GREEN);
         b = ppm.get_pixel(x,y,BLUE);
         myfile << (unsigned char)r << (unsigned char)g << (unsigned char)b;
      }
   }
   cout<<"DONE!"<<endl<<endl;

Why the -1? The usual idiom for an array of size N is

for ( int i = 0; i < N: ++i) { /* ... */ }

Mmm you're right again, The opening as binary fixed it >.< *hugs lots* I'm having a bad day it seems :P

About the loop, I kept getting random errors for 2 pixels, but only 2 pixels, so I removed 1 row to see if it would fix it.

if(r == -1 || g == -1 || b == -1) 
cout<<"Error at pixel "<<(y*ppm.get_image_width()+x)*3<<endl; 

Error at pixel 2359290
Error at pixel 2369233

Which is odd as 1024*768*3 is 2359296, so they should be within the range. But from the photo seems two pixels corrupt, but yes you're right it shouldn't be there.

Thanks lots :P Lilly

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.