/*
* 补全外围空白像素点
*/
static private function _addOutPx($font, $px = 0) {
$maxRow = 0;
$x0 = 0;//x轴的相对0点,因为使用公式产生的数组有负数下标,需要得到绝对0点
foreach($font as $row) {//得到最长行
$x0 = min($x0, key($row));
end($row);//移到最后一个
$maxRow = max($maxRow, key($row));
}
$maxRow = $maxRow - $x0 + 1;
foreach ($font as $key => $row) {
$tmp = array();
end($row);
$xe = key($row);
for ($x = $x0; $x <= $xe; $x++) {//把空值补上
$tmp[] = empty($row[$x]) ? 0 : 1;
}
if ($px < 1) {//不加边
if ($maxRow == count($tmp)) {//不变
$font[$key] = $tmp;
} else{//需要补全行
$font[$key] = array_pad($tmp, $maxRow, 0);
}
} else {//需要加边和补全行
$font[$key] = array_merge(array_fill(0, $px, 0), $tmp, array_fill(0, $maxRow + $px - count($tmp), 0));//增加左右二边
}
}
if ($px < 1) {//不加边
return $font;
} else {
$tmp = array_fill(0, $px, array_fill(0, $maxRow + 2 * $px, 0));
return array_merge($tmp, $font, $tmp);//增加上下二边
}
}
/* * 使用坐标点旋转(矩阵旋转)算法(旋转坐标公式) * X’=X*Cos(φ)-Y*Sin(φ)
* Y’=X*Sin(φ)+Y*Cos(φ)
*/
static private function _turnLR($font, $px) {
if (0 == $px) {
return $font;
}
$tmp = array();
$size = 10;
$yt = count($font) - 1;
foreach ($font as $y => $row) {
//$y = $yt - $y;//因为数组存放方式跟y坐标反了
foreach ($row as $x => $cell) {
$nx = floor($size * ($x * cos($px) - $y * sin($px)));
$ny = floor($size * ($x * sin($px) + $y * cos($px)));//*倍数,不让失真过大
if (! isset($tmp[$ny])) {
$tmp[$ny] = array();
}
$tmp[$ny][$nx] = $cell;
}
}
$tmp = captcha::_addOutPx($tmp);//补足空位
exit(captcha::_show2d($tmp));
return $tmp;
}
/* * 先生成文字图片,再根据像素点黑白二极化,输出字符码 */
static private function _showMakeFontBar() {
$fontW = 5;//使用默认字体,最大号
$fh = imagefontheight($fontW);
$fw = imagefontwidth($fontW);
echo '把下面的代码放到char2BW函数中:<pre>';
$str = STR;
for ($i = 0; $i < strlen($str); $i++) {
$im = imagecreatetruecolor($fw, $fh);
$white = imagecolorallocate($im, 255, 255, 255);
$char = $str{$i};
echo "\t\tcase '{$char}':\n\t\t\treturn ";
imagechar($im, $fontW, 0, 0, $char, $white);
//imagepng($im, $char.'.png');//输出测试图片
$outTmp = array();
for ($c = 0; $c < $fh; $c++) {
$ra = array();
for ($r = 0; $r < $fw; $r++) {
$ra[] = (int) 0 != imagecolorat($im, $r, $c) & 0xFF;//得到黑白码
}
$outTmp[] = 'array(' .implode(',', $ra). ')';
}
$aCode = "array(" .implode(',', $outTmp). ")";
$aCode = preg_replace("/array\((array\(0(,0)*\),)+/", 'array(', $aCode);//平切顶空白
$aCode = preg_replace("/(,array\(0(,0)*\))+\)/", ')', $aCode);//平切底空白
$aCode = preg_replace("/(,0)+\)/", ')', $aCode);//"全"切右空白
while (preg_match("/^array\(array\(0(,[01])*\)(,array\(0(,[01])*\))*\)$/", $aCode)) {//平切左空白
$aCode = str_replace("array(0,", 'array(', $aCode);
}
echo $aCode. ";\n";
eval("show2d({$aCode});");//输出测试二极2d码
}
echo '</pre>';
}
/* * 字符转二维码 */
static private function _getCharCode($str) {
$pxs = array();
$maxCell = 0;
for ($si = 0; $si < strlen($str); $si++) {
$code = captcha::_char2BW($str{$si});
if (is_null($code)) {//没有此字
continue;
}
//对字体变形
$lr = 0;//rand(-1, 1);
if ($lr != 0) {
$code = captcha::_turnLR($code, $lr);
}
$code = captcha::_addOutPx($code, 1);//为字加边
/*
$size = 0;//rand(0, 2);
$code = doHeights($code, $size);
$code = doWidths($code, $size);
*/
$cCount = 0;
$moveY = rand(0, round(count($pxs) / 2));//字y点与0点偏移量
foreach ($code as $r => $row) {
if (! isset($pxs[$r + $moveY])) {
$pxs[$r + $moveY] = array();
}
$cCount = max(count($row), $cCount);//记住最长行
$pxsR = & $pxs[$r + $moveY];//引用,方便
if ($maxCell > count($pxsR)) {//本行没有跟前字最长行平整,必须补0
$pxsR = array_pad($pxsR, $maxCell, '0');//使用0补足
}
foreach($row as $cell) {
$pxsR[] = $cell;//把每个字的相同横行拼一起
}
}
$maxCell += $cCount;//全字符最长行
}
return captcha::_addOutPx($pxs, 1);//补全外围
}
/* 输出二维码式的字形 */
static private function _show2d($chars) {
echo '<br/>/*<br/>';
foreach($chars as $val) {
foreach($val as $tmp) {
echo empty($tmp) ? '.' : '<span style="color:red;">*</span>';
}
echo '<br/>';
}
echo '*/<br/>';
}
/* 回字符对应二极码*/
static private function _char2BW($char) {
if (! is_string($char)) {
return null;
}
switch ($char) {
case 'a':
return array(array(0,0,1,1,1,1,1),array(0,1,1,0,0,0,1,1),array(0,0,0,0,0,0,1,1),array(0,1,1,1,1,1,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,1,1,1),array(0,1,1,1,1,0,1,1));
case 'A':
return array(array(0,0,0,1,1),array(0,0,1,1,1,1),array(0,1,1,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,1,1,1,1,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1));
case 'b':
return array(array(1,1),array(1,1),array(1,1),array(1,1,0,1,1,1),array(1,1,1,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,1,0,0,1,1),array(1,1,0,1,1,1));
case 'B':
return array(array(1,1,1,1,1,1),array(1,1,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,1,1),array(1,1,1,1,1,1),array(1,1,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,1,1),array(1,1,1,1,1,1));
case 'd':
return array(array(0,0,0,0,0,0,1,1),array(0,0,0,0,0,0,1,1),array(0,0,0,0,0,0,1,1),array(0,0,1,1,1,0,1,1),array(0,1,1,0,0,1,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(0,1,1,0,0,1,1,1),array(0,0,1,1,1,0,1,1));
case 'D':
return array(array(1,1,1,1,1,1),array(1,1,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,1,1),array(1,1,1,1,1,1));
case 'e':
return array(array(0,0,1,1,1,1),array(0,1,1,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,1,1,1,1,1,1),array(1,1),array(0,1,1,0,0,0,1,1),array(0,0,1,1,1,1,1));
case 'E':
return array(array(1,1,1,1,1,1,1),array(1,1),array(1,1),array(1,1),array(1,1,1,1,1,1),array(1,1),array(1,1),array(1,1),array(1,1),array(1,1,1,1,1,1,1));
case 'f':
return array(array(0,0,0,1,1,1,1),array(0,0,1,1,0,0,1,1),array(0,0,1,1,0,0,1,1),array(0,0,1,1),array(0,0,1,1),array(1,1,1,1,1,1),array(0,0,1,1),array(0,0,1,1),array(0,0,1,1),array(0,0,1,1));
case 'F':
return array(array(1,1,1,1,1,1,1,1),array(1,1),array(1,1),array(1,1),array(1,1,1,1,1,1),array(1,1),array(1,1),array(1,1),array(1,1),array(1,1));
case 'g':
return array(array(0,1,1,1,1,1,0,1),array(1,1,0,0,0,1,1,1),array(1,1,0,0,0,1,1),array(1,1,0,0,0,1,1),array(0,1,1,1,1,1),array(1,1),array(0,1,1,1,1,1,1),array(1,1,0,0,0,0,1,1),array(0,1,1,1,1,1,1));
case 'G':
return array(array(0,0,1,1,1,1,1),array(0,1,1,0,0,0,1,1),array(1,1),array(1,1),array(1,1),array(1,1,0,0,0,1,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(0,1,1,0,0,0,1,1),array(0,0,1,1,1,1,1));
case 'h':
return array(array(1,1),array(1,1),array(1,1),array(1,1,0,1,1,1),array(1,1,1,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1));
case 'H':
return array(array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,1,1,1,1,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1));
case 'i':
return array(array(0,0,1,1),array(0,0,1,1),array(0),array(0,1,1,1),array(0,0,1,1),array(0,0,1,1),array(0,0,1,1),array(0,0,1,1),array(0,0,1,1),array(1,1,1,1,1,1));
case 'J':
return array(array(0,0,1,1,1,1),array(0,0,0,0,1,1),array(0,0,0,0,1,1),array(0,0,0,0,1,1),array(0,0,0,0,1,1),array(0,0,0,0,1,1),array(0,0,0,0,1,1),array(1,0,0,0,1,1),array(1,1,0,1,1),array(0,1,1,1));
case 'L':
return array(array(1,1),array(1,1),array(1,1),array(1,1),array(1,1),array(1,1),array(1,1),array(1,1),array(1,1),array(1,1,1,1,1,1,1));
case 'm':
return array(array(1,0,1,1,0,1,1),array(1,1,0,1,1,0,1,1),array(1,1,0,1,1,0,1,1),array(1,1,0,1,1,0,1,1),array(1,1,0,1,1,0,1,1),array(1,1,0,1,1,0,1,1),array(1,1,0,1,1,0,1,1));
case 'M':
return array(array(1,1,0,0,0,0,1,1),array(1,1,1,0,0,1,1,1),array(1,1,1,1,1,1,1,1),array(1,1,0,1,1,0,1,1),array(1,1,0,1,1,0,1,1),array(1,1,0,1,1,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1));
case 'n':
return array(array(1,1,0,1,1,1),array(1,1,1,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1));
case 'N':
return array(array(1,1,0,0,0,0,1,1),array(1,1,1,0,0,0,1,1),array(1,1,1,1,0,0,1,1),array(1,1,1,1,0,0,1,1),array(1,1,0,1,1,0,1,1),array(1,1,0,1,1,0,1,1),array(1,1,0,0,1,1,1,1),array(1,1,0,0,0,1,1,1),array(1,1,0,0,0,1,1,1),array(1,1,0,0,0,0,1,1));
case 'q':
return array(array(0,0,1,1,1,0,1,1),array(0,1,1,0,0,1,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(0,1,1,0,0,1,1,1),array(0,0,1,1,1,0,1,1),array(0,0,0,0,0,0,1,1),array(0,0,0,0,0,0,1,1));
case 'Q':
return array(array(0,0,1,1,1,1),array(0,1,1,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,1,1,0,1,1),array(1,1,0,0,1,1,1,1),array(0,1,1,0,0,1,1),array(0,0,1,1,1,1,0,1));
case 'r':
return array(array(1,1,0,1,1,1,1),array(0,1,1,1,0,0,1,1),array(0,1,1),array(0,1,1),array(0,1,1),array(0,1,1),array(0,1,1));
case 'R':
return array(array(1,1,1,1,1,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,1,1,1,1,1),array(1,1,1,1,1),array(1,1,0,0,1,1),array(1,1,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1));
case 't':
return array(array(0,0,1,1),array(0,0,1,1),array(1,1,1,1,1,1),array(0,0,1,1),array(0,0,1,1),array(0,0,1,1),array(0,0,1,1),array(0,0,1,1,0,0,1,1),array(0,0,0,1,1,1,1));
case 'T':
return array(array(1,1,1,1,1,1,1,1),array(0,0,0,1,1),array(0,0,0,1,1),array(0,0,0,1,1),array(0,0,0,1,1),array(0,0,0,1,1),array(0,0,0,1,1),array(0,0,0,1,1),array(0,0,0,1,1),array(0,0,0,1,1));
case 'y':
return array(array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(0,1,1,0,0,1,1,1),array(0,0,1,1,1,0,1,1),array(1,0,0,0,0,0,1,1),array(0,1,1,1,1,1,1));
case 'Y':
return array(array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(0,1,1,0,0,1,1),array(0,0,1,1,1,1),array(0,0,0,1,1),array(0,0,0,1,1),array(0,0,0,1,1),array(0,0,0,1,1),array(0,0,0,1,1),array(0,0,0,1,1));
case '2':
return array(array(0,0,1,1,1,1),array(0,1,1,0,0,1,1),array(1,1,0,0,0,0,1,1),array(0,0,0,0,0,0,1,1),array(0,0,0,0,0,1,1),array(0,0,0,0,1,1),array(0,0,0,1,1),array(0,0,1,1),array(0,1,1),array(1,1,1,1,1,1,1,1));
case '3':
return array(array(0,1,1,1,1,1),array(1,1,0,0,0,1,1),array(0,0,0,0,0,0,1,1),array(0,0,0,0,0,1,1),array(0,0,0,1,1,1),array(0,0,0,0,0,1,1),array(0,0,0,0,0,0,1,1),array(0,0,0,0,0,0,1,1),array(1,1,0,0,0,1,1),array(0,1,1,1,1,1));
case '4':
return array(array(0,0,0,0,0,1,1),array(0,0,0,0,1,1,1),array(0,0,0,1,1,1,1),array(0,0,1,1,0,1,1),array(0,1,1,0,0,1,1),array(1,1,0,0,0,1,1),array(1,1,1,1,1,1,1,1),array(0,0,0,0,0,1,1),array(0,0,0,0,0,1,1),array(0,0,0,0,0,1,1));
case '5':
return array(array(1,1,1,1,1,1,1),array(1,1),array(1,1),array(1,1,0,1,1,1),array(1,1,1,0,0,1,1),array(0,0,0,0,0,0,1,1),array(0,0,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(0,1,1,0,0,1,1),array(0,0,1,1,1,1));
case '6':
return array(array(0,0,1,1,1,1),array(0,1,1,0,0,1,1),array(1,1,0,0,0,0,1),array(1,1),array(1,1,0,1,1,1),array(1,1,1,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(0,1,1,0,0,1,1),array(0,0,1,1,1,1));
case '7':
return array(array(1,1,1,1,1,1,1,1),array(0,0,0,0,0,0,1,1),array(0,0,0,0,0,0,1,1),array(0,0,0,0,0,1,1),array(0,0,0,0,1,1),array(0,0,0,1,1),array(0,0,1,1),array(0,1,1),array(1,1),array(1,1));
case '8':
return array(array(0,0,1,1,1,1),array(0,1,1,0,0,1,1),array(1,1,0,0,0,0,1,1),array(0,1,1,0,0,1,1),array(0,0,1,1,1,1),array(0,1,1,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(0,1,1,0,0,1,1),array(0,0,1,1,1,1));
case '9':
return array(array(0,0,1,1,1,1),array(0,1,1,0,0,1,1),array(1,1,0,0,0,0,1,1),array(1,1,0,0,0,0,1,1),array(0,1,1,0,0,1,1,1),array(0,0,1,1,1,0,1,1),array(0,0,0,0,0,0,1,1),array(0,1,0,0,0,0,1,1),array(0,1,1,0,0,1,1),array(0,0,1,1,1,1));
default:
return null;
}
}
}
-----------代码结束--------