Alien-FreeImage

 view release on metacpan or  search on metacpan

src/Source/FreeImage/PluginTARGA.cpp  view on Meta::CPAN


	WORD is_xorigin;			//! X-origin of image (absolute coordinate of lower-left corner for displays where origin is at the lower left)
	WORD is_yorigin;			//! Y-origin of image (as for X-origin)
	WORD is_width;				//! image width
	WORD is_height;				//! image height
	BYTE is_pixel_depth;		//! bits per pixel
	BYTE is_image_descriptor;	//! image descriptor, bits 3-0 give the alpha channel depth, bits 5-4 give direction
} TGAHEADER;

typedef struct tagTGAEXTENSIONAREA {
	WORD extension_size;		// Size in bytes of the extension area, always 495
	char author_name[41];		// Name of the author. If not used, bytes should be set to NULL (\0) or spaces
	char author_comments[324];	// A comment, organized as four lines, each consisting of 80 characters plus a NULL
	WORD datetime_stamp[6];		// Date and time at which the image was created
	char job_name[41];			// Job ID
	WORD job_time[3];			// Hours, minutes and seconds spent creating the file (for billing, etc.)
	char software_id[41];		// The application that created the file
	BYTE software_version[3];
	DWORD key_color;
	WORD pixel_aspect_ratio[2];
	WORD gamma_value[2];
	DWORD color_correction_offset;	// Number of bytes from the beginning of the file to the color correction table if present
	DWORD postage_stamp_offset;		// Number of bytes from the beginning of the file to the postage stamp image if present
	DWORD scan_line_offset;			// Number of bytes from the beginning of the file to the scan lines table if present
	BYTE attributes_type;			// Specifies the alpha channel
} TGAEXTENSIONAREA;

typedef struct tagTGAFOOTER {
	DWORD extension_offset;	// extension area offset : offset in bytes from the beginning of the file
	DWORD developer_offset;	// developer directory offset : offset in bytes from the beginning of the file
	char signature[18];		// signature string : contains "TRUEVISION-XFILE.\0"
} TGAFOOTER;

#ifdef _WIN32
#pragma pack(pop)
#else
#pragma pack()
#endif

static const char *FI_MSG_ERROR_CORRUPTED = "Image data corrupted";

// ----------------------------------------------------------
// Image type
//
#define TGA_NULL		0	// no image data included
#define TGA_CMAP		1	// uncompressed, color-mapped image
#define TGA_RGB			2	// uncompressed, true-color image
#define TGA_MONO		3	// uncompressed, black-and-white image
#define TGA_RLECMAP		9	// run-length encoded, color-mapped image
#define TGA_RLERGB		10	// run-length encoded, true-color image
#define TGA_RLEMONO		11	// run-length encoded, black-and-white image
#define TGA_CMPCMAP		32	// compressed (Huffman/Delta/RLE) color-mapped image (e.g., VDA/D) - Obsolete
#define TGA_CMPCMAP4	33	// compressed (Huffman/Delta/RLE) color-mapped four pass image (e.g., VDA/D) - Obsolete

// ==========================================================
// Thumbnail functions
// ==========================================================

class TargaThumbnail
{
public:
	TargaThumbnail() : _w(0), _h(0), _depth(0), _data(NULL) { 
	}
	~TargaThumbnail() { 
		if(_data) {
			free(_data); 
		}
	}

	BOOL isNull() const { 
		return (_data == NULL); 
	}
	
	BOOL read(FreeImageIO *io, fi_handle handle, size_t size) {
		io->read_proc(&_w, 1, 1, handle);
		io->read_proc(&_h, 1, 1, handle);
		
		const size_t sizeofData = size - 2;
		_data = (BYTE*)malloc(sizeofData);
		if(_data) {
			return (io->read_proc(_data, 1, (unsigned)sizeofData, handle) == sizeofData);
		}
		return FALSE;
	}
	
