当前位置:编程学习 > VB >>

VB 图片框 无法创建AutoRedraw对象

如题,当用图片框进行图像的加载或者绘制,比如用Loadpicture,或者Bitblt,或者Pic.Paintpicture进行绘制时,当图片的尺寸大于4千像素时,有时会出现.hdc无效,或者报告无法创建Autoredraw对象,这种情况如何解决?
我是想用pic1加载图片,然后采用paintpicture方法或者bitblt函数将pic1裁剪入pic2中,但一发生无法创建autoredraww对象的错误后,就没法弄了,对于这种情形,如何才能办到成功裁剪呢? VB 图片框 裁剪 --------------------编程问答-------------------- 有说将pic的autoredraw设置为false,但设置为false之后,保存出来的空白图片呀 --------------------编程问答-------------------- 感觉你的系统或程序有问题。
错误480的原因是内存不足,这样小的内存都无法申请,系统接近崩溃了吧!
看看任务管理器中你的程序用了多少内存?

--------------------编程问答-------------------- VB或系统提供的图形方案通常是以屏幕显示为基础的,所以所处理的图形大小最多只是屏幕大小的几倍大,如果需要处理那种超大的图形,如 10m*5m 600dpi 这种超大图形,必须自己建立虚拟内存自己处理图形文件格式的数据,当需要显示到屏幕的时候,才把需要显示的数据用四叉树或别的算法提取到一块目标显示区域的数据里,用GDI之类的技术回显出来。很多东西都是如此,当你的需求系统不提供支持的时候,就需要自己去了解这种技术,然后自己出方案解决。就比如我说的这种方案,Photoshop 就是这种应用典型的例子。 --------------------编程问答--------------------
引用 2 楼 Tiger_Zhao 的回复:
感觉你的系统或程序有问题。
错误480的原因是内存不足,这样小的内存都无法申请,系统接近崩溃了吧!
看看任务管理器中你的程序用了多少内存?

当我加载一张3008*2000的数码照片的时候,没有问题,正常;当我加载了一张5400*6800的图像时,就出现了err 480错误,不能创建autoredraw对象了,这时查看内存占用情况,才占用10M,而IE有时还占到16M或者20M呢。应该不是内存不足的问题。 --------------------编程问答--------------------
引用 3 楼 SupermanKing 的回复:
VB或系统提供的图形方案通常是以屏幕显示为基础的,所以所处理的图形大小最多只是屏幕大小的几倍大,如果需要处理那种超大的图形,如 10m*5m 600dpi 这种超大图形,必须自己建立虚拟内存自己处理图形文件格式的数据,当需要显示到屏幕的时候,才把需要显示的数据用四叉树或别的算法提取到一块目标显示区域的数据里,用GDI之类的技术回显出来。很多东西都是如此,当你的需求系统不提供支持的时候,就需要自己去……

我的屏幕宽是1366的,那几倍大,比如4倍大,也就只能处理5千及以下的了。
思路应该是你的这种思路,我不需要显示,我只需要将局部区域裁剪出来保存即可,而在VB中,不借助图片框或者窗体对象,如何才能将内存中指定区域的图像内容保存为单位的图像呢? --------------------编程问答--------------------
引用 楼主 u010222218 的回复:
……当图片的尺寸大于4千像素时……

引用 4 楼 u010222218 的回复:
……当我加载了一张5400*6800的图像时……

换谁都该凌乱了吧!!!

既然不是“64*64 > 4千像素”这种级别,就是3楼说的原因了。 --------------------编程问答-------------------- 采用折衷的办法,不知道行不行:2次平滑缩放
第一次平滑缩小到能够显示的区域,记住缩小系数,裁剪后放到pic2中;
第二次平滑放大,放大系数根据缩小系数来决定。OK后,保存!
2次平滑缩放可能会牺牲一些像素。 --------------------编程问答-------------------- 其实内存是足够的,只是系统不能创建这样大尺寸的句柄而已。
并不需要对原图进行压缩,只需要能替代 LoadPicture、PaintPicture 的方法而已。
建议原图解压成 BITMAPINFO 结构;
可以将原图上需要进行剪裁的区域划分成较小的区块,小区块的内容复制到一个中间 BITMAPINFO 中,就可以 Bitblt 到目标图上了。 --------------------编程问答--------------------
引用 5 楼 u010222218 的回复:
引用 3 楼 SupermanKing 的回复:VB或系统提供的图形方案通常是以屏幕显示为基础的,所以所处理的图形大小最多只是屏幕大小的几倍大,如果需要处理那种超大的图形,如 10m*5m 600dpi 这种超大图形,必须自己建立虚拟内存自己处理图形文件格式的数据,当需要显示到屏幕的时候,才把需要显示的数据用四叉树或别的算法提取到一块目标显示区域的数据里,用GDI之类的技……

