基本说明:
您可以通过本代码片段,了解到:
1.BMP的文件结构,存储方式。
基本说明:
您可以通过本代码片段,了解到:
1.BMP的文件结构,存储方式。
2.对于简单的图像验证码如何进行识别处理。
当然,您也可以使用它完成对一些简单的符合条件的图片验证码进行识别处理。
文件说明:
demo.php 演示脚本
NEATBMP256ValidPic.class.php 相关类脚本
readme.txt 本文件
3721.bmp 3721的图像验证码
csdn.bmp CSDN的图像验证码
demo.php 中已经做了具体的演示。其他部分请自行参考 NEATBMP256ValidPic.class.php
demo.php
[code]
/**
* DEMO for Class NEATBMP256ValidPic
* walkerlee of NEATSTUDIO 2005-8-22
*/
// 包含处理类
include_once( 'NEATBMP256ValidPic.class.php' );
// 实例化
$bmp = new NEATBMP256ValidPic;
// 设置文件
$bmp->SetFile( '3721.bmp' );
$bmp->SetCodeColor( array( 1 ) );
$bmp->SetFrontColor( '#FFFFFF' );
$bmp->SetBackColor( '#3399CC' );
// 打开位图文件
$bmp->Open();
///////////////////////////////////////////////////////////////////////////////
// 例一 绘制位图数据偏移坐标图 ( 存储模式 )
/**
* 绘制位图数据偏移坐标图
* 因为BMP存储数据时候,是把图像反着存储的,所以看到的是一个倒着的图像.
*/
echo "
例一 : 存储模式 ( 一般用于寻找数据偏移位置 )
";$bmp->Draw();
///////////////////////////////////////////////////////////////////////////////
// 例二 绘制位图数据偏移坐标图 ( 观察模式 )
// 现在我们用查看模式来重新读取一次数据
$bmp->GetData( 'pop' );
/**
* 这时候绘制出的数据偏移坐标图则是我们用眼睛所观察到的正置的图像.
*/
echo "
例二 : 观察模式 ( 一般用于观察 )
";$bmp->Draw();
///////////////////////////////////////////////////////////////////////////////
// 例三 绘制位图数据偏移坐标图 ( 颜色代码模式 )
// 设置绘图方式为颜色代码显示方式
$bmp->SetDrawMod( 'source' );
// 绘制
echo "
例三 : 颜色代码模式 ( 一般用于寻找验证码颜色 )
";$bmp->Draw();
///////////////////////////////////////////////////////////////////////////////
// 例四 识别3721验证码 ( 通过逐一设置参数的方式 )
// 码表
$N3721_CODE[0] = "00011000001111000110011011000011110000111100001111000011011001100011110000011000";
$N3721_CODE[1] = "00011000001110000111100000011000000110000001100000011000000110000001100001111110";
$N3721_CODE[2] = "00111100011001101100001100000011000001100000110000011000001100000110000011111111";
$N3721_CODE[3] = "01111100110001100000001100000110000111000000011000000011000000111100011001111100";
$N3721_CODE[4] = "00000110000011100001111000110110011001101100011011111111000001100000011000000110";
$N3721_CODE[5] = "11111110110000001100000011011100111001100000001100000011110000110110011000111100";
$N3721_CODE[6] = "00111100011001101100001011000000110111001110011011000011110000110110011000111100";
$N3721_CODE[7] = "11111111000000110000001100000110000011000001100000110000011000001100000011000000";
$N3721_CODE[8] = "00111100011001101100001101100110001111000110011011000011110000110110011000111100";
$N3721_CODE[9] = "00111100011001101100001111000011011001110011101100000011010000110110011000111100";
// 设置验证码颜色,可以是多个颜色
$bmp->SetCodeColor( array( 1 ) );
// 设置验证码字串数目
$bmp->SetCodeTotal( 5 ); 
// 设置验证码字符宽度
$bmp->SetFontWeight( 8 );
// 设置验证码字符高度
$bmp->SetFontHeight( 10 );
// 设置验证码字符间隔距离
$bmp->SetFontSpace( 1 );
// 设置第一个验证字符的左上数据偏移
$bmp->SetOffSet( 3188 );
// 设置对比用码表
$bmp->SetCollateCode( $N3721_CODE );
// 识别处理
$code = $bmp->Valid();
echo "
例四 识别3721验证码 ( 通过逐一设置参数的方式 )
";echo "
 识别结果:" . $code;
 识别结果:" . $code;
