Česky
Kamil Dudka

GED 2006 (C++)

File detail

Name:Downloadpngimage.cc [Download]
Location: ged2006 > src
Size:7.5 KB
Last modification:2007-08-29 02:16

Source code

/*
 * File: pngimage.cc - Module loading/saving PNG images
 * Project: GED - bitmap editor (ICP)
 * Author: Jakbub Filak, xfilak01
 * Team: xdudka00, xfilak01, xhefka00, xhradi08
 * Created: 2006-03-10
 */
 
#include <string>
#include <errno.h>
#include <png.h>
#include <iostream>
#include <stdio.h>
 
#include "pngimage.h"
 
#ifndef NDEBUG
#define PRINT(x) std::cout << x << std::endl;
#else
#define PRINT(x) 
#endif
/*
 * create an empty PNG image of size "size"
 */
PNGImage::PNGImage (const BoxSize &size)
	: Image (size)
{
	createPNGInfo();
	initPNGInfo();
}
 
/**
 * create structures
 */
void PNGImage::createPNGInfo()
{
	_png_read = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
	_info = png_create_info_struct( _png_read);
}
 
/**
 * Initialize for default new png image
 */
void PNGImage::initPNGInfo()
{	
	BoxSize box = size();
	_info->height = box.height;
	_info->width = box.width;
	_info->channels = 4;
	_info->rowbytes = _info->channels*box.width;
	_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
	_info->bit_depth = 8;
	_info->interlace_type = PNG_INTERLACE_NONE;
	_info->filter_type = PNG_FILTER_TYPE_BASE;
	_info->compression_type = PNG_COMPRESSION_TYPE_BASE;
	_info->pixel_depth = 8;
	_info->srgb_intent = 0;
	_n_of_passes = 1;
}
 
/*
 * open "fileName" PNG image and read image
 */
PNGImage::PNGImage (const std::string &fileName) :Image(fileName) {
	FILE* png_file;
	png_bytep png_sig_buff;
 
	if ( (png_file = fopen(fileName.c_str(), "rb")) == NULL ) {
		throw ErrLoad();
	}
 
	png_sig_buff = new png_byte[_png_sig_num_bytes];
 
	fread(png_sig_buff, 1, _png_sig_num_bytes, png_file);					
 
	if ( png_sig_cmp( png_sig_buff, 0, _png_sig_num_bytes) ) {
		fclose( png_file );
		throw ErrLoad();
	}
 
	delete [] png_sig_buff;
	PRINT("Creating structures ... ")
	createPNGInfo();
	PRINT("[  OK  ]")
	PRINT("Setting long jump ... ")
	if ( setjmp(_png_read->jmpbuf)) {
		png_destroy_read_struct( &_png_read, &_info, (png_infopp)NULL );
		throw ErrLoad();
	}
	PRINT("[  OK  ]")
	PRINT("png init io ...")
	png_init_io( _png_read, png_file );
	PRINT("[  OK  ]")
	PRINT("png set read sig bytes ...")
	png_set_sig_bytes( _png_read, _png_sig_num_bytes );
	PRINT("[  OK  ]")
	PRINT("png read info")
	png_read_info( _png_read, _info );
	PRINT("[  OK  ]")
	PRINT("striping bit depth")
	if (_info->bit_depth == 16) {
		png_set_strip_16(_png_read);
	}
	PRINT("[  OK  ]")
	PRINT("expadn")
	if (_info->color_type == PNG_COLOR_TYPE_GRAY && _info->bit_depth < 8) {
		png_set_expand(_png_read);
	}
	PRINT("[  OK  ]")
	PRINT("packing")
	if (_info->color_type == PNG_COLOR_TYPE_PALETTE && _info->bit_depth < 8 ) {
		png_set_packing(_png_read);
	}
	PRINT("[  OK  ]")
	PRINT("expand if color type is PALETTE")
	if (_info->color_type == PNG_COLOR_TYPE_PALETTE ) {
		png_set_expand(_png_read);
	}
	PRINT("[  OK  ]")
	PRINT("expand")
	if (_info->color_type != PNG_COLOR_TYPE_PALETTE && (_info->valid & PNG_INFO_tRNS)) {
		png_set_expand(_png_read);
	}				
	PRINT("[  OK  ]")
	PRINT("packing if bit depth is less than 8")
	if (_info->bit_depth < 8) {
		png_set_packing(_png_read);
	}
	PRINT("[  OK  ]")
	PRINT("change type to RGB")
	if (_info->color_type == PNG_COLOR_TYPE_GRAY || _info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
		png_set_gray_to_rgb(_png_read);
	}
	PRINT("[  OK  ]")
	PRINT("setting interlance handling")
	_n_of_passes = png_set_interlace_handling(_png_read);
	PRINT("[  OK  ]")
	_n_of_passes = 1;
	_color_type = static_cast<int>( _info->color_type );
	PRINT("read update info")
	png_read_update_info(_png_read, _info);
	PRINT("[  OK  ]")
	PRINT("setting size")	
	this->size ( BoxSize( _info->width, _info->height) );
	PRINT("[  OK  ]")
	PRINT("getting row bytes")
	png_bytepp row_pointers = new png_bytep[_info->height];
	png_uint_32 row_bytes = png_get_rowbytes( _png_read, _info );
 
	for( unsigned int row = 0; row < _info->height; row++ ) {
		row_pointers[row] = new png_byte[row_bytes];
	}
	PRINT("[  OK  ]")
	PRINT("reading image")
	for (int pass = 1; pass <= _n_of_passes; pass++ ) {
		png_read_rows(_png_read, row_pointers, NULL, _info->height);
	}
	PRINT("[  OK  ]")
	PRINT("copying data to buffer")
	for ( unsigned int row = 0, pixel = 0; row < _info->height; row++) {
		for ( unsigned int byte_in_row = 0; byte_in_row + (_info->channels-1) < row_bytes;
		       byte_in_row += _info->channels) {
			_pBuff[pixel].red   = row_pointers[row][byte_in_row];
			_pBuff[pixel].green = row_pointers[row][byte_in_row + 1];
			_pBuff[pixel].blue  = row_pointers[row][byte_in_row + 2];
			if ( _info->channels == 4 ) {
				_pBuff[pixel].alpha = row_pointers[row][byte_in_row + 3];
			}
			else {
				_pBuff[pixel].alpha = 0xff;	// we are using alpha channel, 0xff is full
								// openaguu
			}
			pixel += 1; // next pixel in framebuffer
		}
	}
	PRINT("[  OK  ]")
	PRINT("read end")
	png_read_end (_png_read, _info );
	PRINT("[  OK  ]")
 
	for( unsigned int row = 0; row < _info->height; row++ ) {
		delete [] row_pointers[row];
	}
 
	delete [] row_pointers;
 
	fclose(png_file);
	// set image name
	this->name (fileName);
}
 
