#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>

using namespace std;

/**
   Przetwarza piksel na jego negatyw.
   @param blue wartość niebieskiej składowej piksela
   @param green wartość zielonej składowej piksela
   @param red wartość czerwonej składowej piksela
*/
void process(int& blue, int& green, int& red)
{
   blue = 255 - blue;
   green = 255 - green;
   red = 255 - red;
}

/**
   Pobiera liczbę całkowitą z pliku binarnego.
   @param stream strumień
   @param offset przesunięcie, z którego ma być odczytana liczba całkowita
   @return liczba całkowita zaczynająca się od danego przesunięcia
*/
int get_int(fstream& stream, int offset)
{
   stream.seekg(offset);
   int result = 0;
   int base = 1;
   for (int i = 0; i < 4; i++)
   {
      result = result + stream.get() * base;
      base = base * 256;
   }
   return result;
}

int main()
{
   cout << "Proszę wprowadzić nazwę pliku: ";
   string filename;
   cin >> filename;

   fstream stream;
   // Otwórz plik w trybie binarnym.
   stream.open(filename, ios::in | ios::out | ios::binary);
   
   int file_size = get_int(stream, 2); // Pobierz wymiary obrazu.
   int start = get_int(stream, 10);
   int width = get_int(stream, 18);
   int height = get_int(stream, 22);

   // Długość linii skanowania musi być wielokrotnością czterech bajtów.
   int scanline_size = width * 3;
   int padding = 0;
   if (scanline_size % 4 != 0)
   {
      padding = 4 - scanline_size % 4;
   }

   if (file_size != start + (scanline_size + padding) * height)
   {
      cout << "To nie jest plik obrazu w 24-bitowym trybie True Color." << endl;
      return 1;
   }
   
   int pos = start;

   for (int i = 0; i < height; i++) // Dla każdej linii skanowania
   {
      for (int j = 0; j < width; j++) // Dla każdego piksela
      {
         stream.seekg(pos); // Przejdź do następnego piksela.
         int blue = stream.get(); // Wczytaj piksel.
         int green = stream.get();
         int red = stream.get();

         process(blue, green, red); // Przetwórz piksel.

         stream.seekp(pos); // Wróć do początku piksela.

         stream.put(blue); // Zapisz piksel.
         stream.put(green);
         stream.put(red);
         pos = pos + 3;
      }

      stream.seekg(padding, ios::cur); // Pomiń dopełnienie.
      pos = pos + padding;
   }

   return 0;
}