// 关闭文件
$bmp->Close();
///////////////////////////////////////////////////////////////////////////////
// 例五 识别CSDN验证码 ( 通过装载配置参数的方式 )
// 相关参数
$CSDN_CODE[0] = "001111000100001010000001100000011000000110000001100000011000000110000001100000010100001000111100";
$CSDN_CODE[1] = "000010000000100000111000000010000000100000001000000010000000100000001000000010000000100000111110";
$CSDN_CODE[2] = "001111000100001000000001000000010000000100000010000001000000100000010000001000000100000001111111";
$CSDN_CODE[3] = "001111000100001000000001000000010000001000011100000000100000000100000001000000010100001000111100";
$CSDN_CODE[4] = "000000100000011000001010000100100010001001000010100000101111111100000010000000100000001000000010";
$CSDN_CODE[5] = "011111110100000001000000010000000111110000000010000000010000000100000001000000010100001000111100";
$CSDN_CODE[6] = "000111100010000001000000100000001011110011000010100000011000000110000001100000010100001000111100";
$CSDN_CODE[7] = "011111110000000100000010000000100000010000000100000010000000100000010000000100000010000000100000";
$CSDN_CODE[8] = "001111000100001010000001100000010100001000111100010000101000000110000001100000010100001000111100";
$CSDN_CODE[9] = "001111000100001010000001100000011000000110000001010000110011110100000001000000100000010001111000";
$CSDN = array(
        'CodeColor'                => array( 45 ),
        'CodeTotal'                => 4,
        'FontWeight'                => 8,
        'FontHeight'                => 12,
        'FontSpace'                => 1,
        'OffSet'                                => 1601,
        'CollateCode'                => $CSDN_CODE,
);
// 设置文件
$bmp->SetFile( 'csdn.bmp' );
// 装载参数
$bmp->LoadConfig( $CSDN );
// 把数据初始化
$bmp->Init();
// 打开位图文件
$bmp->Open();
// 识别处理
$code = $bmp->Valid();
// 关闭文件
$bmp->Close();
echo "
例五 识别CSDN验证码 ( 通过装载配置参数的方式 )
";echo "
 识别结果:" . $code;
 识别结果:" . $code;
?>[/code]
NEATBMP256ValidPic.class.php
[code]
/*
* 本代码思路基于 NetDust 
* 由NEATSTUDIO ( http://www.neatstudio.com ) 的 walkerlee 
* 本代码片段遵循GPL许可协议发布. 您可以任意修改和传播本代码片段,但请保留我们的版权信息.
*/
/**
* 256色BMP图片校验码识别类
* Created / Modify : 2005-8-21 / 2005-8-22
* @name  NEATBMP256ValidPic
* @version  1.0.0
* @author  walkerlee 
* @copyright  Powered by NEATSTUDIO 2002 - 2005 
* @link http://www.neatstudio.com NeatStudio
* @package NEATFramework
* @subpackage NEATImage
*/
/**
* TODO :
* 异常处理,比如,在处理前先判断图片是否是BMP格式。并且是256色。
*/
class NEATBMP256ValidPic
{
        
