//
// PImageNativeLoaderXpm.cc for pekwm
// Copyright (C) 2005 Claes Nasten <pekdon{@}pekdon{.}net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//

#include "../config.h"

#ifdef HAVE_IMAGE_XPM

#include "PImageNativeLoaderXpm.hh"

#include <iostream>

using std::cerr;
using std::endl;
using std::string;

const uint PImageNativeLoaderXpm::CHANNELS = 4;
const uint PImageNativeLoaderXpm::ALPHA_SOLID = 255;
const uint PImageNativeLoaderXpm::ALPHA_TRANSPARENT = 0;
const char *PImageNativeLoaderXpm::COLOR_DEFAULT = "#000000";

//! @brief PImageNativeLoaderXpm constructor.
PImageNativeLoaderXpm::PImageNativeLoaderXpm(void) : PImageNativeLoader("XPM")
{
}

//! @brief PImageNativeLoaderXpm destructor.
PImageNativeLoaderXpm::~PImageNativeLoaderXpm(void)
{
}

//! @brief Loads file into data.
//! @param file File to load data from.
//! @param width Set to the width of image.
//! @param height Set to the height of image.
//! @param alpha Set to wheter image has alpha channel.
//! @return Pointer to data on success, else NULL.
uchar*
PImageNativeLoaderXpm::load(const std::string &file, uint &width, uint &height,
														bool &alpha)
{
	XpmImage xpm_image;
	XpmInfo xpm_info;

	// Read XPM to XpmImage format.
	if (XpmReadFileToXpmImage((char*) file.c_str(),
														&xpm_image, &xpm_info) != Success) {
		cerr << " *** WARNING: " << file << " not a valid XPM file!" << endl;
		return NULL;
	}

	if (!xpm_image.ncolors || !xpm_image.data
			|| !xpm_image.width || !xpm_image.height) {
		cerr << " *** WARNING: " << file << " invalid file information!" << endl;
		return NULL;
	}

	// Build XpmColor -> RGBA Table.
	uchar *xpm_to_rgba;
	xpm_to_rgba = createXpmToRgbaTable(&xpm_image);

	width = xpm_image.width;
	height = xpm_image.height;

	// Allocate data.
	uchar *data, *dest;
	uint *src;

	data = new uchar[width * height * CHANNELS];
	dest = data;
	src = xpm_image.data;

	// Fill data.
	for (uint y = 0; y < height; ++y) {
		for (uint x = 0; x < width; ++x) {
			*dest++ = xpm_to_rgba[*src * CHANNELS]; // R
			*dest++ = xpm_to_rgba[*src * CHANNELS + 1]; // G
			*dest++ = xpm_to_rgba[*src * CHANNELS + 2]; // B
			*dest++ = xpm_to_rgba[*src * CHANNELS + 3]; // A

			*src++;
		}
	}

	// Cleanup.
	delete [] xpm_to_rgba;

	XpmFreeXpmImage(&xpm_image);
	XpmFreeXpmInfo(&xpm_info);

	alpha = true;

	return data;
}

//! @brief Creates an color number to RGBA conversion table.
//! @param xpm_image Pointer to XpmImage.
//! @return Pointer to color number to RGBA conversion table.
uchar*
PImageNativeLoaderXpm::createXpmToRgbaTable(XpmImage *xpm_image)
{
	uint c_tmp; // Temporary color value.
	char c_buf[3] = { '\0', '\0', '\0' }; // Temporary hex color string.
	const char *color;
	uchar *xpm_to_rgba, *dest;

	xpm_to_rgba = new uchar[xpm_image->ncolors * CHANNELS];
	dest = xpm_to_rgba;
	for (uint i = 0; i < xpm_image->ncolors; ++i) {
		if (xpm_image->colorTable[i].c_color)
			color = xpm_image->colorTable[i].c_color;
		else if (xpm_image->colorTable[i].g_color)
			color = xpm_image->colorTable[i].g_color;
		else if (xpm_image->colorTable[i].g4_color)
			color = xpm_image->colorTable[i].g4_color;
		else if (xpm_image->colorTable[i].m_color)
			color = xpm_image->colorTable[i].m_color;
		else
			color = COLOR_DEFAULT;

		// Color in format #RRGGBB.
		if (color && (strlen(color) == 7)) {
			for (uint j = 0; j < 3; ++j) {
				c_buf[0] = color[j * 2 + 1];
				c_buf[1] = color[j * 2 + 2];
				if (sscanf(c_buf, "%x", &c_tmp) == 1) {
					*dest++ = c_tmp;
				} else {
					*dest++ = 0;
					cerr << " *** WARNING: " << c_buf << " invalid color value!" << endl;
				}
			}
			*dest++ = ALPHA_SOLID;

			// Invalid format or None, set it transparent
		} else {
			*dest++ = 0; // R
			*dest++ = 0; // G
			*dest++ = 0; // B
			*dest++ = ALPHA_TRANSPARENT; // A
		}
	}

	return xpm_to_rgba;
}

#endif // HAVE_IMAGE_XPM


syntax highlighted by Code2HTML, v. 0.9.1