#pragma once #include #include #include #include #include #include #include #include #include #include "pnm.h" using namespace std; // // // Point // template struct TPoint { T x; T y; TPoint(T a, T b) : x(a) , y(b) {} TPoint& operator+=(TPoint const& rhs) { x += rhs.x; y += rhs.y; return *this; } TPoint& operator-=(TPoint const& rhs) { x -= rhs.x; y -= rhs.y; return *this; } TPoint& operator*=(TPoint const& rhs) { x *= rhs.x; y *= rhs.y; return *this; } TPoint& operator/=(TPoint const& rhs) { x /= rhs.x; y /= rhs.y; return *this; } }; typedef TPoint Point; typedef TPoint DPoint; // absolute point, can be negative template std::basic_ostream& operator << (std::basic_ostream& o, TPoint const& p) { o << "(" << p.x << ", " << p.y << ")"; return o; } // // // Pixel // typedef uint16_t pvalue_t; // pixel value type // // // Image // struct Image { unsigned int width; unsigned int height; pvalue_t* buffer; pnm::Format type; size_t pixel_size; Image(); Image(unsigned int w, unsigned int h, pnm::Format type); Image(string const& path); virtual ~Image(); bool save(string const& path) const; protected: virtual bool read_body(std::ifstream& istr); virtual bool write_body(std::ofstream& ostr) const; }; template struct TiledImage : public Image { pvalue_t* tiles; unsigned int static const tile_w = W; unsigned int static const tile_h = H; // two lines overlap, bottom + right unsigned int static const tile_size = (W + 1) * (H + 1); unsigned int nb_col_tile; unsigned int nb_row_tile; TiledImage() : Image() , tiles(NULL) , nb_col_tile(0) , nb_row_tile(0) {} ~TiledImage() { delete [] tiles; } TiledImage(unsigned int w, unsigned int h) { allocate_memory(w, h); } TiledImage(string const& path) : TiledImage() { ifstream is(path); if (!is.is_open()) { cerr << "Cannot open file '" << path << "'" << endl; abort(); } if (!pnm::read_header(is, this->type, this->width, this->height)) { cerr << "Invalid header." << endl; abort(); } if (!this->read_body(is)) { // TODO: delete tiles cerr << "Invalid header." << endl; abort(); } } pvalue_t const* get_tile(unsigned int index) const { if (index >= nb_col_tile * nb_row_tile) return nullptr; return tiles + index * tile_size * pixel_size; } pvalue_t* get_tile(unsigned int index) { if (index >= nb_col_tile * nb_row_tile) return nullptr; return tiles + index * tile_size * pixel_size; } pvalue_t* access_pixel(unsigned int x, unsigned int y) { if (x >= width || y >= height) return nullptr; unsigned int const tile_width = (tile_w + 1) * pixel_size; unsigned int const tile_index = (y / tile_h) * nb_col_tile + (x / tile_w); pvalue_t* tile = this->get_tile(tile_index); unsigned int const tile_j = y % tile_h; unsigned int const tile_i = x % tile_w; return tile + tile_j * tile_width + (tile_i * pixel_size); } pvalue_t const* access_pixel(unsigned int x, unsigned int y) const { if (x >= width || y >= height) return nullptr; unsigned int const tile_width = (tile_w + 1) * pixel_size; unsigned int const tile_index = (y / tile_h) * nb_col_tile + (x / tile_w); const pvalue_t* tile = this->get_tile(tile_index); unsigned int const tile_j = y % tile_h; unsigned int const tile_i = x % tile_w; return tile + tile_j * tile_width + (tile_i * pixel_size); } void print_tile(unsigned int index) const { cout << "Tile[" << index << "]" << endl; pvalue_t const* tile = this->get_tile(index); unsigned int const tile_width = (tile_w + 1) * pixel_size; for (unsigned int j = 0; j < tile_h + 1; ++j) { for (unsigned int i = 0; i < tile_w + 1; ++i) { if (i != 0) cout << ", "; pvalue_t const* p = tile + j * tile_width + i * pixel_size; cout << (int) *p << " " << (int) *(p + 1) << " " << (int) *(p + 2); } cout << endl; } cout << endl; } void fill_overlap() { unsigned int const tile_width = (W + 1) * pixel_size; for (int j = nb_row_tile - 1; j >= 0; --j) for (unsigned int i = 0; i < nb_col_tile; ++i) { // copy last line overlap if (j != (int) nb_row_tile - 1) { pvalue_t const* tile_src = this->access_pixel(i * W, (j + 1) * H); pvalue_t* tile_dst = this->access_pixel(i * W, j * H); tile_dst += H * tile_width; memcpy(tile_dst, tile_src, tile_width * sizeof (pvalue_t)); } // copy last col overlap if (i != nb_col_tile - 1) { pvalue_t* tile_src = this->get_tile(i + 1 + j * nb_col_tile); pvalue_t* tile_dst = this->get_tile(i + j * nb_col_tile); tile_dst += W * pixel_size; for (unsigned int y = 0; y < H; ++y) { memcpy(tile_dst, tile_src, pixel_size * sizeof (pvalue_t)); tile_src += tile_width; tile_dst += tile_width; } } } } protected: void allocate_memory(unsigned int w, unsigned int h) { width = w; height = h; nb_col_tile = width / tile_w; if (width % tile_w != 0) ++nb_col_tile; nb_row_tile = height / tile_h; if (height % tile_h != 0) ++nb_row_tile; unsigned int const nb_tiles = nb_col_tile * nb_row_tile; tiles = new pvalue_t[nb_tiles * tile_size * pixel_size]; memset(tiles, 0, nb_tiles * tile_size * pixel_size * sizeof (pvalue_t)); } virtual bool read_body(std::ifstream& istr) override { this->allocate_memory(width, height); // Pixel loading for (unsigned int j = 0; j < height; ++j) for (unsigned int i = 0; i < width; ++i) { pvalue_t* tile = this->access_pixel(i, j); tile[0] = istr.get(); tile[1] = istr.get(); tile[2] = istr.get(); tile += pixel_size; } this->fill_overlap(); return true; } virtual bool write_body(std::ofstream& ostr) const override { for (unsigned int j = 0; j < height; ++j) for (unsigned int i = 0; i < width; ++i) { pvalue_t const* tile = this->access_pixel(i, j); ostr << (char) tile[0]; ostr << (char) tile[1]; ostr << (char) tile[2]; tile += pixel_size; } return true; } };