/*
 * Javascript Image Effects - Core Functions
 * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com
 * This software is free to use for non-commercial purposes. For anything else, please contact the author.
 */

var jsImageFX = {

	effects : {}, 

	doEffects : function(oImg, oCanvasImg, strFilter) 
	{
		var bHasCanvas = false;
		var bHasCanvasImageData = false;
		var bIsIE = !!(window.attachEvent && !window.opera);  // ew..

		var oCanvas = document.createElement("canvas");
		if (oCanvas.getContext) {
			bHasCanvas = true;
			var oCtx = oCanvas.getContext("2d");
			if (oCtx.getImageData) {
				bHasCanvasImageData = true;
			}
		}

		var iWidth = parseInt(oImg.offsetWidth);
		var iHeight = parseInt(oImg.offsetHeight);

		var strFilterName = strFilter;
		var oOptions = {};

		var oArgs = {};
		if (strFilter.indexOf("(") > -1) {
			strFilterName = strFilter.substr(0, strFilter.indexOf("("));
			var aArg = strFilter.match(/\((.*?)\)/);
			if (aArg[1]) {
				aArg = aArg[1].split(";");
				for (var a=0;a<aArg.length;a++) {
					aThisArg = aArg[a].split("=");
					if (aThisArg.length == 2)
						oArgs[aThisArg[0]] = aThisArg[1];
				}
			}
		}

		if (typeof jsImageFX.effects[strFilterName] != "function") {
			return false;
		}

		if (bHasCanvas) {
			oCanvas.width = iWidth;
			oCanvas.height = iHeight;
			oCanvas.style.width = iWidth;
			oCanvas.style.height = iHeight;
	
			oCtx.drawImage(oCanvasImg, 0, 0, iWidth, iHeight);
		}

		var oImage = {
			image : oImg,
			canvas : oCanvas,
			width : iWidth,
			height : iHeight,
			client : {
				hasCanvas : bHasCanvas,
				hasCanvasImageData : bHasCanvasImageData,
				isIE : bIsIE
			},
			useData : true
		}

		var bRes = jsImageFX.effects[strFilterName](oImage, oArgs);

		if (bHasCanvas) {
			if (oImage.useData) {
				if (bHasCanvasImageData) {
					oCanvas.getContext("2d").putImageData(oImage.canvasData, 0, 0);
					// Opera doesn't seem to update the canvas until we draw something on it, lets draw a 0x0 rectangle.
					oCanvas.getContext("2d").fillRect(0,0,0,0);
				}
			}
			
			// copy properties and stuff from the source image
			oCanvas.title = oImg.title;
			oCanvas.alt  = oImg.alt;
			oCanvas.imgsrc = oImg.src;
			oCanvas.className = oImg.className;
			oCanvas.cssText = oImg.cssText;
			oCanvas.id = oImg.id;

			oImg.parentNode.replaceChild(oCanvas, oImg);
		}
	},

	// load the image file
	doImage : function(oImg, strFilter)
	{
		var oCanvasImg = new Image();
		oCanvasImg.src = oImg.src;
		if (oCanvasImg.complete) {
			jsImageFX.doEffects(oImg, oCanvasImg, strFilter);
		} else {
			oCanvasImg.onload = function() {
				jsImageFX.doEffects(oImg, oCanvasImg, strFilter)
			}
		}
	},

	processImages : function() 
	{
		var aImg = document.getElementsByTagName("img");
		var aImages = [];
		for (var i=0;i<aImg.length;i++) {
			aImages[i] = aImg[i];
		}

		for (var i=0;i<aImages.length;i++) {
			if (aImages[i].getAttribute("imagefx")) {
				jsImageFX.doImage(aImages[i], aImages[i].getAttribute("imagefx"));
			}
		}
	}

}


if (window.addEventListener) { 
	window.addEventListener("load", jsImageFX.processImages, false); 
} else if (window.attachEvent) { 
	window.attachEvent("onload", jsImageFX.processImages); 
}

