我的程序需要显示一张很大的图片(10000*10000),这么的图片若一次性加载会导致计算机无法响应的。但其实我的程序在某一瞬间只显示其中的某一部分。有没有办法快速加载其中某一部分显示到PictureBox中?如X=100,Y=100,Height=500,Width=500的一小部分。图片是C:\a.bmp(有45M大)读取它应该需要很长时间的。我的意思是在读图片时就已经根据我需要的范围(100,100,500,500)进行读取?就读取这一区域的数据,这样加载到程序中的其实就是500*500的小图片虽然我不太了解,但BMP文件的格式是公开的吧。我要求处理24位真彩色的图片。
通过二进制文件访问的办法应该可以很快构造出哪一个“很小的区域”的图片吧。
请各位高手指点一下阿。

解决方案 »

  1.   

    VB.NET图形图像编程实例详解是这样写的:
    BMP文件是VisualBasic进行图像处理的主要文件格式。BMP文件由文件头(BITMAPFILEHEADER)、文件信息头(BITMAPINFOHEADER)、调色板(PALETTE)及图像数据(Data)组成。
    文件头
    Type BITMAPFILEHEADER'奇怪,.net不是不支持Type了么?
    bfType As Integer'文件类型字段
    bfSize As Long'文件的大小
    bfReserved1 As Integer'保留(=0)
    bfReserved2 As Integer'保留(=0)
    bfOffBits As Long'第一个像素的偏移量
    End Type文件信息头
    Type BITMAPINFOHEADER
    biSize As Long '文件信息头的长度(一般=40)
    biWidth As Long'位图的宽度
    biHeight As Long'位图的高度
    biPlanes As Integer'平面的数目(=1)
    biBitCount As Integer'每个象素所占位数(如=8,16,24)
    biCompression As Long'是否压缩(为压缩=0)
    biSizeImage As Long'图像大小(可选)(按字节)
    biXPelsPerMeter As Long'未使用(=0)
    biYPelsPerMeter As Long'未使用(=0)
    biClrUsed As Long'位图使用的颜色数(使用所有颜色=0)
    biClrImportant As Long'重要颜色数(都重要=0)
    End Type调色板
    Type PALETTENTRY
    peRed As Byte'红色分量值
    peGreen As Byte'绿色分量值
    peBlue As Byte'蓝色分量值
    peFlags As Byte'字母通道(指示透明度)
    End Type数据图像(Data)
    256色图像:数据部分的值并非是图像的颜色值,而是调色板的索引(index)值
    24位真彩色图像:数据部分的值就是颜色值,因而24位真彩色位图没有调色板这一部分。注意,BMP图像的数据是按逆序存储的,即数据的第一行是屏幕显示的最后一行,因而采用顺序读取,逆序显示的方法;其次,BMP文件数据部分每一行像素数目都是4的倍数,这就意味着在读取数据时,应注意每一行的末端都可能包含有一些额外添加的(非像素值)字节,读取时应予忽略
      

  2.   

    其实我是想在VB.net中实现,.net中好像没有PictureClip控件,就算有,用PictureClip加载一个45M大的位图好像也很可怕我觉得只能通过二进制文件访问的办法。但我没有对位图的操作的经验和知识
      

  3.   

    一下是copy来的例子,使用API可以在菜单关闭后得到用户选择的选项,从而避免多次打开菜单的问题。'Example submitted by Leondias Frost ([email protected])
    Const MF_CHECKED = &H8&
    Const MF_APPEND = &H100&
    Const TPM_LEFTALIGN = &H0&
    Const MF_DISABLED = &H2&
    Const MF_GRAYED = &H1&
    Const MF_SEPARATOR = &H800&
    Const MF_STRING = &H0&
    Const TPM_RETURNCMD = &H100&
    Const TPM_RIGHTBUTTON = &H2&
    Private Type POINTAPI
        x As Long
        y As Long
    End Type
    Private Declare Function CreatePopupMenu Lib "user32" () As Long
    Private Declare Function TrackPopupMenuEx Lib "user32" (ByVal hMenu As Long, ByVal wFlags As Long, ByVal x As Long, ByVal y As Long, ByVal HWnd As Long, ByVal lptpm As Any) As Long
    Private Declare Function AppendMenu Lib "user32" Alias "AppendMenuA" (ByVal hMenu As Long, ByVal wFlags As Long, ByVal wIDNewItem As Long, ByVal lpNewItem As Any) As Long
    Private Declare Function DestroyMenu Lib "user32" (ByVal hMenu As Long) As Long
    Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
    Dim hMenu As Long
    Private Sub Form_MouseUp(Button As Integer, Shift As Integer, x As Single, y As Single)
        Dim Pt As POINTAPI
        Dim ret As Long
        hMenu = CreatePopupMenu()
        AppendMenu hMenu, MF_STRING, 1, "Hello !"
        AppendMenu hMenu, MF_GRAYED Or MF_DISABLED, 2, "Testing ..."
        AppendMenu hMenu, MF_SEPARATOR, 3, ByVal 0&
        AppendMenu hMenu, MF_CHECKED, 4, "TrackPopupMenu"
        GetCursorPos Pt
        ret = TrackPopupMenuEx(hMenu, TPM_LEFTALIGN Or TPM_RETURNCMD Or TPM_RIGHTBUTTON, Pt.x, Pt.y, Me.HWnd, ByVal 0&)
        DestroyMenu hMenu
        Debug.Print ret
    End Sub
      

  4.   

    定义BMP的文件结构,再从数据段中读入数据。
    不过如果全部都是24位色的图片的话,有一个投机取巧的方法,
    因为24位色BMP没有调色板,使用2进制方法打开文件,直接跳过文件头的长度,动数据段中读你需要的部分。此方法一旦用于其他颜色位的BMP立刻出错。
      

  5.   

    还有阿,那个双缓冲什么的,忘记它吧。
    既然是缓冲,你就得当场全部读到控件里或变量里,要能直接读,楼主也不用费这么大力气了,等于没说。呵呵.只是记得在学.Net时有个例子说什么双缓冲来的,所以就说一下提个醒呗.其实我也不会.
      

  6.   

    超大图片,应该用二进制方式,自已打开图片文件处理,BMP文件格式很简单,用BITMAPINFOHEADER算出扫描行长度,用BITMAPFILEHEADER.bfOffBits找到位图数据首偏移,就可逐行处理你的图片了。与在内存中处理DIB是一个原理。
      

  7.   

    Dim c As System.Drawing.Color
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            'On Error GoTo err1 '错误捕获
            Dim i As Integer
            Dim imgByte() As Byte
            Dim Pic As Image
            'Pic = New Bitmap("C:\222.bmp")
            'PictureBox1.Image = Pic
            'PictureBox1.Image.Width = 1000
            'Dim ImageBMP As System.Drawing.Bitmap = PictureBox1.Image
            Dim ImageBmp As New System.Drawing.Bitmap(800, 600)        'FileOpen(1, "c:\1\1.gif", OpenMode.Binary, OpenAccess.Read)
            Dim fname As String = "C:\000.bmp"
            Dim newBmp As Byte
            Dim firstPos As Byte
            FileOpen(1, fname, OpenMode.Binary, OpenAccess.Read)
            'FileOpen(2, "C:\111.bmp", OpenMode.Binary, OpenAccess.ReadWrite)
            FileSystem.Seek(1, 10 + 1)
            FileGet(1, firstPos)  '得到像素颜色的开始的位置 firstspos        'For i = 1 To firstPos
            '    FileSystem.Seek(2, i)
            '    FileSystem.Seek(1, i)
            '    FileGet(1, newBmp)
            '    If i = 19 Then newBmp = 10
            '    If i = 23 Then newBmp = 10
            '    FilePut(2, newBmp)
            'Next
            'For i = firstPos + 1 To LOF(1) / Len(newBmp)
            '    FileSystem.Seek(2, i)
            '    FileSystem.Seek(1, i)
            '    FileGet(1, newBmp)
            '    FilePut(2, newBmp)
            'Next
            MsgBox("!")
            'firstPos = firstPos + 1 '取消误差          Dim bmpGeshi1 As Byte '判断是不是BMP图片
            Dim bmpGeshi2 As Byte
            FileSystem.Seek(1, 1)
            FileGet(1, bmpGeshi1)
            FileSystem.Seek(1, 2)
            FileGet(1, bmpGeshi2)        ''UPGRADE_WARNING: Get 已升级到 FileGetObject 并具有新行为。 单击以获得更多信息:“ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="vbup1041"”
            'FileGetObject(1, 1, bmpGeshi1)
            ''UPGRADE_WARNING: Get 已升级到 FileGetObject 并具有新行为。 单击以获得更多信息:“ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="vbup1041"”
            'FileGetObject(1, 2, bmpGeshi2)        If bmpGeshi1 = 66 And bmpGeshi2 = 77 Then
                'Picture2.Print("BMP")
            Else
                'Picture2.Print("格式错误")
                MsgBox("ERROR")
                FileClose(1)
                Exit Sub
            End If        If geShi() = 24 Then '判断BMP图片位数
                'Picture2.Print("24位")
            Else
                MsgBox("文件是" + geShi() + "位格式暂时不支持,请打开24位格式的BMP")
                FileClose(1)
                Exit Sub
            End If        Dim maxX As Long '存图片宽, 附:定义为integer时pos值溢出 找到图片大小
            Dim maxY As Long '存图片高
            Dim x1 As Byte, x2 As Byte, x3 As Byte, x4 As Byte
            Dim y1 As Byte, y2 As Byte, y3 As Byte, y4 As Byte
            FileSystem.Seek(1, 18 + 1)
            FileGet(1, x1) '最低位 需要加 1
            FileSystem.Seek(1, 19 + 1)
            FileGet(1, x2)
            FileSystem.Seek(1, 20 + 1)
            FileGet(1, x3)
            FileSystem.Seek(1, 21 + 1)
            FileGet(1, x4)   '最高位
            maxX = x1 + x2 * 256 + x3 * 256 * 256 + x4 * 256 * 256 * 256 '得到横坐标x
            Dim X10 As Byte, X20 As Byte, X30 As Byte, X40 As Byte
            FileSystem.Seek(1, 22 + 1)
            FileGet(1, y1)  '最低位
            FileSystem.Seek(1, 23 + 1)
            FileGet(1, y2)
            FileSystem.Seek(1, 24 + 1)
            FileGet(1, y3)
            FileSystem.Seek(1, 25 + 1)
            FileGet(1, y4)   '最高位
            'Picture2.Print "y1="; y1; "y2="; y2; "y3="; y3; "y4="; y4
            maxY = y1 + y2 * 256 + y3 * 256 * 256 + y4 * 256 * 256 * 256 '得到纵坐标y
            'Picture2.Print "图像大小:宽"; maxX; "高"; maxY        'Picture1.Picture = LoadPicture() '清空图片框
            'Picture2.Picture = LoadPicture()
            Dim pos As Long '文件中点的坐标 开始描点
            Dim ix As Integer 'BMP文件中的位置
            Dim iy As Integer 'BMP文件中的位置
            Dim ix2 As Integer '用于描点的坐标
            Dim iy2 As Integer '用于描点的坐标
            Dim yanseRed As Byte '存红色的值
            Dim yanseGreen As Byte '存绿色的值
            Dim yanseBlue As Byte '存蓝色的值
            'Dim firstPos As Byte
            ix2 = 1 '用于描x坐标
            iy2 = maxY - 1 '用于描y坐标 附:由于 测试时顶头空了一行(多了行空白),所以-1
            'FileSystem.Seek(1, 10 + 1)
            'FileGet(1, firstPos)  '得到像素颜色的开始的位置 firstspos
            firstPos = firstPos + 1 '取消误差
            'Picture2.Print "像素点开始位置"; firstPos
            'For iy = 1 To 10 'y行
            '    For ix = 1 To 10
            '        Dim PosB
            '        pos = firstPos + (iy - 1) * maxX * 3 + (ix - 1) * 3
            '        PosB = firstPos + (iy - 1) * 10 * 3 + (ix - 1) * 3
            '        FileSystem.Seek(1, pos)
            '        FileGet(1, yanseBlue)
            '        FileSystem.Seek(2, PosB)
            '        FilePut(2, 0)        '        FileSystem.Seek(1, pos + 1)
            '        FileGet(1, yanseBlue)
            '        FileSystem.Seek(2, PosB + 1)
            '        FilePut(2, 0)        '        FileSystem.Seek(1, pos + 2)
            '        FileGet(1, yanseBlue)
            '        FileSystem.Seek(2, PosB + 2)
            '        FilePut(2, 255)
            '    Next
            'Next
            ProgressBar1.Maximum = maxY
            FileSystem.Seek(1, firstPos)
            Dim c As System.Drawing.Color
            For iy = 1 To maxY  'y行
                ix2 = 0 '下一行起点
                For ix = 1 To maxX   'x列
                    'pos = firstPos + (iy - 1) * maxX * 3 + (ix - 1) * 3 '计算文件指针位置 iy-1,ix-1取消误差
                    'Picture2.Print "pos=", pos
                    'FileSystem.Seek(1, pos)
                    FileGet(1, yanseBlue)   '得到颜色
                    'FileSystem.Seek(1, pos + 1)
                    FileGet(1, yanseGreen)   '得到颜色
                    'FileSystem.Seek(1, pos + 2)
                    FileGet(1, yanseRed) '得到颜色
                    'Picture1.PSet (ix2, iy2), RGB(yanseRed, yanseGreen, yanseBlue) '描点
                    'PictureBox1.Image()
                    c = ImageBmp.GetPixel(ix2, iy2)
                    c = c.FromArgb(yanseRed, yanseGreen, yanseBlue)                ImageBmp.SetPixel(ix2, iy2, c)
                    ix2 = ix2 + 1 '下一个点的位置
                Next ix
                ix2 = 0 '下一行起点
                iy2 = iy2 - 1 '下一行
                'Picture2.Print "iy2=", iy2
                'System.Windows.Forms.Application.DoEvents()
                'ProgressBar1.Value = iy
                'PictureBox1.Image = ImageBmp
            Next iy
            PictureBox1.Image = ImageBmp
            'FileClose(2)
            FileClose(1)  '正常时关闭文件
            Exit Sub
            'FileClose(1)
    err1:   '错误处理
            'If Err() = 32755 Then Exit Sub '取消打开文件,发生32755错误错误
            'Picture2.Print("发生错误")
            FileClose(1)  '有错误时关闭文件
            Exit Sub    End Sub
        Private Function geShi() As Integer '判断是几位BMP格式
            Dim gs As Byte
            FileSystem.Seek(1, 28 + 1)
            FileGet(1, gs)  '得到颜色
            geShi = gs
        End Function
      

  8.   

    我要做类似地理信息系统用来数字化地图的东东需要用一个好大好大的图作底图,所以45M应该算是小的用画图打开一个45M的图片需要好长好长好长好长时间上面是我目前写出的代码(二进制文件操作那一块是从VB6.0改写为VB.net的,有点乱七八糟的),可遇到了问题,就是用“画图”新建的24位BMP处理正常,但只要调整大小后就出错了,结果图像好像沿着一条斜线发生了错位,但用PhotoDraw/PhotoShop构建的24位BMP怎么处理都没问题。不知道什么原因?还有,将数组变成位图“ImageBmp.SetPixel(ix2, iy2, c)”那一段(相当于VB6的Pset)好像还是慢,尽管.net好像比VB6的Pset快一些,但还是比不上直接读取相同大小的位图快(那是一瞬间就可以完成的),可否加速?原来我想用数组重新写入二进制文件构建位图再“直接读取”,可从数组到生成二进制文件这一步就太慢了不知大家有什么好建议?将数组修改为1维的会大大提高速度么?如何用API函数快速将数组转为图片?就要过元旦了,先向UP者、解答者、关注者、发错贴者致以新年问候来点实惠的?结贴给分?现在还不行啊还望大家继续赐教啊
      

  9.   

    自己一点一点地画出来肯定慢,提个建议:
    把从BMP文件中提取出来的数据重新形成一个小文件,再用Picture直接读取
    不想形成文件的也可以采用再内存中直接形成位图文件格式后转换
    相信比你直接一点一点地画来的快
      

  10.   

    你可以用别的解决方法呀
    先把位图分割成100来张图片,文件名用一定的顺序
    一张几百K,要用的时候将其读入,用bitblt函数应该可以解决问题了
      

  11.   

    你们的方法有问题,应该这样:
    1、将大图片读入内存,用API函数(不难做到);
    2、LoadImage
       CreateCompatibleDC
       SelectObject...
    3、用BitBlt拷取任一区块。