注册 登录
编程论坛 VFP论坛

截屏保存为bmp文件完整版mbpsaver

sam_jiang 发布于 2023-09-08 12:13, 908 次点击
感谢seasoners网友对我的代码感兴趣,给我动力,促使我重写这个程序,并在win7+vfp9下编译通过。

本源码仅供学习交流,如商用,请私信联系我,非常感谢!
程序代码:

***********************************************************************************************************
*!*    参考自己10几年前写的图片格式转换代码,重新编写这一段精简代码。
*!*    这是一个直接将截屏转换为黑白图片的演示程序,
*!*    运行本示例可以将截取_screen 的200 X 200 的区域,可以把程序中的200改成任何你想要的尺寸
*!*    也可以把你想要的尺寸再设置成2个参数。
*!*    并在你的默认目录中以文件名为testbw.bmp保存。
*!*    同理,稍加修改,它可以用在图片格式转换中,直接将彩图转换为黑白图片。
*!*    这个速度简直不要太快,就是不知道成图效果和挨个对图像数据流进行运算的二值化算法的效果一不一样?
*!*    当初VB代码是一个台湾人写的,可惜忘记他的网名了,在此表示感谢!
*!*    作者:Sam Jiang
*!*    时间:2023/09/06
*!*    1st revised: 2023/09/08
*!*    修改内容:添加16色,256色,及灰阶图,真彩,全彩
*!*    改名为bmpsaver.prg
*!*    本程序在win7 和 vfp9.0(7423版)环境下编译通过
***********************************************************************************************************
PARAMETERS npara

DO case
    CASE npara=1 &&黑白
        nbitcount=1
        ccolortable=bintoc(0,"4rs")+bintoc(RGB(255,255,255),"4rs")
    CASE npara=2 &&16色
        nbitcount=4
        DIMENSION colors[16]
        colors[1]=RGB(0,0,0)
        colors[2]=RGB(0,0,191)
        colors[3]=RGB(0,191,0)
        colors[4]=RGB(0,191,191)
        colors[5]=RGB(191,0,0)
        colors[6]=RGB(191,0,191)
        colors[7]=RGB(191,191,0)
        colors[8]=RGB(191,191,191)
        colors[9]=RGB(64,64,64)
        colors[10]=RGB(0,0,255)
        colors[11]=RGB(0,255,0)
        colors[12]=RGB(0,255,255)
        colors[13]=RGB(255,0,0)
        colors[14]=RGB(255,0,255)
        colors[15]=RGB(255,255,0)
        colors[16]=RGB(255,255,255)
        ccolortable=""
        FOR i=1 TO 16
            ccolortable=ccolortable+BINTOC(colors[i],"4rs")
        ENDFOR
    CASE npara=3 &&256色
        nbitcount=8
        DIMENSION colors[256]
        i=0
        ccolortable=""
        FOR b=0 to 0xe0 step 0x20
            FOR g=0 to 0xe0 step 0x20
                FOR r=0 TO 0xc0 STEP 0x40
                    colors[i+1]=IIF(b=0xe0,0xff,b)*0x10000+;
                                IIF(g=0xe0,0xff,g)*0x100+;
                                IIF(r=0xc0,0xff,r)
                    ccolortable=ccolortable+BINTOC(colors[i+1],"4rs")
                    i=i+1
                ENDFOR
            ENDFOR
        ENDFOR
    CASE npara=4 &&256灰色
        nbitcount=8
        DIMENSION graycolors[256]
        ccolortable=""
        FOR i=0 TO 255
            graycolors[i+1]=RGB(i,i,i)
            ccolortable=ccolortable+BINTOC(graycolors[i+1],"4rs")
        ENDFOR        
    CASE npara=5 &&真彩
        nbitcount=24
        ccolortable=""
    CASE npara=6 &&全彩
        nbitcount=32
        ccolortable=""
    OTHERWISE
        return .f.
ENDCASE

DO decl
obmiheader=NEWOBJECT([bmiheader],[myclass])
WITH obmiheader
    .bibitcount=nbitcount
    .biheight=200
    .biwidth=200
    .bisizeimage=CEILING(.biwidth/16)*2*.biheight
endwith   
lcbitmapinfoheader=obmiheader.getstruct()
hdc=getdc(_screen.HWnd)
hvdc=createcompatibledc(hdc)

if npara=1
    hbitmap=createbitmap(200,200,1,1,null)
ELSE
    hbitmap=createdibsection(hdc,lcbitmapinfoheader+ccolortable,0,null,0,0)
ENDIF