//none
jsImageFX.effects.none = function(oImage)
{
	if (oImage.client.hasCanvas && oImage.client.hasCanvasImageData) {
		var oCtx = oImage.canvas.getContext("2d");
		var oDataSrc = oCtx.getImageData(0, 0, oImage.width, oImage.height);
		var oDataDst = oCtx.getImageData(0, 0, oImage.width, oImage.height);
		var aDataSrc = oDataSrc.data;
		var aDataDst = oDataDst.data;
		oImage.canvasData = oDataDst;

		var h = oImage.height;
		var w = oImage.width;

		var y = h;
		do {
			var iOffsetY = (y-1)*w*4;
			var x = w;
			do {
				var iOffset = iOffsetY + (x-1)*4;
	
				aDataDst[iOffset] = aDataSrc[iOffset];
				aDataDst[iOffset+1] = aDataSrc[iOffset+1];
				aDataDst[iOffset+2] = aDataSrc[iOffset+2];
				aDataDst[iOffset+3] = aDataSrc[iOffset+3];
	
			} while (--x);
		} while (--y);
		return true;
	}
}



//sharpen

jsImageFX.effects.sharpen = function(oImage)
{
	if (oImage.client.hasCanvas && oImage.client.hasCanvasImageData) {

		var oCtx = oImage.canvas.getContext("2d");
		var oDataSrc = oCtx.getImageData(0, 0, oImage.width, oImage.height);
		var oDataDst = oCtx.getImageData(0, 0, oImage.width, oImage.height);
		var aDataSrc = oDataSrc.data;
		var aDataDst = oDataDst.data;
		oImage.canvasData = oDataDst;

		var h = oImage.height;
		var w = oImage.width;
		var y = h;

		var aKernel = [
			[0, 	-2, 	0],
			[-2, 	15, 	-2],
			[0, 	-2, 	0]
		];

		var fWeight = 0;
		for (var i=0;i<3;i++) {
			for (var j=0;j<3;j++) {
				fWeight += aKernel[i][j];
			}
		}

		do {
			var iOffsetY = (y-1)*w*4;

			var iOffsetYPrev = (y-2)*w*4;
			var iOffsetYNext = (y)*w*4;

			var x = w;
			do {
				if (x < w && y < h) {

					var iOffset = iOffsetY + (x-1)*4;
					var iOffsetPrev = iOffsetYPrev + (x-1)*4;
					var iOffsetNext = iOffsetYNext + (x-1)*4;
	
					var iR = (- aDataSrc[iOffsetPrev]*2
						- aDataSrc[iOffset-4]*2
						+ aDataSrc[iOffset] * 15
						- aDataSrc[iOffset+4]*2
						- aDataSrc[iOffsetNext]*2) 
						/ fWeight;
	
					var iG = (- aDataSrc[iOffsetPrev+1]*2
						- aDataSrc[iOffset-3]*2
						+ aDataSrc[iOffset+1] * 15
						- aDataSrc[iOffset+5]*2
						- aDataSrc[iOffsetNext+1]*2)
						/ fWeight;
	
					var iB = (- aDataSrc[iOffsetPrev+2]*2
						- aDataSrc[iOffset-2]*2
						+ aDataSrc[iOffset+2] * 15
						- aDataSrc[iOffset+6]*2
						- aDataSrc[iOffsetNext+2]*2)
						/ fWeight;

					if (iR < 0 ) iR = 0;
					if (iG < 0 ) iG = 0;
					if (iB < 0 ) iB = 0;

					if (iR > 255 ) iR = 255;
					if (iG > 255 ) iG = 255;
					if (iB > 255 ) iB = 255;

					aDataDst[iOffset] = iR;
					aDataDst[iOffset+1] = iG;
					aDataDst[iOffset+2] = iB;
					aDataDst[iOffset+3] = aDataSrc[iOffset+3];
				}

			} while (--x);
		} while (--y);
		return true;

	} else if (oImage.client.isIE) {
		// no sharpen filter for IE
	}
}


