X-Git-Url: https://fleuret.org/cgi-bin/gitweb/gitweb.cgi?p=pom.git;a=blobdiff_plain;f=rgb_image.cc;fp=rgb_image.cc;h=26d4e3c96a22f94111ddd666665de3720ad7f83b;hp=0000000000000000000000000000000000000000;hb=97a7e68f234cc09807d2d55f550e2516be0e9093;hpb=48c9926a2ed03737a3b024a85cda348caebf4cfe diff --git a/rgb_image.cc b/rgb_image.cc new file mode 100644 index 0000000..26d4e3c --- /dev/null +++ b/rgb_image.cc @@ -0,0 +1,340 @@ + +////////////////////////////////////////////////////////////////////////////////// +// This program is free software: you can redistribute it and/or modify // +// it under the terms of the version 3 of the GNU General Public License // +// as published by the Free Software Foundation. // +// // +// 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 . // +// // +// Written by Francois Fleuret // +// (C) Ecole Polytechnique Federale de Lausanne // +// Contact for comments & bug reports // +////////////////////////////////////////////////////////////////////////////////// + +#include +#include + +using namespace std; + +#include + +#include "rgb_image.h" + +void RGBImage::allocate() { + _bit_plans = new unsigned char **[RGB_DEPTH]; + _bit_lines = new unsigned char *[RGB_DEPTH * _height]; + _bit_map = new unsigned char [_width * _height * RGB_DEPTH]; + for(int k = 0; k < RGB_DEPTH; k++) _bit_plans[k] = _bit_lines + k * _height; + for(int k = 0; k < RGB_DEPTH * _height; k++) _bit_lines[k] = _bit_map + k * _width; +} + +void RGBImage::deallocate() { + delete[] _bit_plans; + delete[] _bit_lines; + delete[] _bit_map; +} + +RGBImage::RGBImage() : _bit_plans(0), _bit_lines(0), _bit_map(0) { } + +RGBImage::RGBImage(int width, int height) : _width(width), _height(height) { + allocate(); + memset(_bit_map, 0, _width * _height * RGB_DEPTH * sizeof(unsigned char)); +} + +RGBImage::~RGBImage() { + deallocate(); +} + +void RGBImage::write_ppm(const char *filename) { + FILE *outfile; + + if ((outfile = fopen (filename, "wb")) == 0) { + fprintf (stderr, "Can't open %s for reading\n", filename); + exit(1); + } + + fprintf(outfile, "P6\n%d %d\n255\n", _width, _height); + + char *raw = new char[_width * _height * 3]; + + int k = 0; + for(int y = 0; y < _height; y++) for(int x = 0; x < _width; x++) { + raw[k++] = _bit_map[x + _width * (y + _height * RED)]; + raw[k++] = _bit_map[x + _width * (y + _height * GREEN)]; + raw[k++] = _bit_map[x + _width * (y + _height * BLUE)]; + } + + fwrite((void *) raw, sizeof(unsigned char), _width * _height * 3, outfile); + fclose(outfile); + + delete[] raw; +} + +void RGBImage::read_ppm(const char *filename) { + const int buffer_size = 1024; + FILE *infile; + char buffer[buffer_size]; + int max; + + deallocate(); + + if((infile = fopen (filename, "r")) == 0) { + fprintf (stderr, "Can't open %s for reading\n", filename); + exit(1); + } + + fgets(buffer, buffer_size, infile); + + if(strncmp(buffer, "P6", 2) == 0) { + + do { + fgets(buffer, buffer_size, infile); + } while((buffer[0] < '0') || (buffer[0] > '9')); + sscanf(buffer, "%d %d", &_width, &_height); + fgets(buffer, buffer_size, infile); + sscanf(buffer, "%d", &max); + + allocate(); + + unsigned char *raw = new unsigned char[_width * _height * RGB_DEPTH]; + fread(raw, sizeof(unsigned char), _width * _height * RGB_DEPTH, infile); + + int k = 0; + for(int y = 0; y < _height; y++) for(int x = 0; x < _width; x++) { + _bit_plans[RED][y][x] = raw[k++]; + _bit_plans[GREEN][y][x] = raw[k++]; + _bit_plans[BLUE][y][x] = raw[k++]; + } + + delete[] raw; + + } else if(strncmp(buffer, "P5", 2) == 0) { + + do { + fgets(buffer, buffer_size, infile); + } while((buffer[0] < '0') || (buffer[0] > '9')); + sscanf(buffer, "%d %d", &_width, &_height); + fgets(buffer, buffer_size, infile); + sscanf(buffer, "%d", &max); + + allocate(); + + unsigned char *pixbuf = new unsigned char[_width * _height]; + fread(buffer, sizeof(unsigned char), _width * _height, infile); + + int k = 0, l = 0; + for(int y = 0; y < _height; y++) for(int x = 0; x < _width; x++) { + unsigned char c = pixbuf[k++]; + _bit_map[l++] = c; + _bit_map[l++] = c; + _bit_map[l++] = c; + } + + delete[] pixbuf; + + } else { + cerr << "Can not read ppm of type [" << buffer << "] from " << filename << ".\n"; + exit(1); + } +} + +void RGBImage::read_png(const char* filename) { + // This is the number of bytes the read_png routine will read to + // decide if the file is a PNG or not. According to the png + // documentation, it can be 1 to 8 bytes, 8 being the max and the + // best. + + const int header_size = 8; + + png_byte header[header_size]; + png_bytep *row_pointers; + + deallocate(); + + // open file + FILE *fp = fopen(filename, "rb"); + if (!fp) { + cerr << "Unable to open file " << filename << " for reading.\n"; + exit(1); + } + + // read header + fread(header, 1, header_size, fp); + if (png_sig_cmp(header, 0, header_size)) { + cerr << "File " << filename << " does not look like PNG.\n"; + fclose(fp); + exit(1); + } + + // create png pointer + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); + if (!png_ptr) { + cerr << "png_create_read_struct failed\n"; + fclose(fp); + exit(1); + } + + // create png info struct + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_read_struct(&png_ptr, (png_infopp) 0, (png_infopp) 0); + cerr << "png_create_info_struct failed\n"; + fclose(fp); + exit(1); + } + + // get image info + png_init_io(png_ptr, fp); + png_set_sig_bytes(png_ptr, header_size); + png_read_info(png_ptr, info_ptr); + + _width = info_ptr->width; + _height = info_ptr->height; + + png_byte bit_depth, color_type, channels; + color_type = info_ptr->color_type; + bit_depth = info_ptr->bit_depth; + channels = info_ptr->channels; + + if(bit_depth != 8) { + cerr << "Can only read 8-bits PNG images." << endl; + exit(1); + } + + // allocate image pointer + row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * _height); + for (int y = 0; y < _height; y++) + row_pointers[y] = (png_byte*) malloc(info_ptr->rowbytes); + + allocate(); + + // read image + png_read_image(png_ptr, row_pointers); + + // send image to red, green and blue buffers + switch (color_type) { + case PNG_COLOR_TYPE_GRAY: + { + unsigned char pixel = 0; + for (int y = 0; y < _height; y++) for (int x = 0; x < _width; x++) { + pixel = row_pointers[y][x]; + _bit_plans[RED][y][x] = pixel; + _bit_plans[GREEN][y][x] = pixel; + _bit_plans[BLUE][y][x] = pixel; + } + } + break; + + case PNG_COLOR_TYPE_GRAY_ALPHA: + cerr << "PNG type GRAY_ALPHA not supported.\n"; + exit(1); + break; + + case PNG_COLOR_TYPE_PALETTE: + cerr << "PNG type PALETTE not supported.\n"; + exit(1); + break; + + case PNG_COLOR_TYPE_RGB: + { + if(channels != RGB_DEPTH) { + cerr << "Unsupported number of channels for RGB type\n"; + break; + } + int k; + for (int y = 0; y < _height; y++) { + k = 0; + for (int x = 0; x < _width; x++) { + _bit_plans[RED][y][x] = row_pointers[y][k++]; + _bit_plans[GREEN][y][x] = row_pointers[y][k++]; + _bit_plans[BLUE][y][x] = row_pointers[y][k++]; + } + } + } + break; + + case PNG_COLOR_TYPE_RGB_ALPHA: + cerr << "PNG type RGB_ALPHA not supported.\n"; + exit(1); + break; + + default: + cerr << "Unknown PNG type\n"; + exit(1); + } + + // release memory + png_destroy_read_struct(&png_ptr, &info_ptr, 0); + + for (int y = 0; y < _height; y++) free(row_pointers[y]); + free(row_pointers); + + fclose(fp); +} + +void RGBImage::write_png(const char *filename) { + png_bytep *row_pointers; + + // create file + FILE *fp = fopen(filename, "wb"); + + if (!fp) { + cerr << "Unable to create image '" << filename << "'\n"; + exit(1); + } + + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); + + if (!png_ptr) { + cerr << "png_create_write_struct failed\n"; + fclose(fp); + exit(1); + } + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + cerr << "png_create_info_struct failed\n"; + fclose(fp); + exit(1); + } + + png_init_io(png_ptr, fp); + + png_set_IHDR(png_ptr, info_ptr, _width, _height, + 8, 2, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + png_write_info(png_ptr, info_ptr); + + // allocate memory + row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * _height); + for (int y = 0; y < _height; y++) + row_pointers[y] = (png_byte*) malloc(info_ptr->rowbytes); + + int k; + for (int y = 0; y < _height; y++) { + k = 0; + for (int x = 0; x < _width; x++) { + row_pointers[y][k++] = _bit_map[x + _width * (y + _height * RED)]; + row_pointers[y][k++] = _bit_map[x + _width * (y + _height * GREEN)]; + row_pointers[y][k++] = _bit_map[x + _width * (y + _height * BLUE)]; + } + } + + png_write_image(png_ptr, row_pointers); + png_write_end(png_ptr, 0); + + png_destroy_write_struct(&png_ptr, &info_ptr); + + // cleanup heap allocation + for (int y = 0; y < _height; y++) free(row_pointers[y]); + free(row_pointers); + + fclose(fp); +}