#include #include #include "tgaimage.h" TGAImage::TGAImage(const int w, const int h, const int bpp, TGAColor c) : w(w), h(h), bpp(bpp), data(w*h*bpp, 0) { for (int j=0; j(&header), sizeof(header)); if (!in.good()) { std::cerr << "an error occured while reading the header\n"; return false; } w = header.width; h = header.height; bpp = header.bitsperpixel>>3; if (w<=0 || h<=0 || (bpp!=GRAYSCALE && bpp!=RGB && bpp!=RGBA)) { std::cerr << "bad bpp (or width/height) value\n"; return false; } size_t nbytes = bpp*w*h; data = std::vector(nbytes, 0); if (3==header.datatypecode || 2==header.datatypecode) { in.read(reinterpret_cast(data.data()), nbytes); if (!in.good()) { std::cerr << "an error occured while reading the data\n"; return false; } } else if (10==header.datatypecode||11==header.datatypecode) { if (!load_rle_data(in)) { std::cerr << "an error occured while reading the data\n"; return false; } } else { std::cerr << "unknown file format " << (int)header.datatypecode << "\n"; return false; } if (!(header.imagedescriptor & 0x20)) flip_vertically(); if (header.imagedescriptor & 0x10) flip_horizontally(); std::cerr << w << "x" << h << "/" << bpp*8 << "\n"; return true; } bool TGAImage::load_rle_data(std::ifstream &in) { size_t pixelcount = w*h; size_t currentpixel = 0; size_t currentbyte = 0; TGAColor colorbuffer; do { std::uint8_t chunkheader = 0; chunkheader = in.get(); if (!in.good()) { std::cerr << "an error occured while reading the data\n"; return false; } if (chunkheader<128) { chunkheader++; for (int i=0; i(colorbuffer.bgra), bpp); if (!in.good()) { std::cerr << "an error occured while reading the header\n"; return false; } for (int t=0; tpixelcount) { std::cerr << "Too many pixels read\n"; return false; } } } else { chunkheader -= 127; in.read(reinterpret_cast(colorbuffer.bgra), bpp); if (!in.good()) { std::cerr << "an error occured while reading the header\n"; return false; } for (int i=0; ipixelcount) { std::cerr << "Too many pixels read\n"; return false; } } } } while (currentpixel < pixelcount); return true; } bool TGAImage::write_tga_file(const std::string filename, const bool vflip, const bool rle) const { constexpr std::uint8_t developer_area_ref[4] = {0, 0, 0, 0}; constexpr std::uint8_t extension_area_ref[4] = {0, 0, 0, 0}; constexpr std::uint8_t footer[18] = {'T','R','U','E','V','I','S','I','O','N','-','X','F','I','L','E','.','\0'}; std::ofstream out; out.open(filename, std::ios::binary); if (!out.is_open()) { std::cerr << "can't open file " << filename << "\n"; return false; } TGAHeader header = {}; header.bitsperpixel = bpp<<3; header.width = w; header.height = h; header.datatypecode = (bpp==GRAYSCALE ? (rle?11:3) : (rle?10:2)); header.imagedescriptor = vflip ? 0x00 : 0x20; // top-left or bottom-left origin out.write(reinterpret_cast(&header), sizeof(header)); if (!out.good()) goto err; if (!rle) { out.write(reinterpret_cast(data.data()), w*h*bpp); if (!out.good()) goto err; } else if (!unload_rle_data(out)) goto err; out.write(reinterpret_cast(developer_area_ref), sizeof(developer_area_ref)); if (!out.good()) goto err; out.write(reinterpret_cast(extension_area_ref), sizeof(extension_area_ref)); if (!out.good()) goto err; out.write(reinterpret_cast(footer), sizeof(footer)); if (!out.good()) goto err; return true; err: std::cerr << "can't dump the tga file\n"; return false; } bool TGAImage::unload_rle_data(std::ofstream &out) const { const std::uint8_t max_chunk_length = 128; size_t npixels = w*h; size_t curpix = 0; while (curpix(data.data()+chunkstart), (raw?run_length*bpp:bpp)); if (!out.good()) return false; } return true; } TGAColor TGAImage::get(const int x, const int y) const { if (!data.size() || x<0 || y<0 || x>=w || y>=h) return {}; TGAColor ret = {0, 0, 0, 0, bpp}; const std::uint8_t *p = data.data()+(x+y*w)*bpp; for (int i=bpp; i--; ret.bgra[i] = p[i]); return ret; } void TGAImage::set(int x, int y, const TGAColor &c) { if (!data.size() || x<0 || y<0 || x>=w || y>=h) return; memcpy(data.data()+(x+y*w)*bpp, c.bgra, bpp); } void TGAImage::flip_horizontally() { for (int i=0; i