123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- #include <iostream>
- #include <fstream>
- #include <string.h>
- #include <time.h>
- #include <math.h>
- #include "tgaimage.h"
- TGAImage::TGAImage() : data(NULL), width(0), height(0), bytespp(0) {}
- TGAImage::TGAImage(int w, int h, int bpp) : data(NULL), width(w), height(h), bytespp(bpp) {
- unsigned long nbytes = width*height*bytespp;
- data = new unsigned char[nbytes];
- memset(data, 0, nbytes);
- }
- TGAImage::TGAImage(const TGAImage &img) : data(NULL), width(img.width), height(img.height), bytespp(img.bytespp) {
- unsigned long nbytes = width*height*bytespp;
- data = new unsigned char[nbytes];
- memcpy(data, img.data, nbytes);
- }
- TGAImage::~TGAImage() {
- if (data) delete [] data;
- }
- TGAImage & TGAImage::operator =(const TGAImage &img) {
- if (this != &img) {
- if (data) delete [] data;
- width = img.width;
- height = img.height;
- bytespp = img.bytespp;
- unsigned long nbytes = width*height*bytespp;
- data = new unsigned char[nbytes];
- memcpy(data, img.data, nbytes);
- }
- return *this;
- }
- bool TGAImage::read_tga_file(const char *filename) {
- if (data) delete [] data;
- data = NULL;
- std::ifstream in;
- in.open (filename, std::ios::binary);
- if (!in.is_open()) {
- std::cerr << "can't open file " << filename << "\n";
- in.close();
- return false;
- }
- TGA_Header header;
- in.read((char *)&header, sizeof(header));
- if (!in.good()) {
- in.close();
- std::cerr << "an error occured while reading the header\n";
- return false;
- }
- width = header.width;
- height = header.height;
- bytespp = header.bitsperpixel>>3;
- if (width<=0 || height<=0 || (bytespp!=GRAYSCALE && bytespp!=RGB && bytespp!=RGBA)) {
- in.close();
- std::cerr << "bad bpp (or width/height) value\n";
- return false;
- }
- unsigned long nbytes = bytespp*width*height;
- data = new unsigned char[nbytes];
- if (3==header.datatypecode || 2==header.datatypecode) {
- in.read((char *)data, nbytes);
- if (!in.good()) {
- in.close();
- 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)) {
- in.close();
- std::cerr << "an error occured while reading the data\n";
- return false;
- }
- } else {
- in.close();
- 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 << width << "x" << height << "/" << bytespp*8 << "\n";
- in.close();
- return true;
- }
- bool TGAImage::load_rle_data(std::ifstream &in) {
- unsigned long pixelcount = width*height;
- unsigned long currentpixel = 0;
- unsigned long currentbyte = 0;
- TGAColor colorbuffer;
- do {
- unsigned char 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<chunkheader; i++) {
- in.read((char *)colorbuffer.bgra, bytespp);
- if (!in.good()) {
- std::cerr << "an error occured while reading the header\n";
- return false;
- }
- for (int t=0; t<bytespp; t++)
- data[currentbyte++] = colorbuffer.bgra[t];
- currentpixel++;
- if (currentpixel>pixelcount) {
- std::cerr << "Too many pixels read\n";
- return false;
- }
- }
- } else {
- chunkheader -= 127;
- in.read((char *)colorbuffer.bgra, bytespp);
- if (!in.good()) {
- std::cerr << "an error occured while reading the header\n";
- return false;
- }
- for (int i=0; i<chunkheader; i++) {
- for (int t=0; t<bytespp; t++)
- data[currentbyte++] = colorbuffer.bgra[t];
- currentpixel++;
- if (currentpixel>pixelcount) {
- std::cerr << "Too many pixels read\n";
- return false;
- }
- }
- }
- } while (currentpixel < pixelcount);
- return true;
- }
- bool TGAImage::write_tga_file(const char *filename, bool rle) const {
- unsigned char developer_area_ref[4] = {0, 0, 0, 0};
- unsigned char extension_area_ref[4] = {0, 0, 0, 0};
- unsigned char 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";
- out.close();
- return false;
- }
- TGA_Header header;
- memset((void *)&header, 0, sizeof(header));
- header.bitsperpixel = bytespp<<3;
- header.width = width;
- header.height = height;
- header.datatypecode = (bytespp==GRAYSCALE?(rle?11:3):(rle?10:2));
- header.imagedescriptor = 0x20; // top-left origin
- out.write((char *)&header, sizeof(header));
- if (!out.good()) {
- out.close();
- std::cerr << "can't dump the tga file\n";
- return false;
- }
- if (!rle) {
- out.write((char *)data, width*height*bytespp);
- if (!out.good()) {
- std::cerr << "can't unload raw data\n";
- out.close();
- return false;
- }
- } else {
- if (!unload_rle_data(out)) {
- out.close();
- std::cerr << "can't unload rle data\n";
- return false;
- }
- }
- out.write((char *)developer_area_ref, sizeof(developer_area_ref));
- if (!out.good()) {
- std::cerr << "can't dump the tga file\n";
- out.close();
- return false;
- }
- out.write((char *)extension_area_ref, sizeof(extension_area_ref));
- if (!out.good()) {
- std::cerr << "can't dump the tga file\n";
- out.close();
- return false;
- }
- out.write((char *)footer, sizeof(footer));
- if (!out.good()) {
- std::cerr << "can't dump the tga file\n";
- out.close();
- return false;
- }
- out.close();
- return true;
- }
- // TODO: it is not necessary to break a raw chunk for two equal pixels (for the matter of the resulting size)
- bool TGAImage::unload_rle_data(std::ofstream &out) const {
- const unsigned char max_chunk_length = 128;
- unsigned long npixels = width*height;
- unsigned long curpix = 0;
- while (curpix<npixels) {
- unsigned long chunkstart = curpix*bytespp;
- unsigned long curbyte = curpix*bytespp;
- unsigned char run_length = 1;
- bool raw = true;
- while (curpix+run_length<npixels && run_length<max_chunk_length) {
- bool succ_eq = true;
- for (int t=0; succ_eq && t<bytespp; t++) {
- succ_eq = (data[curbyte+t]==data[curbyte+t+bytespp]);
- }
- curbyte += bytespp;
- if (1==run_length) {
- raw = !succ_eq;
- }
- if (raw && succ_eq) {
- run_length--;
- break;
- }
- if (!raw && !succ_eq) {
- break;
- }
- run_length++;
- }
- curpix += run_length;
- out.put(raw?run_length-1:run_length+127);
- if (!out.good()) {
- std::cerr << "can't dump the tga file\n";
- return false;
- }
- out.write((char *)(data+chunkstart), (raw?run_length*bytespp:bytespp));
- if (!out.good()) {
- std::cerr << "can't dump the tga file\n";
- return false;
- }
- }
- return true;
- }
- TGAColor TGAImage::get(int x, int y) const {
- if (!data || x<0 || y<0 || x>=width || y>=height) {
- return TGAColor(128.f,128.f,128.f,255.f);
- }
- return TGAColor(data+(x+y*width)*bytespp, bytespp);
- }
- bool TGAImage::set(int x, int y, TGAColor &c) {
- if (!data || x<0 || y<0 || x>=width || y>=height) {
- return false;
- }
- memcpy(data+(x+y*width)*bytespp, c.bgra, bytespp);
- return true;
- }
- bool TGAImage::set(int x, int y, const TGAColor &c) {
- if (!data || x<0 || y<0 || x>=width || y>=height) {
- return false;
- }
- memcpy(data+(x+y*width)*bytespp, c.bgra, bytespp);
- return true;
- }
- int TGAImage::get_bytespp() {
- return bytespp;
- }
- int TGAImage::get_width() {
- return width;
- }
- int TGAImage::get_height() {
- return height;
- }
- bool TGAImage::flip_horizontally() {
- if (!data) return false;
- int half = width>>1;
- for (int i=0; i<half; i++) {
- for (int j=0; j<height; j++) {
- TGAColor c1 = get(i, j);
- TGAColor c2 = get(width-1-i, j);
- set(i, j, c2);
- set(width-1-i, j, c1);
- }
- }
- return true;
- }
- bool TGAImage::flip_vertically() {
- if (!data) return false;
- unsigned long bytes_per_line = width*bytespp;
- unsigned char *line = new unsigned char[bytes_per_line];
- int half = height>>1;
- for (int j=0; j<half; j++) {
- unsigned long l1 = j*bytes_per_line;
- unsigned long l2 = (height-1-j)*bytes_per_line;
- memmove((void *)line, (void *)(data+l1), bytes_per_line);
- memmove((void *)(data+l1), (void *)(data+l2), bytes_per_line);
- memmove((void *)(data+l2), (void *)line, bytes_per_line);
- }
- delete [] line;
- return true;
- }
- unsigned char *TGAImage::buffer() {
- return data;
- }
- void TGAImage::clear() {
- memset((void *)data, 0, width*height*bytespp);
- }
- bool TGAImage::scale(int w, int h) {
- if (w<=0 || h<=0 || !data) return false;
- unsigned char *tdata = new unsigned char[w*h*bytespp];
- int nscanline = 0;
- int oscanline = 0;
- int erry = 0;
- unsigned long nlinebytes = w*bytespp;
- unsigned long olinebytes = width*bytespp;
- for (int j=0; j<height; j++) {
- int errx = width-w;
- int nx = -bytespp;
- int ox = -bytespp;
- for (int i=0; i<width; i++) {
- ox += bytespp;
- errx += w;
- while (errx>=(int)width) {
- errx -= width;
- nx += bytespp;
- memcpy(tdata+nscanline+nx, data+oscanline+ox, bytespp);
- }
- }
- erry += h;
- oscanline += olinebytes;
- while (erry>=(int)height) {
- if (erry>=(int)height<<1) // it means we jump over a scanline
- memcpy(tdata+nscanline+nlinebytes, tdata+nscanline, nlinebytes);
- erry -= height;
- nscanline += nlinebytes;
- }
- }
- delete [] data;
- data = tdata;
- width = w;
- height = h;
- return true;
- }
|