#import "bitmap.h"


NXColor
ReadPixel (unsigned char **data,
	int width,
	int height,
	int bps,
	int spp,
	BOOL hasAlpha,
	BOOL isPlanar,
	NXColorSpace colourSpace,
	int x,
	int y)
{
	int bpp, offset, index, maxval, i;
	int sample, samples[5];
	float components[5];
	NXColor colour;
	
	
	/* Number of bits per pixel. */
	bpp = bps * spp;


	/* Calculate the offset (in bits) into the data. */
	offset = (y * width + x) * bpp;
	index = offset >> 3;


	/* Read the samples. */
	maxval = (0x1 << bps) - 1;

	if (isPlanar) {
		for (i=0; i<spp && data[i]; i++)
			samples[i] = (int)(data[i][index] >> ((8-bps) - (offset & 0x7))) & maxval;

	} else {
		for (i=0; i<spp; i++) {
			index = offset >> 3;
			samples[i] = (int)(data[0][index] >> ((8-bps) - (offset & 0x7))) & maxval;
			offset += bps;
		}
	}
	
	
	/* Convert the samples to [0, 1] interval. */
	for (i=0; i<spp; i++)
		components[i] = (float)samples[i] / (float)maxval;
	
	
	/* Build the NXColor object. */
	if (hasAlpha) {
		switch (colourSpace) {
			case NX_OneIsBlackColorSpace:
				colour = NXConvertGrayAlphaToColor(1. - components[0],
					components[1]);
				break;
	
			case NX_OneIsWhiteColorSpace:
				colour = NXConvertGrayAlphaToColor(components[0],
					components[1]);
				break;
	
			case NX_RGBColorSpace:
				colour = NXConvertRGBAToColor(components[0],
					components[1],
					components[2],
					components[3]);
				break;
	
			case NX_CMYKColorSpace:
				colour = NXConvertCMYKAToColor(components[0],
					components[1],
					components[2],
					components[3],
					components[4]);
				break;
	
			default:
				colour = NXConvertGrayAlphaToColor(0., 1.);
		}
	} else {
		switch (colourSpace) {
			case NX_OneIsBlackColorSpace:
				colour = NXConvertGrayToColor(1. - components[0]);
				break;
	
			case NX_OneIsWhiteColorSpace:
				colour = NXConvertGrayToColor(components[0]);
				break;
	
			case NX_RGBColorSpace:
				colour = NXConvertRGBToColor(components[0],
					components[1],
					components[2]);
				break;
	
			case NX_CMYKColorSpace:
				colour = NXConvertCMYKToColor(components[0],
					components[1],
					components[2],
					components[3]);
				break;
	
			default:
				colour = NX_COLORBLACK;
		}
	}
	
	return colour;
}


void
WritePixel (unsigned char **data,
	int width,
	int height,
	int bps,
	int spp,
	BOOL hasAlpha,
	BOOL isPlanar,
	NXColorSpace colourSpace,
	int x,
	int y,
	NXColor colour)
{
	int bpp, offset, index, maxval, i;
	int sample, samples[5];
	float components[5];
	
	
	/* Convert the colour into its individual components. */
	if (hasAlpha) {
		switch (colourSpace) {
			case NX_OneIsBlackColorSpace:
				NXConvertColorToGrayAlpha(colour,
					&components[0],
					&components[1]);
				
				components[0] = 1. - components[0];
				break;
	
			case NX_OneIsWhiteColorSpace:
				NXConvertColorToGrayAlpha(colour,
					&components[0],
					&components[1]);
				break;
	
			case NX_RGBColorSpace:
				NXConvertColorToRGBA(colour,
					&components[0],
					&components[1],
					&components[2],
					&components[3]);
				break;
	
			case NX_CMYKColorSpace:
				 NXConvertColorToCMYKA(colour,
					&components[0],
					&components[1],
					&components[2],
					&components[3],
					&components[4]);
				break;
	
			default:
				return;
		}
	} else {
		switch (colourSpace) {
			case NX_OneIsBlackColorSpace:
				NXConvertColorToGray(colour, &components[0]);
				components[0] = 1. - components[0];
				break;
	
			case NX_OneIsWhiteColorSpace:
				NXConvertColorToGray(colour, &components[0]);
				break;
	
			case NX_RGBColorSpace:
				NXConvertColorToRGB(colour,
					&components[0],
					&components[1],
					&components[2]);
				break;
	
			case NX_CMYKColorSpace:
				 NXConvertColorToCMYK(colour,
					&components[0],
					&components[1],
					&components[2],
					&components[3]);
				break;
	
			default:
				return;
		}
	}
	
	
	/* Convert the colour value into the sample range. */
	maxval = (0x1 << bps) - 1;
	for (i=0; i<spp; i++)
		samples[i] = (int)(maxval * components[i]);

	
	/* Number of bits per pixel. */
	bpp = bps * spp;
	
	/* Calculate the offset (in bits) into the data. */
	offset = (y * width + x) * bpp;
	index = offset >> 3;
	
	if (isPlanar) {
		for (i=0; i<spp && data[i]; i++) {
			sample = samples[i] << ((8-bps) - (offset & 0x7));
			data[i][index] &= ~(maxval << ((8-bps) - (offset & 0x7)));
			data[i][index] |= sample;
		}
	} else {
		for (i=0; i<spp; i++) {
			index = offset >> 3;
			sample = samples[i] << ((8-bps) - (offset & 0x7));
			data[0][index] &= ~(maxval << ((8-bps) - (offset & 0x7)));
			data[0][index] |= sample;
			
			offset += bps;
		}
	}
}