selectobject(hvdc,hbitmap)
=bitblt(hvdc,0,0,200,200,hdc,0,0,0x00cc0020)
n=getobjecta(hbitmap,0,null)
lcbitmap=REPLICATE(CHR(0),n)
GETOBJECTA(hbitmap,n,@lcbitmap)
obitmap=NEWOBJECT([bitmap],[myclass])
obitmap.set(lcbitmap)
m=obitmap.bmwidthbytes*obitmap.bmheight
lcbitmapdata=REPLICATE(CHR(0),m)
getbitmapbits(hbitmap,m,@lcbitmapdata)
x=CEILING(obitmap.bmwidthbytes/4)*4-obitmap.bmwidthbytes
lcbmpfdata=""
if x#0
    for i=1 to obitmap.bmheight
        lcbmpfdata=SUBSTR(lcbitmapdata,(i-1)*obitmap.bmwidthbytes+1,obitmap.bmwidthbytes)+REPLICATE(CHR(0),x)+lcbmpfdata
    ENDFOR
ELSE
    if npara=1
        lcbmpfdata=lcbitmapdata
    ELSE
        for i=obitmap.bmheight to 1 step -1
            lcbmpfdata=lcbmpfdata+SUBSTR(lcbitmapdata,(i-1)*obitmap.bmwidthbytes+1,obitmap.bmwidthbytes)
        ENDFOR
    ENDIF            
ENDIF
        
bmpfile=NEWOBJECT("bmpfile","myclass")
WITH bmpfile
    .bitmapdata=lcbmpfdata
    .colortable=ccolortable
    WITH .bmfheader
        .bfoffbits=54+LEN(ccolortable)
        .bfsize=54+LEN(ccolortable)+LEN(lcbmpfdata)
    ENDWITH
    WITH .bmiheader   
        .bibitcount=nbitcount
        .biwidth=200
        .biheight=200
        .bisize=40
        .bisizeimage=LEN(lcbmpfdata)
        .bixpelspermeter=0
        .biypelspermeter=0
    ENDWITH   
ENDWITH
deletedc(hvdc)
deleteobject(hbitmap)
releasedc(_screen.hwnd,hdc)
bmpfile.save("testbw.bmp")
clea memory
release all


FUNCTION decl
    DECLARE integer GetObject IN WIN32API as getobjecta integer,integer,string
    DECLARE integer ReleaseDC IN WIN32API integer,integer
    DECLARE integer DeleteDC IN WIN32API integer
    DECLARE integer CreateBitmap IN WIN32API integer,integer,integer,integer,string
    DECLARE integer SelectObject IN WIN32API integer,integer
    DECLARE integer DeleteObject IN WIN32API integer
    DECLARE integer CreateCompatibleDC IN WIN32API integer
    declare integer CreateCompatibleBitmap in win32api integer,integer,integer
    DECLARE integer GetBitmapBits IN WIN32API integer,integer,string
    DECLARE integer CreateDIBSection IN WIN32API integer,string,integer,string,integer,integer
    DECLARE integer BitBlt IN WIN32API integer,integer,integer,integer,integer,integer,integer,integer,integer
    DECLARE integer GetDC IN WIN32API integer
    declare integer GetDIBits in win32api integer,integer,integer,integer,string,string,integer
ENDFUNC


黑白效果图:
只有本站会员才能查看附件,请 登录

16色效果图:
只有本站会员才能查看附件,请 登录

256色效果图:
只有本站会员才能查看附件,请 登录

灰阶效果图:
只有本站会员才能查看附件,请 登录

真彩效果图:
只有本站会员才能查看附件,请 登录

全彩效果图:
只有本站会员才能查看附件,请 登录



[此贴子已经被作者于2023-9-8 12:18编辑过]

15 回复
#2
sam_jiang2023-09-08 12:21
真彩和全彩效果一样,只是全彩可以设置透明度。
#3
schtg2023-09-08 14:59
谢谢!
#4
kangss2023-09-08 15:26
十分感谢!
#5
nbwww2023-09-08 18:27
#6
easyppt2023-09-08 21:21
#7
laowan0012023-09-08 21:42
#8
pvm20002023-09-08 23:55
辛苦
#9
吹水佬2023-09-09 17:40
试试用 GdipCreateBitmapFromScan0(),看效果如何

支持以下常量指定位图中使用的各种像素格式。

PixelFormat1bppIndexed = 196865
PixelFormat4bppIndexed = 197634
PixelFormat8bppIndexed = 198659
PixelFormat16bppGrayScale = 1052676
PixelFormat16bppRGB555 = 135173
PixelFormat16bppRGB565 = 135174
PixelFormat16bppARGB1555 = 397319
PixelFormat24bppRGB = 137224
PixelFormat32bppRGB = 139273
PixelFormat32bppARGB = 2498570
PixelFormat32bppPARGB = 925707
PixelFormat48bppRGB = 1060876
PixelFormat64bppARGB = 3424269
PixelFormat64bppPARGB = 29622286
PixelFormatMax = 15