看看我的资源,里面有BMP文件格式相关的东西,中文很多,很好懂的:
http://download.csdn.net/detail/SupermanKing/427319 --------------------编程问答--------------------
引用 7 楼 chenjl1031 的回复:
采用折衷的办法,不知道行不行:2次平滑缩放
第一次平滑缩小到能够显示的区域,记住缩小系数,裁剪后放到pic2中;
第二次平滑放大,放大系数根据缩小系数来决定。OK后,保存!
2次平滑缩放可能会牺牲一些像素。

缩小后,当能显示到pic上,但然后再放大还原,就失真了,不可取。 --------------------编程问答--------------------
引用 8 楼 Tiger_Zhao 的回复:
其实内存是足够的,只是系统不能创建这样大尺寸的句柄而已。
并不需要对原图进行压缩,只需要能替代 LoadPicture、PaintPicture 的方法而已。
建议原图解压成 BITMAPINFO 结构;
可以将原图上需要进行剪裁的区域划分成较小的区块,小区块的内容复制到一个中间 BITMAPINFO 中,就可以 Bitblt 到目标图上了。


这是一种可以可行,但不是一步到位的方法。 --------------------编程问答--------------------
引用 9 楼 SupermanKing 的回复:
引用 5 楼 u010222218 的回复:
引用 3 楼 SupermanKing 的回复:VB或系统提供的图形方案通常是以屏幕显示为基础的,所以所处理的图形大小最多只是屏幕大小的几倍大,如果需要处理那种超大的图形,如 10m*5m 600dpi 这种超大图形,必须自己建立虚拟内存自己处理图形文件格式的数据,当需要显示到屏幕的时候,才把需要显示的数据用四叉树或别的算法提取到一块目标显示区域的数……


你这方法能实现将内存中的图像直接截取指定的区域并保存吗? --------------------编程问答--------------------
引用 12 楼 u010222218 的回复:
你这方法能实现将内存中的图像直接截取指定的区域并保存吗?

如果你能看懂就能。 --------------------编程问答-------------------- 研究了下,还是很迷糊的呀

引用 13 楼 SupermanKing 的回复:
引用 12 楼 u010222218 的回复:
你这方法能实现将内存中的图像直接截取指定的区域并保存吗?
如果你能看懂就能。


研究了下,还是很迷糊的呀:你这功能保存出来的图像,只是实现了将每一份图像文件的数据依次保存在新的图像文件对应的区域,但是,所得的新图像的尺寸跟原始图像直接未缩放的拼接所得的尺寸不一样,况且,得到的新图像,打开后全是密密麻麻的杂色点,没有清晰的正确的拼接后的图像呢。那就更不用说能够只截取图像的部分进行保存了。 --------------------编程问答--------------------
引用 14 楼 u010222218 的回复:
研究了下,还是很迷糊的呀:你这功能保存出来的图像,只是实现了将每一份图像文件的数据依次保存在新的图像文件对应的区域,但是,所得的新图像的尺寸跟原始图像直接未缩放的拼接所得的尺寸不一样,况且,得到的新图像,打开后全是密密麻麻的杂色点,没有清晰的正确的拼接后的图像呢。那就更不用说能够只截取图像的部分进行保存了。

看来你还是没看懂,那个例子是把其他的数据硬套进BMP文件格式里保存的,里面有关于BMP文件格式相关的说明和处理过程,虽然是以写BMP文件为主,但可以把写的过程逆过来就可以读。如果你尝试自己去读一个小的BMP文件并能正确的显示出来,那么就意味着你明白了BMP图像数据在BMP图像文件里的结构是如何排列和存放的,当读大图像数据的时候就可以根据这种规律任意取值和运算,你现在只不过是看程序的运行效果,根本没去理解这些问题,也没去尝试研究这种图形文件格式,所以才会很迷糊。 --------------------编程问答--------------------
引用 11 楼 u010222218 的回复:
这是一种可以可行,但不是一步到位的方法。

只有直接调用 Bitblt、Paintpicture 才叫一步到位,既然你来求方法,肯定已经不能一步到位了。
SupermanKing 给出的 BMP 的存取例子,我给出的是操作思路,不冲突。 --------------------编程问答--------------------
引用 3 楼 SupermanKing 的回复:
VB或系统提供的图形方案通常是以屏幕显示为基础的,所以所处理的图形大小最多只是屏幕大小的几倍大,如果需要处理那种超大的图形,如 10m*5m 600dpi 这种超大图形,必须自己建立虚拟内存自己处理图形文件格式的数据,当需要显示到屏幕的时候,才把需要显示的数据用四叉树或别的算法提取到一块目标显示区域的数据里,用GDI之类的技术回显出来。很多东西都是如此,当你的需求系统不提供支持的时候,就需要自己去……


Private Const SRCCOPY = &HCC0020 ' (DWORD) dest = source
Private Const NOTSRCCOPY = &H330008      ' (DWORD) dest = (NOT source)
Private Declare Function CreateCompatibleBitmap Lib "gdi32" (ByVal Hdc As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal Hdc As Long) As Long
Private Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" (ByVal Hdc As Long) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, ByVal Hdc As Long) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal Hdc As Long, ByVal hObject As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
Private Declare Function StretchBlt Lib "gdi32" (ByVal Hdc As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal dwRop As Long) As Long

