Browse Source

[PPM] Reading functionality; Merged reader and writer in one class; Improved testing

master
Unbewohnte 3 years ago
parent
commit
2a34ba01ca
  1. 4
      .gitignore
  2. 124
      src/pnm.cpp
  3. 64
      tests/test.cpp

4
.gitignore vendored

@ -1,2 +1,4 @@
image.ppm result_image.ppm
img.ppm
test_img512x512.ppm
test test

124
src/pnm.cpp

@ -10,9 +10,16 @@ The above copyright notice and this permission notice shall be included in all c
THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#ifndef RWPNM #ifndef RWPNM
#define RWPNM #define RWPNM
/*
RWPNM v0.1.0
A drop-in library to work with PNM images
*/
#include <vector> #include <vector>
#include <fstream> #include <fstream>
@ -36,6 +43,15 @@ public:
uint8_t R; uint8_t R;
uint8_t G; uint8_t G;
uint8_t B; uint8_t B;
bool operator==(const RGB& other) {
if (R != other.R || G != other.G || B != other.B) {
return false;
}
return true;
}
}; };
class Grayscale : public Color { class Grayscale : public Color {
@ -49,7 +65,7 @@ public:
}; };
// PPM file format reader/writer base class // PPM image file format reader/writer
class PPM { class PPM {
protected: protected:
// PPM colored image magic number // PPM colored image magic number
@ -71,37 +87,86 @@ protected:
} }
public: public:
PPM() {} PPM() {
// set defaults (these can and will be changed when reading/coloring the image)
m_width = 0;
m_height = 0;
m_max_color = 255;
}
~PPM() {} ~PPM() {}
// Color a pixel at coordinates (x, y) // Color a pixel at coordinates (x, y)
void put_pixel(uint32_t x, uint32_t y, RGB color) { void put_pixel(uint32_t x, uint32_t y, RGB color) {
uint64_t i = index_at(x, y); uint64_t i = index_at(x, y);
if (i >= m_pixel_data.size()) {
// the image is not big enough !
m_pixel_data.resize(i + 1);
if (i >= (m_width * m_height)) { if (x > m_width) {
throw std::runtime_error("Pixel coordinates are out of bounds"); m_width = x + 1;
}
if (y > m_height) {
m_height = y + 1;
}
} }
m_pixel_data.at(i) = color; m_pixel_data.at(i) = color;
} }
};
// PPM file format image writer class // Read PPM image from disk
class PPM_writer : public PPM { void read(std::string path) {
public: // try to open file
PPM_writer(uint32_t width, uint32_t height, uint16_t maxcolor = 255) { std::ifstream ppm_image_file;
m_width = width; ppm_image_file.open(path, std::ios::in);
m_height = height; if (!ppm_image_file.is_open()) {
m_max_color = maxcolor; throw std::runtime_error("Could not open an image");
m_pixel_data.resize(width*height); }
// check for magic number
std::string entity;
ppm_image_file >> entity;
if (entity != "P6") {
throw std::runtime_error("Does not have a magic number");
}
// width, height, max color
ppm_image_file >> entity;
m_width = std::stoi(entity);
ppm_image_file >> entity;
m_height = std::stoi(entity);
ppm_image_file >> entity;
m_max_color = std::stoi(entity);
m_pixel_data.resize(m_width * m_height);
// skip one byte
char one[1];
ppm_image_file.read(one, 1);
// retrieve pixels
char pixel_color[3];
for (uint64_t i = 0; i < m_width * m_height; i++) {
ppm_image_file.read(pixel_color, 3);
RGB color(pixel_color[0], pixel_color[1], pixel_color[2]);
if (color == RGB(255, 0, 0)) {
break;
}
m_pixel_data.at(i) = color;
}
ppm_image_file.close();
} }
~PPM_writer() {}
// Write PPM image to disk // Write PPM image to disk
void save(std::string path) { void save(std::string path) {
// check if there are less/more pixels than needed // check if there are pixels at all
if (m_pixel_data.size() > (m_width * m_height) || m_pixel_data.size() < (m_width * m_height)) { if (m_pixel_data.size() == 0) {
throw std::runtime_error("Invalid amount of pixels. There must be width*height pixels"); throw std::runtime_error("No pixels were assigned");
} }
// try to create file // try to create file
@ -130,31 +195,6 @@ public:
} }
}; };
class PPM_reader : public PPM {
public:
PPM_reader() {}
~PPM_reader() {}
// Read PPM image from disk
void read(std::string path) {
// try to open file
std::ifstream ppm_image_file;
ppm_image_file.open(path, std::ios::in);
if (!ppm_image_file.is_open()) {
throw std::runtime_error("Could not open an image");
}
while(true) {
std::string data;
ppm_image_file >> data;
if (data.length() == 0) {
break;
}
}
}
};
} }
#endif #endif

64
tests/test.cpp

@ -1,29 +1,71 @@
#include <iostream> #include <iostream>
#include "../src/pnm.cpp" #include "../src/pnm.cpp"
using namespace pnm;
int main() { void make_test_img() {
try {
pnm::PPM image;
const uint32_t width = 512;
const uint32_t height = 512;
for (uint32_t y = 0; y < height; y++) {
for (uint32_t x = 0; x < width; x++) {
image.put_pixel(x, y, pnm::RGB(x / 2, y / 2, x / 2 + y / 2));
}
}
image.save("test_img512x512.ppm");
} catch(const std::exception& e) {
std::string error_message("make_test_img: ", e.what());
throw std::runtime_error(error_message);
}
}
void green_rectangle_on_top_of_existing_image() {
try { try {
PPM_writer ppm_image(800, 800); pnm::PPM image;
image.read("test_img512x512.ppm");
// image.read("img.ppm");
uint8_t cc = 0; uint32_t rec_width = 100;
for (uint32_t y = 0; y < 800; y++) { uint32_t rec_height = 100;
for (uint32_t x = 0; x < 800; x++) {
ppm_image.put_pixel(x, y, RGB(cc, cc, cc));
cc++; for (uint32_t y = 0; y < rec_height; y++) {
for (uint32_t x = 0; x < rec_width; x++) {
image.put_pixel(x, y, pnm::RGB(0, 255, 0));
} }
cc--;
} }
ppm_image.save("image.ppm");
image.save("result_image.ppm");
} catch(const std::exception& e) {
std::string error_message("green_rectangle_on_top_of_existing_image: ", e.what());
throw std::runtime_error(error_message);
}
}
void no_pixel_assign() {
try {
pnm::PPM image;
image.save("result_image.ppm");
std::string error_message("no_pixel_assign: should`ve gotten an error, but there weren`t any thrown");
throw std::runtime_error(error_message);
} catch(const std::exception& e) {}
}
int main() {
try {
make_test_img();
green_rectangle_on_top_of_existing_image();
no_pixel_assign();
} catch(const std::exception& e) { } catch(const std::exception& e) {
std::cout << "[ERROR] " << e.what() << "\n"; std::cout << "[ERROR] " << e.what() << "\n";
return 1; return 1;
} }
std::cout << "[SUCCESS]\n"; std::cout << "[ALL TESTS WERE COMPLETED SUCCESSFULLY]\n";
return 0; return 0;
} }

Loading…
Cancel
Save