常量
PixelFormat1bppIndexed 指定格式为每像素1位,进行索引。
PixelFormat4bppIndexed 指定格式为每像素4位,进行索引。
PixelFormat8bppIndexed 指定格式为每像素8位,进行索引。
PixelFormat16bppARGB1555 指定格式为每像素16位; 1位用于alpha分量,每个5位用于红色,绿色和蓝色分量。
PixelFormat16bppGrayScale 指定格式为每像素16位灰度。
PixelFormat16bppRGB555 指定格式为每像素16位;每个5位用于红色,绿色和蓝色组件。剩余的位不被使用。
PixelFormat16bppRGB565 指定格式为每像素16位;红色分量使用5位,绿色分量使用6位,蓝色分量使用5位。
PixelFormat24bppRGB 指定格式为每像素24位;每个8位用于红色,绿色和蓝色组件。
PixelFormat32bppARGB 指定格式为每像素32位;每个8位用于alpha,red,green和blue组件。
PixelFormat32bppPARGB 指定格式为每像素32位;每个8位用于alpha,red,green和blue组件。红色,绿色和蓝色组件根据Alpha组件预乘。
PixelFormat32bppRGB 指定格式为每像素32位;每个8位用于红色,绿色和蓝色组件。剩余的8位不被使用。
PixelFormat48bppRGB 指定格式为每像素48位;红色,绿色和蓝色组件都使用16位。
PixelFormat64bppARGB 指定格式为每像素64位; 16位用于alpha,red,green和blue组件。
PixelFormat64bppPARGB 指定格式为每像素64位; 16位用于alpha,red,green和blue组件。红色,绿色和蓝色组件根据Alpha组件预乘。

备注
PixelFormat48bppRGB,PixelFormat64bppARGB和PixelFormat64bppPARGB每个颜色组件(通道)使用16位。Microsoft Windows GDI+版本1.0可以读取每通道16位图像,但是这些图像将被转换为每通道8位格式进行处理,显示和保存。
#10
schtg2023-09-09 18:36
回复 9楼 吹水佬
@吹版主,可否给一点示例,谢谢!
#11
sam_jiang2023-09-09 20:13
回复 9楼 吹水佬
​​Declare​​​​Function​​​​GdipCreateBitmapFromScan0 ​​​​Lib​​​​"gdiplus"​​​​(​​​​ByVal​​​​Width ​​​​As​​​​Long​​​​, ​​​​ByVal​​​​Height ​​​​As​​​​Long​​​​, ​​​​ByVal​​​​stride ​​​​As​​​​Long​​​​, ​​​​ByVal​​​​PixelFormat ​​​​As​​​​Long​​​​, scan0 ​​​​As​​​​Any, bitmap ​​​​As​​​​Long​​​​) ​​​​As​​​​GpStatus​​

这个scan0,有点头疼,是个指针,vfp里面处理好像比较麻烦。能不能详细介绍一下用法?网上搜的其他语言的毕竟看着有点吃力。
#12
吹水佬2023-09-09 22:15
简单试了一下,灰度无效?
程序代码:

**
** 屏幕截图
**
DECLARE long GetDC     IN user32 long
DECLARE long ReleaseDC IN user32 long,long

DECLARE long CreateCompatibleDC     IN gdi32 long
DECLARE long DeleteDC               IN gdi32 long
DECLARE long CreateCompatibleBitmap IN gdi32 long,long,long
DECLARE long SelectObject           IN gdi32 long,long
DECLARE long DeleteObject           IN gdi32 long
DECLARE long BitBlt                 IN gdi32 long,long,long,long,long,long,long,long,long

DECLARE long GdiplusStartup              IN gdiplus long@,string@,long
DECLARE long GdiplusShutdown             IN gdiplus long
DECLARE long GdipCreateBitmapFromHBITMAP IN gdiplus long,long,long@
DECLARE long GdipCreateBitmapFromScan0   IN gdiplus long,long,long,long,string@,long@
DECLARE long GdipGetImageGraphicsContext IN gdiplus long, long@
DECLARE long GdipDrawImageRectI          IN gdiplus long, long, long, long, long, long
DECLARE long GdipSaveImageToFile         IN gdiplus long,string,string,long
DECLARE long GdipDisposeImage            IN gdiplus long
DECLARE long GdipDeleteGraphics          IN gdiplus long

