Access911.net   |   a9BBS   |   OTaA System  
  搜索文章:  
Access911欢迎您光临  
   主页      上传      繁體版       论坛     
设为首页  |  加入收藏   
  
你现在的位置:文章索引 -> 文章分类 -> ASP/ASP.NET  
 首页|  近日更新|  下载  |  文章索引  |  搜索|  术语|  承接工程|  
 
系统正在加载内容,请耐心等待...
 
 查询
 窗体
 报表
 
 
 VBA
 函数
 ADO/DAO/ADO.NET
 API
 ADP
 安全
 发布
 OA
 ASP/ASP.NET
 其他语言
 控件
 DELPHI
 C#/.Net
 本站
 其他
 小例程
 常用软件
 参考文档
 业主作品
 网友大作
 
 
友情链接
 access911.net
 
访问人次
 1702097
 
站长 E-Mail
 net911@sina.com
 access911@gmail.com
 
RSS 订阅

显示附加信息 >>>

asp验证码bmp图片的生成原理(不必知道BMP的二进制构成)

作者:cg1  摘自:access911.net  :cg1  更新日期:2005-7-27  浏览人次:

 

asp验证码bmp图片的生成原理(不必知道BMP的二进制构成)


<%
'------ 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 测试用 --------
%>



http://access911.net/down/eg/checkcode.rar
 (261KB)

本站文章旨在为该问题提供解决思路及关键性代码,并不能完成应该由网友自己完成的所有工作,请网友在仔细看文章并理解思路的基础上举一反三、灵活运用。

access911.net 原创文章,作者本人对文章保留一切权利。
如需转载必须征得作者同意并注明本站链接

 

 
相关文章
     没有手动相关文章
 
评论
     查看或发表更多的评论,请单击这里。
 
 
 
 
 
   
  Access911.net   |   a9BBS   |   OTaA System   |
建站日期:2000年4月2日  |  设计施工:陈格 ( access911 & cg1 )
 Copyright © 2000 - 2003 COMET, 陈格 保留所有权利