//brightness

jsImageFX.effects.brightness = function(oImage, oArgs)
{
	if (oImage.client.hasCanvas && oImage.client.hasCanvasImageData) {

		var oCtx = oImage.canvas.getContext("2d");
		var oDataSrc = oCtx.getImageData(0, 0, oImage.width, oImage.height);
		var oDataDst = oCtx.getImageData(0, 0, oImage.width, oImage.height);
		var aDataSrc = oDataSrc.data;
		var aDataDst = oDataDst.data;
		oImage.canvasData = oDataDst;

		var h = oImage.height;
		var w = oImage.width;

		var iBrightness = 0;
		var iContrast = 0;

		if (oArgs) {
			if (typeof oArgs.brightness != "undefined")
				iBrightness = parseInt(oArgs.brightness,10);
			if (typeof oArgs.contrast != "undefined")
				fContrast = parseFloat(oArgs.contrast);
		}


		var y = h;
		do {
			var iOffsetY = (y-1)*w*4;

			var iOffsetYPrev = (y-2)*w*4;
			var iOffsetYNext = (y)*w*4;

			var x = w;
			do {
				if (x < w && y < h) {

					var iOffset = iOffsetY + (x-1)*4;
					var iOffsetPrev = iOffsetYPrev + (x-1)*4;
					var iOffsetNext = iOffsetYNext + (x-1)*4;
	
					var iR = 0;
					var iG = 0;
					var iB = 0;
	
					var iR = aDataSrc[iOffset] + iBrightness;
					var iG = aDataSrc[iOffset+1] + iBrightness;
					var iB = aDataSrc[iOffset+2] + iBrightness;

					if (iR < 0) iR = 0; if (iR > 255) iR = 255;
					if (iG < 0) iG = 0; if (iG > 255) iG = 255;
					if (iB < 0) iB = 0; if (iB > 255) iB = 255;

					if (iR > 127) {
						iR += ((iR + 1) - 128) * fContrast;
						if (iR < 128) iR = 128;
					} else if (iR < 127) {
						iR -= (iR + 1) * fContrast;
						if (iR > 127) iR = 127;
					}

					if (iG > 127) {
						iG += ((iG + 1) - 128) * fContrast;
						if (iG < 128) iG = 128;
					} else if (iG < 127) {
						iG -= (iG + 1) * fContrast;
						if (iG > 127) iG = 127;
					}

					if (iB > 127) {
						iB += ((iB + 1) - 128) * fContrast;
						if (iB < 128) iB = 128;
					} else if (iB < 127) {
						iB -= (iB + 1) * fContrast;
						if (iB > 127) iB = 127;
					}

					if (iR < 0) iR = 0; if (iR > 255) iR = 255;
					if (iG < 0) iG = 0; if (iG > 255) iG = 255;
					if (iB < 0) iB = 0; if (iB > 255) iB = 255;

					aDataDst[iOffset] = iR;
					aDataDst[iOffset+1] = iG;
					aDataDst[iOffset+2] = iB;
					aDataDst[iOffset+3] = aDataSrc[iOffset+3];
				}

			} while (--x);
		} while (--y);
		return true;

	} else if (oImage.client.isIE) {
		// none for IE!
	}
}