Public Function CutAndSavePicInMem(ByVal strSrcImage As String, ByVal strDestImage As String, ByVal Left As Long, ByVal Top As Long, _
ByVal NewPicW As Long, ByVal NewPicH As Long, ByVal CutW As Long, ByVal CutH As Long, Optional ByVal SaveType As Long = 1, Optional ByVal BatDo As Boolean = True) As Boolean  '在 内存中裁剪并保存图腾
    Dim objPic As New StdPicture
    Dim lDC As Long, lMemDC As Long, lTmpDC As Long, cR As Double
    Dim lBitmap As Long, lBitmap1 As Long, lBitmap2 As Long
    Dim nHeight As Long, nWidth As Long
    On Error GoTo Err_Cut
    Set objPic = LoadPicture(app.path & "\bmp.bmp")  '将bmp图像文件读入静态图像而不加载并在图片框中显示
    nWidth = BigPicW '该图片的宽   
    nHeight = BigPicH '该图片的高
    lDC = GetDC(0)
    lTmpDC = CreateCompatibleDC(lDC)  '在内存中创建兼容dc
    lMemDC = CreateCompatibleDC(lDC)
    lBitmap = CreateCompatibleBitmap(lDC, NewPicW, NewPicH)      ' 在内存中创建一个临时图片,图片新的尺寸为截取的局部区域的尺寸
    lBitmap1 = SelectObject(lMemDC, objPic.handle)              ' 源图片
    lBitmap2 = SelectObject(lTmpDC, lBitmap)                    ' 临时图片
    StretchBlt lTmpDC, 0, 0, NewPicW, NewPicH, lMemDC, Left, Top, CutW, CutH, SRCCOPY  ' 反将源图片中由(Left,Top)坐标以及CutW, CutH界定的裁剪区域图像复制到临时中
''    StretchBlt lMemDC, 0, 0, nWidth, nHeight, lTmpDC, 0, 0, NewPicW, NewPicH, SRCCOPY    ' 将临时图片放大并覆盖源图像,得到裁剪后的新图片
     SelectObject lTmpDC, lBitmap2
     SelectObject lMemDC, lBitmap1
    SavePicture objPic, StrDir & "\bmp.bmp"    ' 保存裁剪后的图片,但该新图片的内容是指定裁剪区域的内容,是所需要且是正确的,但新图片的尺寸被放大跟原始尺寸一样了,怎么才能将被裁剪后的不放大保存出来呢?
    DeleteObject lBitmap
    DeleteDC lTmpDC
    DeleteDC lMemDC
    ReleaseDC 0, lDC
    Exit Function

Err_cut:
     MsgBox err.description, vbInformation + vbOKOnly, "消息"
End Function

对于你说的对你的那程序逆向研究其读写,我再研究。数据结构和读写是明白的,就是合并后的图像怎么显示不正确的问题,需要再研究。 --------------------编程问答-------------------- 既然你接触到了GDI,那么你可以研究一下 GetBitmapBits 和 SetBitmapBits 函数,这就两个函数可以取得和设置GDI设备中的图像数据,其数据结构与BMP文件格式的数据极为相似,BMP的数据是从下至上,从左至右的排列,还有个行字节对齐,对其值是4的倍数,而GDI则是从上至下,从左至右,也有行对齐概念,只是该值为2的倍数,如果你理解了BMP的数据结构,完全可以稍做改变把BMP读到的值放到某个字节数组中,通过SetBitmapBits放到GDI设备里回显出来,当然,如果不需要回显,你也可以直接按照你的需求提取指定区域值到目标文件。 --------------------编程问答--------------------
Quote: 引用 18 楼 SupermanKing 的回复:

既然你接触到了GDI,quote]
   If InitGDIPlus = OK Then  '初始化GDI+
         Picture1.AutoRedraw=false
       GdipCreateFromHDC Picture1.hdc, Graphics   '初始化绘图区
        GdipSetSmoothingMode Graphics, SmoothingModeAntiAlias '平滑绘图区
        GdipLoadImageFromFile StrPtr(app.path & "\bmp.bmp"), img  '加载目标大图片
        GdipDrawImageRectRect Graphics, img, 0, 0, NewPicW, NewPicH, Left, Top, CutW, CutH, UnitPixel  '将内存中的大图片img,截取以(Left,Top)为左上角起点坐标,宽为CutW高伟CutH的区域画入Graphics中
      SaveImageToJPG img, app.path & "\test.jpg", 80  '此保存得到的还是原始图像,未被截取
      SaveImageToJPG Graphics, app.path & "\test.jpg", 80 '用此无法保存得到被裁剪后的新图像
        GdipDeleteGraphics Graphics '释放graphics占用的内存
          TerminateGDIPlus '反初始化
              Picture1.AutoRedraw=True
         Picture1.Picture = Picture1.Image  '仍然出现autoredraw无法创建图像,导致无法保存
      Picture1.Refresh     
     End If
如何修改呢?
补充:VB ,  多媒体
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,