/*
 * create PNG image from "img"
 */
PNGImage::PNGImage (const Image &img)
	: Image (img)
{	
	createPNGInfo();
	initPNGInfo();
}
 
/*
 * Destroy PNG image structures
 */
PNGImage::~PNGImage () {
	png_destroy_read_struct(&_png_read, &_info, (png_infopp)NULL );
}
 
/**
 * save PNG image
 */
void PNGImage::save (const std::string &fileName) {
	FILE* png_file;
 
	if ( (png_file = fopen( fileName.c_str(), "wb")) == NULL){
		throw ErrSave();
	}
 
	png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
 
	if ( png_ptr == NULL ) {
		fclose(png_file);
		throw ErrSave();
	}
 
	if ( setjmp(png_jmpbuf(png_ptr))) {
		png_destroy_write_struct(&png_ptr, NULL);
		fclose( png_file);
	}
 
	png_init_io(png_ptr, png_file);	
 
	BoxSize box= size();
	_info->height = box.height;	// set height
	_info->width = box.width;	// set width
	_info->channels = _info->channels >= 3 ? _info->channels : 3;	// we need minimal 3 channels
 
	if ( _color_type == PNG_COLOR_TYPE_PALETTE ) {
		_info->valid &= 0xffef;	// if original is PALETTE we must delete tRNS chunk
	}
 
	png_write_info( png_ptr, _info);	//write info
 
	if ( _n_of_passes > 1 ) {
		_n_of_passes = png_set_interlace_handling(png_ptr);	// set interlace handling
	}
 
	if ( _info->color_type == PNG_COLOR_TYPE_PALETTE && _info->bit_depth < 8 ) {
		png_set_packing(png_ptr);
	}
 
	png_bytepp row_pointers = new png_bytep[_info->height];	// create memory for image in png format
 
	int channels = _info->channels;	// get channels
 
	png_uint_32 row_bytes = channels*_info->width;	// how many bytes we need for image in png
 
	for( unsigned int row = 0; row < _info->height; row++ ) {
		row_pointers[row] = new png_byte[row_bytes];	// create memory for pixels on rows
	}
 
	for ( unsigned int row = 0, pixel = 0; row < _info->height; row++) {	// copy image to png format
		for ( unsigned int byte_in_row = 0; byte_in_row + (channels-1) < row_bytes;
		      byte_in_row += channels) {
			row_pointers[row][byte_in_row] = _pBuff[pixel].red;
			row_pointers[row][byte_in_row + 1] = _pBuff[pixel].green;
			row_pointers[row][byte_in_row + 2] = _pBuff[pixel].blue;
			if ( channels == 4 ) {
				row_pointers[row][byte_in_row + 3] = _pBuff[pixel].alpha;
			}
			pixel += 1; // next pixel in framebuffer
		}
	}
 
	for ( int pass = 1; pass <= _n_of_passes; pass++ ) {	// write image
		png_write_rows(png_ptr, row_pointers, _info->height);
	}
 
	png_write_end (png_ptr, _info );
 
	png_destroy_write_struct( &png_ptr, NULL );
 
	for( unsigned int row = 0; row < _info->height; row++ ) {
		delete [] row_pointers[row];
	}
 
	delete [] row_pointers;
 
	fclose(png_file);																		
	// set image name
	this->name (fileName);
}