        /**
        * 待处理文件的绝对或者相对路径
        * @var string
        * @access private
        */
        var $bmpFile = '';
        /**
        * 前景色
        * @var string
        * @access private
        */
        var $frontColor = '#3399CC';
        /**
        * 背景色
        * @var string
        * @access private
        */
        var $backColor = '#FFFFFF';
        /**
        * 验证码颜色
        * @var integer
        * @access private
        */
        var $codeColor = '';
        /**
        * 表格绘图模式
        * @var string
        * @access private
        */
        var $drawMod = '';
        /**
        * 字体宽度
        * @var integer
        * @access private
        */
        var $fontWeight = '';
        /**
        * 字体高度
        * @var integer
        * @access private
        */
        var $fontHeight = '';
        /**
        * 字间距离
        * @var integer
        * @access private
        */
        var $fontSpace = '';
        /**
        * 待识别验证码字符个数
        * @var integer
        * @access private
        */
        var $codeTotal = '';
        /**
        * 第一个数字的左上角的数据偏移
        * @var integer
        * @access private
        */
        var $offSet = '';
        /**
        * 对比码数组
        * @var array
        * @access private
        */
        var $collateCode = array();
//////////////////////////////////////////////////////////////////////////////
        /**
        * 图片信息数组
        * @var array
        * @access private
        */
        var $imageInfo = array();
        /**
        * 原始图像数据数组
        * @var array
        * @access private
        */
        var $buffer = array();
        /**
        * 图片数据数组
        * @var array
        * @access private
        */
        var $imgData = array();
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // communications function
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        
        /**
        * 设置待处理的文件
        * @param string $file 文件绝对或者相对路径
        * @access public
        */
        function SetFile( $file )
        {
                $this->bmpFile = $file;
        }
        /**
        * 设置前景色
        * @param string $color 前景色 用于在表格上显示 16位格式 例:#FF0000
        * @access public
        */
        function SetFrontColor( $color )
        {
                $this->frontColor = $color;
        }
        /**
        * 设置背景色
        * @param string $color 背景色 用于在表格上显示 16位格式 例:#FF0000
        * @access public
        */
        function SetBackColor( $color )
        {
                $this->backColor = $color;
        }
        