//sepia
jsImageFX.effects.sepia = function(oImage)
{
	if (oImage.client.hasCanvas && oImage.client.hasCanvasImageData) {

		var oCtx = oImage.canvas.getContext("2d");
		var oDataSrc = oCtx.getImageData(0, 0, oImage.width, oImage.height);
		var oDataDst = oCtx.getImageData(0, 0, oImage.width, oImage.height);
		var aDataSrc = oDataSrc.data;
		var aDataDst = oDataDst.data;
		oImage.canvasData = oDataDst;

		var h = oImage.height;
		var w = oImage.width;
		var y = h;
		do {
			var iOffsetY = (y-1)*w*4;
			var x = w;
			do {
				var iOffset = iOffsetY + (x-1)*4;

				var iOldR = aDataSrc[iOffset];
				var iOldG = aDataSrc[iOffset+1];
				var iOldB = aDataSrc[iOffset+2];

				var iR = (iOldR * 0.393 + iOldG * 0.769 + iOldB * 0.189);
				var iG = (iOldR * 0.349 + iOldG * 0.686 + iOldB * 0.168);
				var iB = (iOldR * 0.272 + iOldG * 0.534 + iOldB * 0.131);

				if (iR < 0) iR = 0; if (iR > 255) iR = 255;
				if (iG < 0) iG = 0; if (iG > 255) iG = 255;
				if (iB < 0) iB = 0; if (iB > 255) iB = 255;

				aDataDst[iOffset] = iR;
				aDataDst[iOffset+1] = iG;
				aDataDst[iOffset+2] = iB;
				aDataDst[iOffset+3] = aDataSrc[iOffset+3];
	
			} while (--x);
		} while (--y);
		return true;

	} else if (oImage.client.isIE) {
		// nothing for IE!
	}
}


//lighten
jsImageFX.effects.lighten = function(oImage, oArgs)
{
	var fAmount = 0;

	if (oArgs) {
		if (typeof oArgs.amount != "undefined")
			fAmount = parseFloat(oArgs.amount);
	}

	if (oImage.client.hasCanvas && oImage.client.hasCanvasImageData) {
		var oCtx = oImage.canvas.getContext("2d");
		var oDataSrc = oCtx.getImageData(0, 0, oImage.width, oImage.height);
		var oDataDst = oCtx.getImageData(0, 0, oImage.width, oImage.height);
		var aDataSrc = oDataSrc.data;
		var aDataDst = oDataDst.data;
		oImage.canvasData = oDataDst;

		var h = oImage.height;
		var w = oImage.width;
		var y = h;
		do {
			var iOffsetY = (y-1)*w*4;
			var x = w;
			do {
				var iOffset = iOffsetY + (x-1)*4;
	
				var iR = aDataSrc[iOffset];
				var iG = aDataSrc[iOffset+1];
				var iB = aDataSrc[iOffset+2];

				if (fAmount < 0 ||true) {
					iR = iR + iR*fAmount;
					iG = iG + iG*fAmount;
					iB = iB + iB*fAmount;
				} else if (fAmount > 0) {
					iR = iR + (255-iR)*fAmount;
					iG = iG + (255-iG)*fAmount;
					iB = iB + (255-iB)*fAmount;
				}

				if (iR < 0 ) iR = 0;
				if (iG < 0 ) iG = 0;
				if (iB < 0 ) iB = 0;
				if (iR > 255 ) iR = 255;
				if (iG > 255 ) iG = 255;
				if (iB > 255 ) iB = 255;

				aDataDst[iOffset] = iR;
				aDataDst[iOffset+1] = iG;
				aDataDst[iOffset+2] = iB;
				aDataDst[iOffset+3] = aDataSrc[iOffset+3];
	
			} while (--x);
		} while (--y);
		return true;

	} else if (oImage.client.isIE) {
		if (fAmount < 0) {
			oImage.image.style.filter += " light()";
			oImage.image.filters[oImage.image.filters.length-1].addAmbient(
				255,255,255,
				100 * -fAmount
			);
		} else if (fAmount > 0) {
			oImage.image.style.filter += " light()";
			oImage.image.filters[oImage.image.filters.length-1].addAmbient(
				255,255,255,
				100
			);
			oImage.image.filters[oImage.image.filters.length-1].addAmbient(
				255,255,255,
				100 * fAmount
			);
		}
		return true;
	}
}

