Scratchapixel 2.0
Sign in
This project contains the following files (right-click files you'd like to download):
readwrite.cppxmas.ppm
//[header] // Digital Images //[/header] //[compile] // Download the readwrite.cpp and xmas.ppm file to a folder. // Open a shell/terminal, and run the following command where the files is saved: // // clang++ -o readwrite readwrite.cpp -std=c++11 -O3 // // You can use c++ if you don't use clang++ // // Run with: ./readwrite. Open the resulting image (ppm) in Photoshop or any program // reading PPM files. //[/compile] //[ignore] // Copyright (C) 2016 www.scratchapixel.com // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. //[/ignore] #include <cstdlib> #include <cstdio> #include <cstring> #include <fstream> #include <cassert> #include <exception> // [comment] // The main Image class // [/comment] class Image { public: struct Rgb { Rgb() : r(0), g(0), b(0) {} Rgb(float rr) : r(rr), g(rr), b(rr) {} Rgb(float rr, float gg, float bb) : r(rr), g(gg), b(bb) {} float r, g, b; }; Image() : w(0), h(0), pixels(nullptr) {} Image(const unsigned int &_w, const unsigned int &_h) : w(_w), h(_h), pixels(nullptr) { pixels = new Rgb[w * h]; for (int i = 0; i < w * h; ++i) pixels[i] = 0; } ~Image() { if (pixels != nullptr) delete [] pixels; } unsigned int w, h; Rgb *pixels; }; // [comment] // Save an image to PPM image file // [/comment] void savePPM(const Image &img, const char *filename) { if (img.w == 0 || img.h == 0) { fprintf(stderr, "Can't save an empty image\n"); return; } std::ofstream ofs; try { ofs.open(filename, std::ios::binary); // need to spec. binary mode for Windows users if (ofs.fail()) throw("Can't open output file"); ofs << "P6\n" << img.w << " " << img.h << "\n255\n"; unsigned char r, g, b; // loop over each pixel in the image, clamp and convert to byte format for (int i = 0; i < img.w * img.h; ++i) { r = static_cast<unsigned char>(std::min(1.f, img.pixels[i].r) * 255); g = static_cast<unsigned char>(std::min(1.f, img.pixels[i].g) * 255); b = static_cast<unsigned char>(std::min(1.f, img.pixels[i].b) * 255); ofs << r << g << b; } ofs.close(); } catch (const char *err) { fprintf(stderr, "%s\n", err); ofs.close(); } } // [comment] // Read a PPM image file // [/comment] Image readPPM(const char *filename) { std::ifstream ifs; ifs.open(filename, std::ios::binary); // need to spec. binary mode for Windows users Image img; try { if (ifs.fail()) { throw("Can't open input file"); } std::string header; int w, h, b; ifs >> header; if (strcmp(header.c_str(), "P6") != 0) throw("Can't read input file"); ifs >> w >> h >> b; img.w = w; img.h = h; img.pixels = new Image::Rgb[w * h]; // this is throw an exception if bad_alloc ifs.ignore(256, '\n'); // skip empty lines in necessary until we get to the binary data unsigned char pix[3]; // read each pixel one by one and convert bytes to floats for (int i = 0; i < w * h; ++i) { ifs.read(reinterpret_cast<char *>(pix), 3); img.pixels[i].r = pix[0] / 255.f; img.pixels[i].g = pix[1] / 255.f; img.pixels[i].b = pix[2] / 255.f; } ifs.close(); } catch (const char *err) { fprintf(stderr, "%s\n", err); ifs.close(); } return img; } // [comment] // Read/Write an image stored in the PPM format // [/comment] int main(int argc, char **argv) { Image I = readPPM("./xmas.ppm"); savePPM(I, "./out.ppm"); return 0; }