4

I am trying to convert a 24 bit bitmap image into grayscale.

#include<iostream>
#include<fstream>
#include<conio.h>
#include<stdio.h>
using namespace std;
class pixel{
            public:
                   unsigned char b;
                   unsigned char g;
                   unsigned char r;
            void display()
            {
                 cout<<r<<" "<<g<<" "<<b<<" ";
                 }
      }p1;
using namespace std;
int main(){
    unsigned char avg;
    fstream file("image.bmp",ios::binary|ios::in|ios::out);

    int start;
    file.seekg(10);
    file.read((char*)&start,4);


    file.seekg(start);
    int i=0;
   while(!file.eof()){
                      cout<<file.tellg();//Remove this and the program doesn't work!
                     file.read((char*)&p1,3);
                     avg=(p1.b+p1.g+p1.r)/3;
                     p1.b=avg;
                     p1.g=avg;
                     p1.r=avg;
                     file.seekg(-3,ios::cur);
                     file.write((char*)&p1,3);
                       }
    file.close();
    getch();
    return 0;
}

When I remove the cout tellg statement the loop runs only two times!

I don't understand what difference removing a cout statement make?

Result: Only one pixel changes to grayscale.

I found a simpler version of my problem here

Reading and writing to files simultaneously?

But didnt find a solution...

Community
  • 1
  • 1
Diptanshu
  • 103
  • 2
  • 6
  • Please bear in mind that humans are not good at seeing the blue end of the spectrum. So one would need to modify for that. – Ed Heal Sep 22 '12 at 17:27
  • See http://stackoverflow.com/questions/687261/converting-rgb-to-grayscale-intensity for the color issue. However does not help you with your current problem. – ypnos Sep 22 '12 at 17:28
  • I'm always wary of reading from a file in the same stream I just wrote with. I'd try reading all the pixels, processing them all, then writing them all. I also have no idea why it would run only twice. – Mooing Duck Sep 22 '12 at 17:33
  • It would take a lot of memory...close to 3-4 mb.bmp files are already too big... It takes only a few bytes if u process each pixel one by one... – Diptanshu Sep 22 '12 at 17:36

1 Answers1

6

When reading and writing a std::fstream you need a seek when switching between reading and writing. The reason for this is that file streams share a common input and output position. To also support efficient buffering it is necessary to inform the respective other buffer about the current position. This is part of what the seek does. tellg() does a seek to the current position.

Note, that it is very inefficient to switch between reading and writing, especially when the implementation is well optimized. You'd be much better off either writing a different file or updating values in reasonable sized groups.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • Especially absurd is seekg(-3) in a loop for all pixels! – Alex Cohn Sep 22 '12 at 19:07
  • Is this standard-mandated? [I'm seeing differing behaviour across platforms.](http://stackoverflow.com/q/42116186/560648) – Lightness Races in Orbit Feb 08 '17 at 14:58
  • @LightnessRacesinOrbit: the seek when changing from reading to writing or vice versa is required for both C and C++ file I/O: the actual requirement is in the C standard. The C++ stream behavior is defined in terms of the C requirements. When implementing buffered I/O and trying to make it efficient the need for seeking becomes rather apparent: supporting switching between reading and writing without seeking has (at least, had at the time I implemented `filebuf`) a significant cost (for those uses which did not switch between input and output). – Dietmar Kühl Feb 08 '17 at 15:41
  • @DietmarKühl: Thanks for clarifying – Lightness Races in Orbit Feb 08 '17 at 15:47