	void setDepth(BYTE dp) { 
		_depth = dp;
	}
	
	FIBITMAP* toFIBITMAP();
	
private:
	BYTE _w;
	BYTE _h;
	BYTE _depth;
	BYTE* _data;
};

#ifdef FREEIMAGE_BIGENDIAN
static void 
swapShortPixels(FIBITMAP* dib) {
	if(FreeImage_GetImageType(dib) != FIT_BITMAP) {
		return;
	}
		
	const unsigned Bpp = FreeImage_GetBPP(dib)/8;
	if(Bpp != 2) {
		return;
	}
		
	BYTE* bits = FreeImage_GetBits(dib);
	const unsigned height = FreeImage_GetHeight(dib);
	const unsigned pitch = FreeImage_GetPitch(dib);
	
	BYTE* line = bits;
	for(unsigned y = 0; y < height; y++, line += pitch) {
		for(BYTE* pixel = line; pixel < line + pitch ; pixel += Bpp) {
			SwapShort((WORD*)pixel);
		}
	}
}
#endif // FREEIMAGE_BIGENDIAN

FIBITMAP* TargaThumbnail::toFIBITMAP() {
	if(isNull() || _depth == 0) {
		return NULL;
	}
		
	const unsigned line_size = _depth * _w / 8;
	FIBITMAP* dib = FreeImage_Allocate(_w, _h, _depth);
	if(!dib) {
		return NULL;
	}

	const BYTE* line = _data;
	const BYTE height = _h;
	for (BYTE h = 0; h < height; ++h, line += line_size) {
		BYTE* dst_line = FreeImage_GetScanLine(dib, height - 1 - h);
		memcpy(dst_line, line, line_size);
	}

#ifdef FREEIMAGE_BIGENDIAN
	swapShortPixels(dib);
#endif
	
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
	SwapRedBlue32(dib);
#endif

	return dib;
}
// ==========================================================
// Internal functions
// ==========================================================

/** This class is used when loading RLE compressed images, it implements io cache of fixed size.
	In general RLE compressed images *should* be compressed line by line with line sizes stored in Scan Line Table section.
	In reality, however there are images not obeying the specification, compressing image data continuously across lines,
	making it impossible to load the file cached at every line.
*/
class IOCache
{
public:
	IOCache(FreeImageIO *io, fi_handle handle, size_t size) :
		_ptr(NULL), _begin(NULL), _end(NULL), _size(size), _io(io), _handle(handle)	{
			_begin = (BYTE*)malloc(size);
			if (_begin) {
			_end = _begin + _size;
			_ptr = _end;	// will force refill on first access
		}
	}
	
	~IOCache() {
		if (_begin != NULL) {
			free(_begin);
		}	
	}
		
	BOOL isNull() { return _begin == NULL;}
	
	inline
	BYTE getByte() {
		if (_ptr >= _end) {
			// need refill
			_ptr = _begin;
			_io->read_proc(_ptr, sizeof(BYTE), (unsigned)_size, _handle);	//### EOF - no problem?
		}

		BYTE result = *_ptr;

		_ptr++;

		return result;
	}
	
	inline
	BYTE* getBytes(size_t count /*must be < _size!*/) {
		if (_ptr + count >= _end) {
			
			// need refill

			// 'count' bytes might span two cache bounds,
			// SEEK back to add the remains of the current cache again into the new one

			long read = long(_ptr - _begin);
			long remaining = long(_size - read);

			_io->seek_proc(_handle, -remaining, SEEK_CUR);

			_ptr = _begin;
			_io->read_proc(_ptr, sizeof(BYTE), (unsigned)_size, _handle);	//### EOF - no problem?
		}

		BYTE *result = _ptr;

		_ptr += count;

		return result;
	}

private:
	IOCache& operator=(const IOCache& src); // deleted
	IOCache(const IOCache& other); // deleted



( run in 0.497 second using v1.01-cache-2.11-cpan-62a16548d74 )