您现在的位置: 雨哲在线 >> 文章教程 >> Web开发 >> Asp编程 >> 查看文章内容

asp验证码bmp图片的生成原理

【字体: 】         ★★★ 作者:cg1    文章来源:access911.net    点击数:1037    更新时间:2008-04-14    阅读点数:0

载入中

复制内容到剪贴板
雨[http://www.yz81.com]11740哲提示:代码片段
<%
'------ access911.net 开发验证码图片 --------
'以下是方法原理演示,并没有做最优化,请大家自己看吧,解释绝对够详细了,
'你不需要有 BMP 图片的知识都可以看懂

'如果你要自定义图片,只要在MYCODE中建立对应的文件夹,比如 mycode\w15h15;
'然后在其中用 WINDOWS 自己带的画图软件建立11张BMP图片,
'按规定定义图片名称即可,0-9 可定义为 0.BMP .... 9.BMP;
'最终要显示在客户端界面的 BMP 图片的大小应该定义为 displaysize.bmp;
'注意 0-9.BMP 与 DISPLAYSIZE.BMP 的高度和宽度要配合
'displaysize.BMP的底色就是杂点的颜色


Option Explicit
Response.buffer=true
NumCode

Function NumCode()
    Response.Expires = -1
    Response.AddHeader "Pragma","no-cache"
    Response.AddHeader "cache-ctrol","no-cache"
    On Error Resume Next
    Dim strNumber,i,j
    Dim adoStream,adoStream1,adoStream2
    dim CodeLen
    dim fld
    Dim intImg(),strAll
    dim lngZ            '杂点的百分比
    dim x1,x2,x3(2)
    Dim Pos                '文件头的长度,一般固定为 54
    dim w,h,w1,w0,h0

    pos=54                '文件头的长度,一般固定为 54
    lngZ=2                '杂点比率是 1%
    '对应文件的目录,长宽不同的BMP图片放在不同目录
    fld = "w30h20"        'w宽度,h高度
    
    
    Set adoStream=Server.CreateObject("Adodb.Stream")
    adoStream.Mode=3
    adoStream.Type=1
    adoStream.Open
    Set adoStream1=Server.CreateObject("Adodb.Stream")
    adoStream1.Mode=3
    adoStream1.Type=1
    adoStream1.Open
    Set adoStream2=Server.CreateObject("Adodb.Stream")
    adoStream2.Mode=3
    adoStream2.Type=1
    adoStream2.Open
    
    adoStream2.LoadFromFile(Server.mappath("mycode/" & fld & "/displaysize.bmp"))
    if err<>0 then
        response.Write server.HTMLEncode(err.number & err.Description) 
        response.End 
    end if
    
    'displaysize.bmp 是你自己定义的显示的 BMP 的大小,我们只要取他的前54个字节
    'adoStream2中存储了头字节

    'bmp图像头信息中,&H12 的四个字节代表宽  &H16 的四个字节代表高
    adoStream2.position= &H12        '3+15 18个字节开始
    w=adoStream2.read(4)            '宽
    h=adoStream2.read(4)            '高
    w=binval(w)                        '显示时候的总宽度
    h=binval(h)
    adoStream2.Position =0

    adoStream.LoadFromFile(Server.mappath("mycode/" & fld & "/0.bmp"))
    if err<>0 then
        response.Write server.HTMLEncode(err.number & err.Description)
        response.End 
    end if
    adoStream.position = &H12
    w0=adoStream.read(4)            '宽
    h0=adoStream.read(4)            '高
    w0=binval(w0)                    '显示时候的总宽度
    h0=binval(h0)

    '显示验证码图片的总宽度是每个图片的公倍数,并且显示验证码图片高度与每个数字图片高度一致
    if w mod w0 = 0 and h = h0 then
        '验证码由 N 个字构成,可更改,但是注意要与 displaysize.bmp配合
        CodeLen= clng(w/w0)
    else
        response.write "显示图片宽度与数字图片宽度不符合或高度不符,请用画图软件重新编辑"
        response.end
    end if

    w1=clng(w/CodeLen)                '每个图片的宽度

    Randomize timer
    'strNumber = clng(8999*Rnd+1000)
    '指定范围取随机整数 Int((upperbound - lowerbound + 1) * RND + lowerbound)
    for i=1 to CodeLen
        strNumber=strNumber & cstr(Int((9 - 0 + 1) * RND + 0))
    next
    Session("GetCode") = left(strNumber,CodeLen)
    strAll=strNumber
    redim intImg(CodeLen)
    For i=0 To CodeLen-1
        '以下代码用于调试,可以删除
        'response.write "d" & i & "d" & mid(strAll,i+1,1) & "<br>"
        intImg(i)=cint(mid(strAll,i+1,1))
    Next

    for i=0 to CodeLen-1
        adoStream.LoadFromFile(Server.mappath("mycode/" & fld & "/" & intImg(i) &".bmp"))
        '以下代码用于调试,可以删除
        'adostream.Position =0
        'response.Write lenb(adostream.Read())
        'response.End 
        '调试结束
        
        '开始做杂点
        for x2=1 to w1*h/100*lngZ
            Randomize timer
            x1=clng(clng((w1*h) - 0 + 1) * RND + 0)    '随机取某个像素
            if (pos+x1*3) < (w1*h*3+pos) then
                adoStream.Position = (pos + x1*3)
            end if
            '注意,displaysize.BMP的底色就是杂点的颜色
            adoStream2.Position =54
            adoStream.Write adoStream2.Read(3)
        next
        '杂点结束
    
        adoStream.position=54                    '偏移到第54个字节,也就是图像矩阵开始的地方
        adoStream1.write adoStream.read()        '读取第54个字节到最后
    next
    '现在为止, adoStream1中存储了所有图像,不过是竖的
    adostream1.Position =0
    '以下代码用于调试,可以删除
    'response.Write LENB(adostream1.read()) & "<BR>"
    'response.End 
    '调试结束

    adoStream2.Position =0

    '这里要进行行列转换
    '如果是20像素*20像素,竖排,每像素1200/20/20=3个字节,每行20*3=60字节
    DIM x,t1,t2,t3
    For i=0 To h-1 Step 1    '高度是几个像素
        For j=0 To CodeLen-1    'j代表有几个验证码字符
            '如果是20*20像素,第一个图片的第一行,就应该停在0,第二个图片应该停在 1200字节上,第二行第一个图片时应该,60,第二行第二个图片应该是J*1200+i*60
            
            'adoStream1.Position=i*60+j*1200                        '固定大小:20*20
            'adoStream1.Position=i*60+j*1800                        '固定大小:20*20
            'adoStream2.Position=Pos+60*j+i*360                        '固定大小:20*20
            'adoStream2.write adoStream1.read(60)                    '固定大小:20*20

            'adoStream1.Position=i*w1*3+j*w1*h*3
            '由于扫描时,每一行必须是4的公倍数,因此上面这行由下面这段 IF 代替
            IF (w1*3) MOD 4 <>0 THEN
                FOR X = 1 TO 20
                    if (w1*3+X) MOD 4 = 0 then
                        exit for
                    end if
                NEXT
                t1=i*(w1*3+x)
                t2=j*(w1*3+x)*h
                '以下代码用于调试,可以删除
                'RESPONSE.Write "I:" & i & " J:" & J & " W1:" & w1 & "--" & T2+T1 & "<BR>"
                adoStream1.Position =t1+t2
                '以下这句被前面那句 T1+T2 代替
                'adoStream1.Position=i*(w/CodeLen*3+x)+j*(w/CodeLen*3+x)*h
            ELSE
                '动态:w/CodeLen 是宽度,w/CodeLen*h 是整个图片的大小,每过一个J,就是条转到下一个图片的相同位置
                adoStream1.Position=i*w1*3+j*w1*h*3
            END IF
            
            '动态:w/CodeLen*3 是宽度,高度是第I行的整个字节长度 w/CodeLen*3*4
            'adoStream2.Position=Pos+w1*3*j+i*w*3                
            '由于扫描时,每一行必须是4的公倍数,因此上面这行由下面这段 IF 代替
            if (w*3) mod 4 <> 0 then
                FOR X = 1 TO 20
                    if (w*3+x) MOD 4 = 0 then
                        exit for
                    end if
                NEXT
                adoStream2.Position=Pos+w1*3*j+i*(w*3+x)
            else
                '动态:w/CodeLen*3 是宽度,高度是第I行的整个字节长度 w/CodeLen*3*4
                adoStream2.Position=Pos+w1*3*j+i*w*3                
            end if
            '动态:
            adoStream2.write adoStream1.read(w1*3)
        Next
    Next

    Response.ContentType = "image/BMP"
    adoStream2.Position=0
    '这里是组成好整个 BMP 以后再输出,你完全可以一面组织一面输出给客户端。
    '杂点也可以直接在输出的时候完成。
    Response.BinaryWrite adoStream2.read()
    
    adoStream.Close
    adoStream1.Close
    adoStream2.Close
    set adoStream=nothing
    set adoStream1=nothing
    set adoStream2=nothing
    
    If Err Then Session("GetCode") = err.description & 9999
End Function

Public Function BinVal(byval Bin)
    Dim Ret, I
    Ret = 0
    For I = LenB(Bin) To 1 Step -1
        Ret = Ret * 256 + AscB(MidB(Bin, I, 1))
    Next
    BinVal = Ret
End Function

'------ access911.net 测试用 --------
%>

文章来源:WWW.YZ81.COM

网友看法
    数据载入中,请稍后……
    发表评论
    昵 称: 邮 箱:
    评 分:
    内 容:
    0/5000)
    插入链接
    验证码:

    雨哲提示:Alt+S快速发表
用户信息中心
与本文章相关内容
广告位招商QQ:425162221