#import <appkit/NXImage.h>
#import <appkit/NXBitmapImageRep.h>
#import "SilkScreen.h"
#import "bitmap.h"



@implementation SilkScreen


- filter:bitmap intoImage:smartImage
{
	NXBitmapImageRep *filtered;
	int width, height, bps, spp, x, y;
	BOOL hasAlpha, isPlanar;
	NXColorSpace colourSpace;
	NXColor source, work, dest;
	unsigned char *data[5], *output[5];
	float sh, ss, sb, sa, dh, ds, db, da;

	/* Read the bitmap information. */
	width = [bitmap pixelsWide];
	height = [bitmap pixelsHigh];
	bps = [bitmap bitsPerSample];
	spp = [bitmap samplesPerPixel];
	hasAlpha = [bitmap hasAlpha];
	isPlanar = [bitmap isPlanar];
	colourSpace = [bitmap colorSpace];
	[bitmap getDataPlanes:data];

	if (!width || !height)
		return nil;


	/* Create a working copy of the bitmap. */
	filtered = [bitmap copy];
	[filtered getDataPlanes:output];


	/* Destination colour. */
	source = [sourceColourWell color];
	NXConvertColorToHSBA(source, &sh, &ss, &sb, &sa);
	dest = [destColourWell color];
	NXConvertColorToHSBA(dest, &dh, &ds, &db, &da);

	
	for (y=0; y<height; y++) {
		for (x=0; x<width; x++) {
			work = ReadPixel(data,
				width,
				height,
				bps,
				spp,
				hasAlpha,
				isPlanar,
				colourSpace,
				x,
				y);
			
			if ([self compareColour:work]) {
				if ([interpolateBox state]) {
					float h, s, b, a;
					
					NXConvertColorToHSBA(work, &h, &s, &b, &a);
					h = dh + (h - sh);
					s = ds + (s - ss);
					b = db + (b - sb);
					a = da + (a - sa);

					if (h < 0.) h += 1.;
					if (h > 1.) h -= 1.;
					if (s < 0.) s = 0.;
					if (s > 1.) s = 1.;
					if (b < 0.) b = 0.;
					if (b > 1.) b = 1.;

					work = NXConvertHSBAToColor(h, s, b, a);
				} else
					work = dest;

				WritePixel(output,
					width,
					height,
					bps,
					spp,
					hasAlpha,
					isPlanar,
					colourSpace,
					x,
					y,
					work);
			}
		}
	}

	return filtered;
}


- (BOOL) compareColour:(NXColor)colour
{
	float sr, sg, sb, sa;
	float r, g, b, a;
	float delta, tol;
	float dr, dg, db, da;


	/* Convert the colours to their components. */
	NXConvertColorToRGBA(colour, &r, &g, &b, &a);
	NXConvertColorToRGBA([sourceColourWell color], &sr, &sg, &sb, &sa);


	/* Calculate the difference between each component. */
	dr = r - sr;
	dg = g - sg;
	db = b - sb;
	da = ((a >= 0.) && (sa >= 0.)) ? a - sa : 0.;


	/* Euclidean distance based on the axis chosen. */
	delta = 0.;
	if ([RBox state]) delta += dr * dr;
	if ([GBox state]) delta += dg * dg;
	if ([BBox state]) delta += db * db;
	if ([ABox state]) delta += da * da;
	if (0. == delta)
		return YES;

	
	/* Compare it to the tolerance. */
	tol = [toleranceSlider floatValue] / 100.;
	tol *= tol;
	return delta <= tol ? YES : NO;
}

@end