        /**
        * 设置验证码颜色
        * @param string $color 验证码颜色 验证码的着色 范围在0-255
        * @access public
        */
        function SetCodeColor( $color )
        {
                $this->codeColor = $color;
        }
        /**
        * 设置表格绘图模式
        * @param string $mod 绘图模式 source 是直接显示出当前像素的颜色代码 0-255
        * @access public
        */
        function SetDrawMod( $mod )
        {
                $this->drawMod = $mod;
        }
        /**
        * 设置字体宽度
        * @param integer $weight 字体宽度 以像素为单位
        * @access public
        */
        function SetFontWeight( $weight )
        {
                $this->fontWeight = $weight;
        }
        /**
        * 设置字体高度
        * @param integer $height 字体高度 以像素为单位
        * @access public
        */
        function SetFontHeight( $height )
        {
                $this->fontHeight = $height;
        }
        /**
        * 设置字间距离
        * @param integer $space 字间距离 以像素为单位
        * @access public
        */
        function SetFontSpace( $space )
        {
                $this->fontSpace = $space;
        }
        /**
        * 设置待识别的验证码字符个数
        * @param integer $total 字符个数
        * @access public
        */
        function SetCodeTotal( $total )
        {
                $this->codeTotal = $total;
        }
        /**
        * 设置第一个数字的左上角的数据偏移
        * @param integer $offset 偏移位置
        * @access public
        */
        function SetOffSet( $offset )
        {
                $this->offSet = $offset;
        }
        /**
        * 设置对比码
        * @param array $code 对比码数组
        * @access public
        */
        function SetCollateCode( $code )
        {
                $this->collateCode = $code;
        }
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // common operation function
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /**
        * 打开文件
        * @return boolean
        * @access public
        */
        function Open()
        {
                return $this->fp = fopen( $this->bmpFile, "rb" );
        }
        /**
        * 关闭文件
        * @return boolean
        * @access public
        */
        function Close()
        {
                return fclose( $this->fp );
        }
        /**
        * 读取配置参数
        * @param array $config 配置参数数组
        * @access public
        */
        function LoadConfig( $config )
        {
                $this->codeColor        = $config['CodeColor'];
                $this->codeTotal        = $config['CodeTotal'        ];
                $this->fontWeight        = $config['FontWeight'];
                $this->fontHeight        = $config['FontHeight'];
                $this->fontSpace        = $config['FontSpace'];
                $this->offSet                        = $config['OffSet'];
                $this->collateCode = $config['CollateCode'];
        }
        /**
        * 返回已经获取的图片信息
        * @return array 图片信息数组
        * @access public
        */
        function GetInfo()
        {
                return $this->imageInfo;
        }
        /**
        * 获取原始的图片内容
        * @return array 原始图片内容数组
        * @access public
        */
        function GetBaseData()
        {                
                // 如果 $this->imageInfo 不存在 : 读取图片信息
                if ( !$this->imageInfo )
                        $this->Info();
                
                // 逐行读取
                for ( $i = $this->imageInfo['Height'] - 1; $i >= 0; $i-- )
                {
                        // 计算出数据偏移
                        $pos = $this->imageInfo['Offset'] + ( $this->imageInfo['Height'] - $i - 1 ) * $this->imageInfo['Weight'];
                        
                        // 移动指针
                        fseek ( $this->fp, $pos );
                        // 计算本行数据偏移
                        $line = $i * $this->imageInfo['Weight'];
                        // 初始化数组
                        $arr = array();
                        // 逐列读取
                        for ( $k = 0; $k < $this->imageInfo['Weight'] ; $k++ )
                        {
                                // 读取当前像素点的颜色数值,保存进本列数组
                                $arr[] = $this->_Bin2asc( fread( $this->fp, 1 ) );
                        }
                        // 构造数组
                        $this->buffer[$line] = $arr;
                }
                return $this->buffer;
        }
        /**
        * 获取图片内容
        * @param string $order 参数:shift 原始存储模式 图片是反着存储的。用于寻找第一个字符的数据偏移 参数:pop 显示模式 用于显示。
        * @return array 图片内容数组
        * @see GetBaseData
        * @access public
        */
        function GetData( $order = 'shift' )
        {
                
                // 如果 $this->buffer 不存在 : 获取图片原始内容
                if ( !$this->buffer )
                        $this->GetBaseData();
                // 判断数据构造模式
                if ( $order == 'shift' )
                        $handleMod = 'array_shift'; // 存储模式 图像倒置
                else
                        $handleMod = 'array_pop'; // 显示模式 图像正置
                
                // 获取原始图片内容数组的行数
                $arrayNum = count( $this->buffer );
                // 逐行处理
                for( $i = 1; $i <= $arrayNum; $i++ )
                {
                        // 重建数组
                        $this->imgData[$i] = $handleMod( $this->buffer );
                }
                return $this->imgData;
        }
/**
        * 取得图片信息
        * @return array 图片信息数组
        * @access public
        */
        function Info()
        {
                // 读取图片格式
                $this->imageInfo['Type'] = fread( $this->fp, 2 );
                // 读取图片尺寸
                $this->imageInfo['Size'] = $this->_ReadInt();
                // 保留地址
                $this->imageInfo['Reserved'] = $this->_ReadInt();
                // 获取数据偏移
                $this->imageInfo['Offset'] = $this->_ReadInt();
                // 获取头信息
                $this->imageInfo['Header'] = dechex( $this->_ReadInt() ) . 'H';
                // 获取图片的宽度
                $this->imageInfo['Weight'] =  $this->_ReadInt();
                // 获取图片的高度
                $this->imageInfo['Height'] =  $this->_ReadInt();
                // 获取图片的位面数
                $this->imageInfo['Planes'] =  $this->_Bin2asc( fread( $this->fp, 2 ) );
                // 获取图片的每个象素的位数
                $this->imageInfo['Bits Per Pixel'] =  $this->_Bin2asc( fread( $this->fp, 2 ) );
                // 获取图片的压缩说明
                $this->imageInfo['Compression'] =  $this->_ReadInt();
                // 用字节数表示的位图数据的大小。该数必须是4的倍数
                $this->imageInfo['Bitmap Data Size'] =  $this->_ReadInt();
                // 用象素/米表示的水平分辨率
                $this->imageInfo['HResolution'] =  $this->_ReadInt();
                // 用象素/米表示的垂直分辨率
                $this->imageInfo['VResolution'] =  $this->_ReadInt();
                // 位图使用的颜色数。如8-比特/象素表示为100h或者 256.
                $this->imageInfo['Colors'] =  $this->_ReadInt();
                // 指定重要的颜色数。当该域的值等于颜色数时(或者等于0时),表示所有颜色都一样重要
                $this->imageInfo['Important Colors'] =  $this->_ReadInt();
        }
        /**
        * 绘出坐标表
        * @access public
        */
        function Draw()
        {
                // 如果 $this->imgData 不存在 : 获取图片内容
                if ( !$this->imgData )
                        $this->GetData();
                
                // 显示表格以及样式
                echo "
| "; | " . sprintf( '%02.0f', $i ) . ""; | |||
| " . ( ( $I - 1 ) * $this->imageInfo['Weight'] ) . " | " . sprintf( '%02.0f', $I ) . ""; | " . $data . ""; | "; | " . sprintf( '%02.0f', $I ) . " | 
| "; | " . sprintf( '%02.0f', $i ) . ""; | 
}
        /**
        * 识别位图
        * @return string 识别后的字串
        * @access public
        */
        function Valid()
        {
                // 如果 $this->imgData 不存在 : 获取图片内容
                if ( !$this->imgData )
                        $this->GetData();
                
                // 根据校验码个数逐一识别
                for ( $i = 0; $i < $this->codeTotal; $i++)
                {
                        // 计算数字左上数据偏移
                        $bp = $this->offSet + ( $this->fontWeight + $this->fontSpace ) * $i;
                        // 获取对比特征码
                        $tmp = $this->_GetBound( $bp );
                        // 设置当前字符默认识别结果 * 代表无法识别
                        $c = '*';
                        // 遍历对比码,检查匹配情况
                        foreach ( $this->collateCode as $k => $v )
                        {
                                // 匹配
                                if ( $tmp === $v )
                                {
                                        // 设置当前字符识别结果
                                        $c = $k;
                                        break;
                                }
                        }
                        // 组合结果
                        $rs .= $c;
                }
                return $rs;
        }
        /**
        * 初始化数据状态
        * @access public
        */
        function Init()
        {
                $this->imageInfo = array();
                $this->buffer = array();
                $this->imgData = array();
        }
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // private function
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /**
        * 读取INT
        * @return integer 数字
        * @access private
        */
        function _ReadInt()
        {
           return $this->_Bin2asc( fread ( $this->fp, 4 ) );
        }
        /**
        * 二进制转ASCII
        * @return string 转换后的内容
        * @access private
        */
        function _Bin2asc ( $binary )
        {
                $val = 0;
                for ($i = strlen( $binary ) - 1; $i >= 0; $i--)
                {
                   $ch = substr( $binary, $i, 1 );
                   $val = ( $val << 8 ) | ord( $ch );
           }
           return $val;
        }
        /**
        * 获取数据区域特征码
        * @return string 特征码
        * @access private
        */
        function _GetBound( $bp )
        {
                // 移动指针
                fseek( $this->fp, $bp );
                // 按照矩形图形从左到右、从上到下的方向进行提取
                for ( $i = 1; $i <= $this->fontHeight; $i++  )
                {
                        for ( $ii = 1; $ii <= $this->fontWeight; $ii++ )
                        {
                                // 获取当前像素点颜色数值
                                $data = $this->_Bin2asc( fread( $this->fp, 1 ) );
                                // 如该像素颜色数值和校验码颜色匹配则表示为1, 否则为0
                                if (  in_array( $data, $this->codeColor ) )
                                        $rs .= 1;
                                else
                                        $rs .= 0;
                        }
                        // 指针移动到下一校验码区域
                        fseek( $this->fp, $bp - $i * $this->imageInfo['Weight'] );
                }
                return $rs;
        }
}
?>
[/code]
