/**
	 * Generates a captcha image
	 *
	 * @param string $id
	 * @param string $function
	 */
	public function captchaImage( $id, $function )
	{
		global $_PLUGINS;

		if ( $id ) {
			$absPath						=	$_PLUGINS->getPluginPath( $this->getPluginId() );
			$captcha						=	cbantispamCaptcha::getInstance( $id, ( $function != 'image' ? $function : null ) );
			$code							=	$captcha->getCaptchaCode();

			if ( $this->input( 'ver', null, GetterInterface::STRING ) ) {
				$code						=	$captcha->generateCode();
			}

			$height							=	(int) $this->params->get( 'captcha_internal_height', 40 );

			if ( ! $height ) {
				$height						=	40;
			}

			$bgColor						=	$this->params->get( 'captcha_internal_bg_color', '255,255,255' );

			if ( ! $bgColor ) {
				$bgColor					=	'255,255,255';
			}

			$bgColors						=	explode( ',', $bgColor );
			$imgBgColors					=	array();

			if ( $bgColors ) for( $i = 0; $i < 3; $i++ ) {
				if ( isset( $bgColors[$i] ) ) {
					$color					=	(int) trim( $bgColors[$i] );
					$imgBgColors[]			=	( $color > 255 ? 255 : ( $color < 0 ? 0 : $color ) );
				}
			}

			if ( ! $imgBgColors ) {
				$imgBgColors				=	array( 255, 255, 255 );
			} elseif ( count( $imgBgColors ) < 3 ) {
				if ( count( $imgBgColors ) < 2 ) {
					$imgBgColors[]			=	255;
					$imgBgColors[]			=	255;
				} else {
					$imgBgColors[]			=	255;
				}
			}

			$txtColor						=	$this->params->get( 'captcha_internal_txt_color', '20,40,100' );

			if ( ! $txtColor ) {
				$txtColor					=	'20,40,100';
			}

			$txtColors						=	explode( ',', $txtColor );
			$imgTxtColors					=	array();

			if ( $txtColors ) for( $i = 0; $i < 3; $i++ ) {
				if ( isset( $txtColors[$i] ) ) {
					$color					=	(int) trim( $txtColors[$i] );
					$imgTxtColors[]			=	( $color > 255 ? 255 : ( $color < 0 ? 0 : $color ) );
				}
			}

			if ( ! $imgTxtColors ) {
				$imgTxtColors				=	array( 20, 40, 100 );
			} elseif ( count( $imgTxtColors ) < 3 ) {
				if ( count( $imgTxtColors ) < 2 ) {
					$imgTxtColors[]			=	40;
					$imgTxtColors[]			=	100;
				} else {
					$imgTxtColors[]			=	100;
				}
			}

			$nBgColor						=	$this->params->get( 'captcha_internal_bg_noise_color', '100,120,180' );

			if ( ! $nBgColor ) {
				$nBgColor					=	'100,120,180';
			}

			$nBgColors						=	explode( ',', $nBgColor );
			$imgNoiseBgColors				=	array();

			if ( $nBgColors ) for( $i = 0; $i < 3; $i++ ) {
				if ( isset( $nBgColors[$i] ) ) {
					$color					=	(int) trim( $nBgColors[$i] );
					$imgNoiseBgColors[]		=	( $color > 255 ? 255 : ( $color < 0 ? 0 : $color ) );
				}
			}

			if ( ! $imgNoiseBgColors ) {
				$imgNoiseBgColors			=	array( 100, 120, 180 );
			} elseif ( count( $imgNoiseBgColors ) < 3 ) {
				if ( count( $imgNoiseBgColors ) < 2 ) {
					$imgNoiseBgColors[]		=	120;
					$imgNoiseBgColors[]		=	180;
				} else {
					$imgNoiseBgColors[]		=	180;
				}
			}

			$nFgColor						=	$this->params->get( 'captcha_internal_fg_noise_color', '100,120,120' );

			if ( ! $nFgColor ) {
				$nFgColor					=	'100,120,120';
			}

			$nFgColors						=	explode( ',', $nFgColor );
			$imgNoiseFgColors				=	array();

			if ( $nFgColors ) for( $i = 0; $i < 3; $i++ ) {
				if ( isset( $nFgColors[$i] ) ) {
					$color					=	(int) trim( $nFgColors[$i] );
					$imgNoiseFgColors[]		=	( $color > 255 ? 255 : ( $color < 0 ? 0 : $color ) );
				}
			}

			if ( ! $imgNoiseFgColors ) {
				$imgNoiseFgColors			=	array( 100, 120, 120 );
			} elseif ( count( $imgNoiseFgColors ) < 3 ) {
				if ( count( $imgNoiseFgColors ) < 2 ) {
					$imgNoiseFgColors[]		=	120;
					$imgNoiseFgColors[]		=	120;
				} else {
					$imgNoiseFgColors[]		=	120;
				}
			}

			$font							=	$this->params->get( 'captcha_internal_font', 'monofont.ttf' );

			if ( ! $font ) {
				$font						=	'monofont.ttf';
			}

			if ( ! file_exists( $absPath . '/fonts/' . $font ) ) {
				$imgFont					=	$absPath . '/fonts/monofont.ttf';
			} else {
				$imgFont					=	$absPath . '/fonts/' . $font;
			}

			if ( ! file_exists( $imgFont ) ) {
				exit( CBTxt::T( 'failed to locate "[file]" font file', array( '[file]' => $imgFont ) ) );
			}

			$fontSize						=	( $height * 0.75 );
			$textBox						=	imagettfbbox( $fontSize, 0, $imgFont, $code );

			if ( $textBox === false ) {
				exit( CBTxt::T( 'imagettfbbox failed to establish image size' ) );
			}

			$width							=	( $textBox[4] + 20 );
			$image							=	imagecreate( $width, $height );

			if ( $image === false ) {
				exit( CBTxt::T( 'imagecreate failed to create new image' ) );
			}

			$charRotation					=	(int) $this->params->get( 'captcha_internal_rotation', 13 );

			if ( $charRotation < 0 ) {
				$charRotation				=	0;
			}

			$charOffset						=	(int) $this->params->get( 'captcha_internal_offset', 3 );

			if ( $charOffset < 0 ) {
				$charOffset					=	0;
			}

			$colorRange						=	(int) $this->params->get( 'captcha_internal_color_range', 2 );

			if ( $colorRange < 0 ) {
				$colorRange					=	0;
			}

			if ( $colorRange ) {
				$bgColorR					=	mt_rand( ( ( $imgBgColors[0] - $colorRange ) < 0 ? 0 : ( $imgBgColors[0] - $colorRange ) ), ( ( $imgBgColors[0] + $colorRange ) > 255 ? 255 : ( $imgBgColors[0] + $colorRange ) ) );
				$bgColorG					=	mt_rand( ( ( $imgBgColors[1] - $colorRange ) < 0 ? 0 : ( $imgBgColors[1] - $colorRange ) ), ( ( $imgBgColors[1] + $colorRange ) > 255 ? 255 : ( $imgBgColors[1] + $colorRange ) ) );
				$bgColorB					=	mt_rand( ( ( $imgBgColors[2] - $colorRange ) < 0 ? 0 : ( $imgBgColors[2] - $colorRange ) ), ( ( $imgBgColors[2] + $colorRange ) > 255 ? 255 : ( $imgBgColors[2] + $colorRange ) ) );

				if ( imagecolorallocate( $image, $bgColorR, $bgColorG, $bgColorB ) === false ) {
					exit( CBTxt::T( 'CAPTCHA_IMAGE_BG_COLOR_FAILED', 'imagecolorallocate failed to set BG colors [r], [g], [b]', array( '[r]' => $bgColorR, '[g]' => $bgColorG, '[b]' => $bgColorB ) ) );
				}

				$textColorR					=	mt_rand( ( ( $imgTxtColors[0] - $colorRange ) < 0 ? 0 : ( $imgTxtColors[0] - $colorRange ) ), ( ( $imgTxtColors[0] + $colorRange ) > 255 ? 255 : ( $imgTxtColors[0] + $colorRange ) ) );
				$textColorG					=	mt_rand( ( ( $imgTxtColors[1] - $colorRange ) < 0 ? 0 : ( $imgTxtColors[1] - $colorRange ) ), ( ( $imgTxtColors[1] + $colorRange ) > 255 ? 255 : ( $imgTxtColors[1] + $colorRange ) ) );
				$textColorB					=	mt_rand( ( ( $imgTxtColors[2] - $colorRange ) < 0 ? 0 : ( $imgTxtColors[2] - $colorRange ) ), ( ( $imgTxtColors[2] + $colorRange ) > 255 ? 255 : ( $imgTxtColors[2] + $colorRange ) ) );

				$textColor					=	imagecolorallocate( $image, $textColorR, $textColorG, $textColorB );

				if ( $textColor === false ) {
					exit( CBTxt::T( 'CAPTCHA_IMAGE_TEXT_COLOR_FAILED', 'imagecolorallocate failed to set text colors [r], [g], [b]', array( '[r]' => $textColorR, '[g]' => $textColorG, '[b]' => $textColorB ) ) );
				}

				$noiseBgColorR				=	mt_rand( ( ( $imgNoiseBgColors[0] - $colorRange ) < 0 ? 0 : ( $imgNoiseBgColors[0] - $colorRange ) ), ( ( $imgNoiseBgColors[0] + $colorRange ) > 255 ? 255 : ( $imgNoiseBgColors[0] + $colorRange ) ) );
				$noiseBgColorG				=	mt_rand( ( ( $imgNoiseBgColors[1] - $colorRange ) < 0 ? 0 : ( $imgNoiseBgColors[1] - $colorRange ) ), ( ( $imgNoiseBgColors[1] + $colorRange ) > 255 ? 255 : ( $imgNoiseBgColors[1] + $colorRange ) ) );
				$noiseBgColorB				=	mt_rand( ( ( $imgNoiseBgColors[2] - $colorRange ) < 0 ? 0 : ( $imgNoiseBgColors[2] - $colorRange ) ), ( ( $imgNoiseBgColors[2] + $colorRange ) > 255 ? 255 : ( $imgNoiseBgColors[2] + $colorRange ) ) );

				$noiseBgColor				=	imagecolorallocate( $image, $noiseBgColorR, $noiseBgColorG, $noiseBgColorB );

				if ( $noiseBgColor === false ) {
					exit( CBTxt::T( 'CAPTCHA_IMAGE_BG_NOISE_COLOR_FAILED', 'imagecolorallocate failed to set noise BG colors [r], [g], [b]', array( '[r]' => $noiseBgColorR, '[g]' => $noiseBgColorG, '[b]' => $noiseBgColorB ) ) );
				}

				$noiseFgColorR				=	mt_rand( ( ( $imgNoiseFgColors[0] - $colorRange ) < 0 ? 0 : ( $imgNoiseFgColors[0] - $colorRange ) ), ( ( $imgNoiseFgColors[0] + $colorRange ) > 255 ? 255 : ( $imgNoiseFgColors[0] + $colorRange ) ) );
				$noiseFgColorG				=	mt_rand( ( ( $imgNoiseFgColors[1] - $colorRange ) < 0 ? 0 : ( $imgNoiseFgColors[1] - $colorRange ) ), ( ( $imgNoiseFgColors[1] + $colorRange ) > 255 ? 255 : ( $imgNoiseFgColors[1] + $colorRange ) ) );
				$noiseFgColorB				=	mt_rand( ( ( $imgNoiseFgColors[2] - $colorRange ) < 0 ? 0 : ( $imgNoiseFgColors[2] - $colorRange ) ), ( ( $imgNoiseFgColors[2] + $colorRange ) > 255 ? 255 : ( $imgNoiseFgColors[2] + $colorRange ) ) );

				$noiseFgColor				=	imagecolorallocate( $image, $noiseFgColorR, $noiseFgColorG, $noiseFgColorB );

				if ( $noiseFgColor === false ) {
					exit( CBTxt::T( 'CAPTCHA_IMAGE_FG_NOISE_COLOR_FAILED', 'imagecolorallocate failed to set noise FG colors [r], [g], [b]', array( '[r]' => $noiseFgColorR, '[g]' => $noiseFgColorG, '[b]' => $noiseFgColorB ) ) );
				}
			} else {
				if ( imagecolorallocate( $image, $imgBgColors[0], $imgBgColors[1], $imgBgColors[2] ) === false ) {
					exit( CBTxt::T( 'CAPTCHA_IMAGE_BG_COLOR_FAILED', 'imagecolorallocate failed to set BG colors [r], [g], [b]', array( '[r]' => $imgBgColors[0], '[g]' => $imgBgColors[1], '[b]' => $imgBgColors[2] ) ) );
				}

				$textColor					=	imagecolorallocate( $image, $imgTxtColors[0], $imgTxtColors[1], $imgTxtColors[2] );

				if ( $textColor === false ) {
					exit( CBTxt::T( 'CAPTCHA_IMAGE_TEXT_COLOR_FAILED', 'imagecolorallocate failed to set text colors [r], [g], [b]', array( '[r]' => $imgTxtColors[0], '[g]' => $imgTxtColors[1], '[b]' => $imgTxtColors[2] ) ) );
				}

				$noiseBgColor				=	imagecolorallocate( $image, $imgNoiseBgColors[0], $imgNoiseBgColors[1], $imgNoiseBgColors[2] );

				if ( $noiseBgColor === false ) {
					exit( CBTxt::T( 'CAPTCHA_IMAGE_BG_NOISE_COLOR_FAILED', 'imagecolorallocate failed to set noise BG colors [r], [g], [b]', array( '[r]' => $imgNoiseBgColors[0], '[g]' => $imgNoiseBgColors[1], '[b]' => $imgNoiseBgColors[2] ) ) );
				}

				$noiseFgColor				=	imagecolorallocate( $image, $imgNoiseFgColors[0], $imgNoiseFgColors[1], $imgNoiseFgColors[2] );

				if ( $noiseFgColor === false ) {
					exit( CBTxt::T( 'CAPTCHA_IMAGE_FG_NOISE_COLOR_FAILED', 'imagecolorallocate failed to set noise FG colors [r], [g], [b]', array( '[r]' => $imgNoiseFgColors[0], '[g]' => $imgNoiseFgColors[1], '[b]' => $imgNoiseFgColors[2] ) ) );
				}
			}

			if ( $this->params->get( 'captcha_internal_bg_noise', 1 ) ) {
				for ( $i = 0; $i < ( ( $width * $height ) / 3 ); $i++ ) {
					if ( imagefilledellipse( $image, mt_rand( 0, $width ), mt_rand( 0, $height ), 1, 1, $noiseBgColor ) === false ) {
						exit( CBTxt::T( 'imagefilledellipse failed to add BG noise to the image' ) );
					}
				}

				for( $i = 1; ( $i < ( $width / 10 ) ); $i++ ) {
					if ( imageline( $image, ( ( $i * 10 ) - mt_rand( -20, 20 ) ), 0, ( ( $i * 10 ) + mt_rand( -20, 20 ) ), $height, $noiseBgColor ) === false ) {
						exit( CBTxt::T( 'imageline failed to add first pass BG noise to the image' ) );
					}
				}

				for( $i = 1; ( $i < ( $height / 10 ) ); $i++ ) {
					if ( imageline( $image, 0, ( ( $i * 10 ) - mt_rand( -20, 20 ) ), $width, ( ( $i * 10 ) + mt_rand( -20, 20 ) ), $noiseBgColor ) === false ) {
						exit( CBTxt::T( 'imageline failed to add second pass BG noise to the image' ) );
					}
				}
			}

			$x								=	( ( $width - $textBox[4] ) / 2 );
			$y								=	( ( $height - $textBox[5] ) / 2 );
			$codeSplit						=	cbantispamClass::UTF8_str_split( $code );
			$i								=	0;

			if ( $codeSplit ) foreach ( $codeSplit as $c ) {
				$result						=	imagettftext( $image, $fontSize, mt_rand( -$charRotation, $charRotation ), ( $x + $i ), ( $y + mt_rand( -$charOffset, $charOffset ) ), $textColor, $imgFont, $c );

				if ( ! $result ) {
					exit( CBTxt::T( 'CAPTCHA_IMAGE_TEXT_FAILED', 'imagettftext failed to add "[text]" to the image', array( '[text]' => $c ) ) );
				}

				$i							+=	( $textBox[4] / count( $codeSplit ) );
			}

			if ( $this->params->get( 'captcha_internal_fg_noise', 1 ) ) for ( $i = 0; $i < 3; $i++ ) {
				if ( imageline( $image, mt_rand( 0, $width ), mt_rand( 0, $height ), mt_rand( 0, $width ), mt_rand( 0, $height ), $noiseFgColor ) === false ) {
					exit( CBTxt::T( 'imageline failed to add FG noise to the image' ) );
				}
			}

			header( 'Expires: Mon, 26 Jul 1997 05:00:00 GMT' );
			header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
			header( 'Cache-Control: no-store, no-cache, must-revalidate' );
			header( 'Cache-Control: post-check=0, pre-check=0', false );
			header( 'Pragma: no-cache' );

			switch ( $this->params->get( 'captcha_internal_format', 'jpeg' ) ) {
				case 'gif':
					header( 'Content-Type: image/gif; charset=utf-8' );

					if ( imagegif( $image ) === false ) {
						exit( CBTxt::T( 'imagegif failed to generate image' ) );
					}
					break;
				case 'png':
					header( 'Content-Type: image/png; charset=utf-8' );

					if ( imagepng( $image, null, 0 ) === false ) {
						exit( CBTxt::T( 'imagepng failed to generate image' ) );
					}
					break;
				case 'jpeg':
				default:
					header( 'Content-Type: image/jpeg; charset=utf-8' );

					if ( imagejpeg( $image, null, 100 ) === false ) {
						exit( CBTxt::T( 'imagejpeg failed to generate image' ) );
					}
					break;
			}

			if ( imagedestroy( $image ) === false ) {
				exit( CBTxt::T( 'imagedestroy failed to destroy the image' ) );
			}

			exit();
		}
	}