** Gdipluspixelformats.h
#define PixelFormat1bppIndexed       0x030101  &&每像素1位,进行索引。
#define PixelFormat4bppIndexed       0x030402  &&每像素4位,进行索引。
#define PixelFormat8bppIndexed       0x030803  &&每像素8位,进行索引。
#define PixelFormat16bppGrayScale    0x101004  &&每像素16位灰度。
#define PixelFormat16bppRGB555       0x021005  &&每像素16位;每个5位用于红色,绿色和蓝色组件。剩余的位不被使用。
#define PixelFormat16bppRGB565       0x021006  &&每像素16位;红色分量使用5位,绿色分量使用6位,蓝色分量使用5位。
#define PixelFormat16bppARGB1555     0x061007  &&每像素16位;1位用于alpha分量,每个5位用于红色,绿色和蓝色分量。
#define PixelFormat24bppRGB          0x021808  &&每像素24位;每个8位用于红色,绿色和蓝色组件。
#define PixelFormat32bppRGB          0x022009  &&每像素32位;每个8位用于红色,绿色和蓝色组件。剩余的8位不被使用。
#define PixelFormat32bppARGB         0x26200A  &&每像素32位;每个8位用于alpha,red,green和blue组件。
#define PixelFormat32bppPARGB        0x0E200B  &&每像素32位;每个8位用于alpha,red,green和blue组件。红色,绿色和蓝色组件根据Alpha组件预乘。
#define PixelFormat48bppRGB          0x10300C  &&每像素48位;红色,绿色和蓝色组件都使用16位。
#define PixelFormat64bppARGB         0x34400D  &&每像素64位;16位用于alpha,red,green和blue组件。
#define PixelFormat64bppPARGB        0x1C4000E &&每像素64位;16位用于alpha,red,green和blue组件。红色,绿色和蓝色组件根据Alpha组件预乘。

* 初始化GDI
stGSI = 0h01000000000000000000000000000000
lpGDI = 0
GdiplusStartup(@lpGDI, @stGSI, 0)
screenshot(0, "d:\temp\tmp_黑白.bmp", 0, 0, 1000, 500, PixelFormat1bppIndexed)
screenshot(0, "d:\temp\tmp_灰度.bmp", 0, 0, 1000, 500, PixelFormat16bppGrayScale)
screenshot(0, "d:\temp\tmp_彩色.bmp", 0, 0, 1000, 500, PixelFormat32bppARGB)
MESSAGEBOX("截图完成")
GdiplusShutdown(lpGDI)
CLEAR DLLS
RETURN

FUNCTION screenshot(hWnd, outFile, X, Y, nWidth, nHeight, nPixelFormat)
    IF !DIRECTORY(JUSTPATH(outFile))
        MESSAGEBOX("无效的输出文件路径")
        RETURN .F.
    ENDIF
    * 图像GUID
    LOCAL cExt, GUID
    cExt = LOWER(JUSTEXT(outFile))
    GUID = ICASE(cExt == "bmp", 0h00,;
                 cExt == "jpg", 0h01,;
                 cExt == "gif", 0h02,;
                 cExt == "tif", 0h05,;
                 cExt == "png", 0h06, "")
    IF ("" == GUID)
        MESSAGEBOX("无效的输出文件名")
        RETURN .F.
    ENDIF
    GUID = GUID + 0hF47C55041AD3119A730000F81EF32E
        * 获取图像设备句柄
    LOCAL hDC  
    hDC = GetDC(hWnd)
    IF (hDC == 0)
        MESSAGEBOX("获取图像设备句柄失败")
        RETURN .F.
    ENDIF
        * 获取截图设备句柄
    LOCAL hppDC, hBitmap, pBitmap
    hppDC   = CreateCompatibleDC(hDC)
    hBitmap = CreateCompatibleBitmap(hDC, nWidth, nHeight)
        * 获取截图
    SelectObject(hppDC, hBitmap)
    BitBlt(hppDC, 0, 0, nWidth, nHeight, hDC, X, Y, 0xCC0020)  && SRCCOPY
    pBitmap = 0
    GdipCreateBitmapFromHBITMAP(hBitmap, 2, @pBitmap)
        * 转换格式
    pBitmapScan = 0
    GdipCreateBitmapFromScan0(nWidth, nHeight, 0, nPixelFormat, 0, @pBitmapScan)
    pGraphics = 0
    GdipGetImageGraphicsContext(pBitmapScan, @pGraphics)
    GdipDrawImageRectI(pGraphics, pBitmap, 0, 0, nWidth, nHeight)
        * 保存截图
    outFile = STRCONV(outFile + 0h00, 5)
    GdipSaveImageToFile(pBitmapScan, outFile, GUID, 0)
        * 释放资源
    GdipDeleteGraphics(pGraphics)
    GdipDisposeImage(pBitmapScan)
    GdipDisposeImage(pBitmap)
    DeleteObject(hBitmap)
    DeleteDC(hppDC)
    ReleaseDC(hWnd, hDC)
    RETURN .T.
ENDFUNC
#13
schtg2023-09-10 05:40
回复 12楼 吹水佬
谢谢吹版主!
#14
sam_jiang2023-09-10 08:55
是的,灰度图出错了。
#15
asdf_1230002023-09-18 20:25
#16
nbwww2023-12-28 16:43
回复 12楼 吹水佬


[此贴子已经被作者于2023-12-28 18:49编辑过]

1