I've been working in C++ for the better part of this year and am looking to improve my style and efficiency as much as possible. One thing I've been told is to work on commenting code to make it clearer, so if you have any suggestions about where I could use a comment to clarify what is going on I would be very glad to hear them.
A guide to how PPM is structured can be found here for those unfamiliar with the file type.
Pixel.h
#ifndef __PIXEL_H_INCLUDED__
#define __PIXEL_H_INCLUDED__
#include <fstream>
struct Pixel {
public:
int red;
int green;
int blue;
Pixel(): Pixel(0, 0, 0) {};
Pixel(int _r, int _g, int _b): red(_r), green(_g), blue(_b) {};
};
std::ifstream& operator >> (std::ifstream& fin, Pixel& temp) {
fin >> temp.red;
fin >> temp.green;
fin >> temp.blue;
return fin;
}
std::ofstream& operator << (std::ofstream& fout, Pixel& temp) {
fout << temp.red << " ";
fout << temp.green << " ";
fout << temp.blue;
return fout;
}
#endif
PortablePixelMap.h
#ifndef __PICTURE_H_INCLUDED__
#define __PICTURE_H_INCLUDED__
#include <vector>
#include <fstream>
#include <string>
class PortablePixelMap {
private:
std::vector<std::vector<Pixel> > picture_data;
std::string magicNumber;
int width;
int height;
int intensity;
public:
bool ReadPPMFile(std::ifstream& fin);
bool WritePPMFile(std::ofstream& fout);
void FlipY();
void FlipX();
void InvertPixelIntensity();
};
#endif
main.cpp
#include <iostream>
#include <cmath>
#include "Pixel.h"
#include "PortablePixelMap.h"
int main(int argc, char** argv) {
if (argc < 3) {
std::cout << "Usage: inputfile outputfile [XYI]\n";
return -1;
}
std::ifstream fin;
fin.open(argv[1]);
PortablePixelMap picture;
bool able_to_read_ppm_file = picture.ReadPPMFile(fin);
if(!able_to_read_ppm_file) {
std::cout << "Error: unable to read PPM file " << argv[1] << "\n";
return -1;
}
if (argc == 4) {
if (*argv[3] == 'X') {
picture.FlipX();
} else if (*argv[3] == 'Y') {
picture.FlipY();
} else if (*argv[3] == 'I') {
picture.InvertPixelIntensity();
} else {
std::cout << "Error: " << argv[3] << " is an invalid command. Use either X, Y, or I.\n";
return -1;
}
}
std::ofstream fout;
fout.open(argv[2]);
bool able_to_write_ppm_file = picture.WritePPMFile(fout);
if (!able_to_write_ppm_file) {
std::cout << "Error: unable to write uninitialized PPM file " << argv[2] << "\n";
return -1;
}
fout.close();
}
bool PortablePixelMap::ReadPPMFile(std::ifstream& fin) {
if (fin.fail()) {
return false;
};
fin >> magicNumber;
if (magicNumber != "P3") {
return false;
}
fin >> width >> height;
fin >> intensity;
for (int i = 0; i < height; i++) {
std::vector<Pixel> pixel_vector;
for (int j = 0; j < width; j++) {
Pixel temp;
fin >> temp;
pixel_vector.push_back(temp);
}
picture_data.push_back(pixel_vector);
}
return true;
}
bool PortablePixelMap::WritePPMFile(std::ofstream& fout) {
if (fout.fail()) {
return false;
}
fout << magicNumber << "\n";
fout << width << " " << height << "\n";
if (width == 0 || height == 0) {
return false;
}
fout << intensity << "\n";
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
fout << picture_data[i][j] << "\n";
}
}
return true;
}
void PortablePixelMap::FlipX() {
for (int i = 0; i < height/2; i++) {
std::vector<Pixel> temp = picture_data[i];
picture_data[i] = picture_data[picture_data.size()-i-1];
picture_data[picture_data.size()-i-1] = temp;
}
}
void PortablePixelMap::FlipY() {
for (unsigned int i = 0; i < picture_data.size(); i++) {
std::vector<Pixel> temp = picture_data[i];
for (unsigned int j = 0; j < temp.size(); j++) {
temp[j] = picture_data[i][width-j-1];
}
picture_data[i] = temp;
}
}
void PortablePixelMap::InvertPixelIntensity() {
for (unsigned int i = 0; i < picture_data.size(); i++) {
std::vector<Pixel> temp = picture_data[i];
for (unsigned int j = 0; j < temp.size(); j++) {
temp[j].red = abs(temp[j].red - intensity);
temp[j].green = abs(temp[j].green - intensity);
temp[j].blue = abs(temp[j].blue - intensity);
}
picture_data[i] = temp;
}
}