批处理之家's Archiver

happy886rr 发表于 2017-5-17 21:35

命令行截屏工具kping发布

[i=s] 本帖最后由 happy886rr 于 2017-5-18 19:13 编辑 [/i]

Kping [最新升级版 v1.1]修复个别漏洞,请下载附件7KB。
命令行截屏工具,最大支持9参数截屏,参数输入多少不限,智能高速截屏,自动位深处理,支持多种格式输出,强悍无与伦比。代码经过高度优化,比QQ截图更清晰,速度更快,虽然不是鼠标类截图,但适合批处理高速调用,高质量截屏。

[quote]
附件下载:1.1版[attach]10633[/attach]
[img]http://i4.buimg.com/1949/f8a86cc81ecd54d7.png[/img]

摘要:
=============================================================================
命令行截图工具,支持截图位深1、4、8、16、32、48、64,可选保存格式有bmp、jpg、
png、gif、tif等;支持多种附件参数,如截图延时、截图间隔、截图尺寸、截图起始位
置等。
=============================================================================

用法:
kping [-选项] [选项对应的参数] ...
   -n  截图数
   -o  输出图像名称
   -b  图像位深度
   -d  延迟时间
   -t  屏幕截图间隔时间
   -x  截图开始的x坐标
   -y  截图开始的y坐标
   -w  屏幕截图的宽度
   -h  屏幕截图的高度

举例:[code]
REM 延迟100毫秒之后开始截图,每隔8毫秒截屏一次,共截图64张,保存为bmp八位图,截图开始坐标点(100,200), 截图宽度:800、截图高度:320。
kping -d100 -t8 -n64 -otest.bmp -b8 -x100 -y200 -w800 -h320

REM 当然也支持省参数截屏,写几个参数都行
kping -o.bmp
[/code][/quote]

源码:(支持各类编译器编译,支持宽窄字符各版本编译;由于GDI是win下的库,暂时不支持linux平台,但后期升级将会支持linux和arm手机平台)[code]
/*
        CONSOLE SCREENSHOT TOOL, COPYRIGHT@2017~2019 BY LEO, VERSION 1.1
        KPING.EXE
        LINK GDI32 GDIPLUS SHLWAPI USER32

        UNICODE COMPILATION:
        --> G++ kping.cpp -lgdi32 -lgdiplus -D _UNICODE -D UNICODE -municode -O2 -static
        --> CL  kping.cpp /O2 /Oy- /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /MD

        ANSI COMPILATION:
        --> G++ kping.cpp -lgdi32 -lgdiplus -O2 -static
        --> CL  kping.cpp /O2 /Oy- /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /MD
*/
#include <stdio.h>
#include <windows.h>
#include <tchar.h>
#include <io.h>

#ifndef _FILE_EXIST
#define _FILE_EXIST 0
#endif

#if defined _MSC_VER
#include <gdiplus.h>
#pragma comment(lib, "gdi32.lib")
#pragma comment(lib, "gdiplus.lib")
#pragma comment(lib, "user32.lib")
#else
//兼容MINGW32
#include <gdiplus\gdiplus.h>
#endif

#ifndef _UNICODE
#define TCHARFORMAT CHAR
#else
#define TCHARFORMAT WCHAR
#endif

//GDI+命名空间
using namespace Gdiplus;

//定义帮助说明
#define HELP_INFORMATION "\
kping v1.1 - Screenshot Tool - Copyright (C) 2017-2019 By Leo\n\
Usage: kping {[option] [parameter]} \n\
\n\
General options:\n\
  -n   The number of screenshots\n\
  -o   Output image name\n\
  -b   Image bit depth\n\
  -d   Delay time\n\
  -t   Screenshot interval time\n\
  -x   The x-coordinate of the beginning of the screenshot\n\
  -y   The y-coordinate of the beginning of the screenshot\n\
  -w   The width of the screenshots\n\
  -h   The height of the screenshots\n\
\n\
Official website:\n\
       http://www.bathome.net/thread-44149-1-1.html\n"

#define FILE_EXIST 0

//定义位深度枚举
INT BITDEEP[65] = {0,PixelFormat1bppIndexed,0,0,PixelFormat4bppIndexed,0,0,0,PixelFormat8bppIndexed,0,0,0,0,0,0,0,PixelFormat16bppRGB555,0,0,0,0,0,0,0,PixelFormat24bppRGB,0,0,0,0,0,0,0,PixelFormat32bppARGB,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,PixelFormat48bppRGB,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,PixelFormat64bppARGB};

//定义截图区域结构体
typedef struct
{
        int startX;
        int startY;
        int capWITH;
        int capHIGH;
} PAREA;

//开关解析
int OPTIND=1, OPTOPT;
TCHAR* OPTARG;
int _tgetopt(int nargc, TCHAR* nargv[], TCHAR* ostr)
{
        static TCHAR* place=(TCHAR*)_T("");
        static TCHAR* lastostr=NULL;
        register TCHAR* oli;

        if(ostr!=lastostr)
        {
                lastostr=ostr;
                place=(TCHAR*)_T("");
        }

        if(!*place)
        {
                if(
                    (OPTIND>=nargc)                  ||
                    (*(place=nargv[OPTIND])!=(TCHAR)_T('-'))||
                    (!*(++place))
                )
                {
                        place=(TCHAR*)_T("");
                        return _TEOF;
                }
                if (*place == (TCHAR)_T('-') && *(place+1) == (TCHAR)_T('\0'))
                {
                        ++OPTIND;
                        return _TEOF;
                }
        }

        if (
            (OPTOPT=*place++)==(TCHAR)_T(':') ||
            !(oli=(TCHAR*)_tcschr((TCHARFORMAT*)ostr, (TCHAR)OPTOPT))
        )
        {
                if(!*place)
                {
                        ++OPTIND;
                }
        }

        if (oli != NULL && *(++oli) != (TCHAR)_T(':'))
        {
                OPTARG=NULL;
                if(!*place)
                {
                        ++OPTIND;
                }
        }
        else
        {
                if(*place)
                {
                        OPTARG=place;
                }
                else if(nargc<=++OPTIND)
                {
                        place=(TCHAR*)_T("");
                }
                else
                {
                        OPTARG=nargv[OPTIND];
                }
                place=(TCHAR*)_T("");
                ++OPTIND;
        }
        return OPTOPT;
}

//获取编码器CLSID
BOOL GetEncoderClsid(TCHAR* expNAME, CLSID* pClsid)
{
        UINT n=0, s=0;
        ImageCodecInfo* pInfo=NULL;
        GetImageEncodersSize(&n, &s);
        if(s==0)
        {
                return FALSE;
        }
        pInfo=(ImageCodecInfo*)(malloc(s));
        if(pInfo==NULL)
        {
                return FALSE;
        }
        GetImageEncoders(n, s, pInfo);
        for(UINT i=0; i<n; i++)
        {
                if(lstrlen(expNAME)<2 || *expNAME==_T('\0'))
                {
                        ;
                }
                else if(
                    *(pInfo[i].MimeType+6) == *expNAME     &&
                    *(pInfo[i].MimeType+7) == *(expNAME+1)
                )
                {
                        *pClsid=pInfo[i].Clsid;
                        free(pInfo);
                        return TRUE;
                }
        }
        free(pInfo);
        return FALSE;
}

//截图核心
int CaptureScreenToImage(TCHAR* srcNAME, PAREA* inpa, int imgBIT, int intervalTIME, int countNUM)
{
        //切分文件名
        TCHAR *imgNAME=NULL, *outDIR=NULL, *expNAME=NULL, *lpwstr=(TCHAR*)_tcsrchr((TCHARFORMAT*)srcNAME, _T('\\'));
        if(lpwstr==NULL)
        {
                outDIR =(TCHAR*)_T(".\\");
                imgNAME = srcNAME;
        }
        else
        {
                *lpwstr=_T('\0'), outDIR=srcNAME, imgNAME=++lpwstr;
                if(_taccess((TCHARFORMAT*)outDIR, _FILE_EXIST) != 0)
                {
                        _ftprintf(stderr, _T("The outdir don't exist\n"));
                        exit(1);
                }
        }
        lpwstr=(TCHAR*)_tcsrchr((TCHARFORMAT*)imgNAME, _T('.'));
        if(lpwstr==NULL)
        {
                _ftprintf(stderr, _T("Wrong image output format\n"));
                exit(1);
        }
        else
        {
                *lpwstr=_T('\0'), expNAME = ++lpwstr;
        }

        //获取桌面HWND句柄
        HWND hDSK=GetDesktopWindow();
        //获取桌面DC
        HDC  hDC =GetDC(hDSK);
        //创建兼容桌面DC
        HDC  pDC =CreateCompatibleDC(hDC);
        //创建兼容位图
        HBITMAP pHBITMAP =CreateCompatibleBitmap(hDC, inpa->capWITH, inpa->capHIGH);
        //绑定兼容DC与位图
        HGDIOBJ preOBJ   =SelectObject(pDC, pHBITMAP);

        //获取编码器
        CLSID clsid;
        if(! GetEncoderClsid(expNAME, &clsid))
        {
                _ftprintf(stderr, _T("Encode image failed\n"));
                exit(1);
        }

        //申请动态内存
        TCHAR* outNAME =new TCHAR[_MAX_PATH];

#ifndef UNICODE
        WCHAR* outNAMEW=new WCHAR[_MAX_PATH];
#endif

        //进入截图主循环
        for(int i=1; i<= countNUM; i++)
        {
                //编号文件名
                _stprintf((TCHARFORMAT*)outNAME, _T("%s\\%s%03d.%s"), outDIR, imgNAME, i, expNAME);

                //开始捕获屏幕
                BitBlt(pDC, 0, 0, inpa->capWITH, inpa->capHIGH, hDC, inpa->startX, inpa->startY, SRCCOPY);

                //HBITMAP转Bitmap
                Bitmap* bitIMG=new Bitmap(pHBITMAP, NULL);

                //位化深度
                Bitmap* covIMG=bitIMG->Clone(0, 0, inpa->capWITH, inpa->capHIGH, imgBIT);

                //保存截屏
#ifndef UNICODE
                int wLen=MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, outNAME, -1, NULL, 0);
                MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, outNAME, -1, outNAMEW, wLen);
                outNAMEW[wLen]='\0';
                if(covIMG->Save((LPCWSTR)outNAMEW, &clsid, NULL) != S_OK)
#else
                if(covIMG->Save((LPCWSTR)outNAME,  &clsid, NULL) != S_OK)
#endif
                {
                        _ftprintf(stderr, _T("Save image failed\n"));
                        exit(1);
                }

                //局部释放
                delete bitIMG;
                delete covIMG;

                //间隔时间
                Sleep(intervalTIME);
        }

        //释放动态内存
        delete outNAME;

#ifndef UNICODE
        delete outNAMEW;
#endif

        //释放DC与绑定,恢复之前模式
        DeleteDC(pDC);
        DeleteDC(hDC);
        SelectObject(pDC, preOBJ);

        return 0;
}

#if defined _MSC_VER
#else
//兼容MINGW32
extern "C"
#endif

//主函数入口
int _tmain(int argc, TCHAR** argv)
{
        if(argc<2)
        {
                //无参数则退出
                fprintf(stdout, HELP_INFORMATION);
                exit(0);
        }

        //设置传入参数
        TCHAR* srcNAME=NULL;
        INT K=-1, countNUM=1, imgBIT=PixelFormat32bppARGB, delayTIME=0, intervalTIME=0;
        PAREA pmi= {0}, *inpa=&pmi;

        //开关解析
        while((K=_tgetopt(argc, argv, (TCHAR*)_T("n:b:t:d:r:o:x:y:w:h:N:B:T:D:R:O:X:Y:W:H:")))!=_TEOF)
        {
                switch(K)
                {
                case 'n':
                case 'N':
                        if(OPTARG !=NULL)
                        {
                                countNUM=_ttoi((TCHARFORMAT*)OPTARG);
                                if(countNUM <1)
                                {
                                        _ftprintf(stderr, _T("The number of screenshots can't be less than 1\n"));
                                        exit(1);
                                }
                        }
                        break;

                case 't':
                case 'T':
                        if(OPTARG !=NULL)
                        {
                                intervalTIME=_ttoi((TCHARFORMAT*)OPTARG);
                                if(intervalTIME <0)
                                {
                                        _ftprintf(stderr, _T("The interval time can't be less than 0\n"));
                                        exit(1);
                                }
                        }
                        break;

                case 'd':
                case 'D':
                        if(OPTARG !=NULL)
                        {
                                delayTIME =_ttoi((TCHARFORMAT*)OPTARG);
                                if(delayTIME <0)
                                {
                                        _ftprintf(stderr, _T("The waiting time can't be less than 0\n"));
                                        exit(1);
                                }
                        }
                        break;

                case 'o':
                case 'O':
                        srcNAME=OPTARG;
                        break;

                case 'b':
                case 'B':
                        if(OPTARG !=NULL)
                        {
                                int i =_ttoi((TCHARFORMAT*)OPTARG);
                                if(i<0 || 64<i)
                                {
                                        _ftprintf(stderr, _T("Wrong bit depth\n"));
                                        exit(1);
                                }
                                imgBIT=BITDEEP[i];
                        }
                        break;

                case 'x':
                case 'X':
                        if(OPTARG !=NULL)
                        {
                                inpa->startX =_ttoi((TCHARFORMAT*)OPTARG);
                                if(inpa->startX <0)
                                {
                                        _ftprintf(stderr, _T("The swith '-x' Need a positive number\n"));
                                        exit(1);
                                }
                        }
                        break;

                case 'y':
                case 'Y':
                        if(OPTARG !=NULL)
                        {
                                inpa->startY =_ttoi((TCHARFORMAT*)OPTARG);
                                if(inpa->startY <0)
                                {
                                        _ftprintf(stderr, _T("The swith '-y' Need a positive number\n"));
                                        exit(1);
                                }
                        }
                        break;

                case 'w':
                case 'W':
                        if(OPTARG !=NULL)
                        {
                                inpa->capWITH =_ttoi((TCHARFORMAT*)OPTARG);
                                if(inpa->capWITH <0)
                                {
                                        _ftprintf(stderr, _T("The swith '-w' Need a positive number\n"));
                                        exit(1);
                                }
                        }
                        break;

                case 'h':
                case 'H':
                        if(OPTARG !=NULL)
                        {
                                inpa->capHIGH =_ttoi((TCHARFORMAT*)OPTARG);
                                if(inpa->capHIGH <0)
                                {
                                        _ftprintf(stderr, _T("The swith '-h' Need a positive number"));
                                        exit(1);
                                }
                        }
                        break;

                default:
                        _ftprintf(stderr, _T("Unknown switch '-%c'\n"), K);
                        exit(1);
                }
        }

        if(srcNAME == NULL)
        {
                _ftprintf(stderr, _T("Needs output image name\n"));
                exit(1);
        }

        //初始化GDI+
        GdiplusStartupInput gdiplusstartupinput;
        ULONG_PTR gdiplustoken;
        GdiplusStartup(&gdiplustoken, &gdiplusstartupinput, NULL);

        //获取屏幕尺寸
        PAREA srcPAREA=
        {
                GetSystemMetrics(SM_XVIRTUALSCREEN),
                GetSystemMetrics(SM_YVIRTUALSCREEN),
                GetSystemMetrics(SM_CXVIRTUALSCREEN),
                GetSystemMetrics(SM_CYVIRTUALSCREEN)

        }, *ps=&srcPAREA;

        //当参数缺省时 修正截图区域
        if(inpa->capWITH==0)
        {
                inpa->capWITH = ps->capWITH - inpa->startX;
        }
        if(inpa->capHIGH==0)
        {
                inpa->capHIGH = ps->capHIGH - inpa->startY;
        }

        //执行等待
        Sleep(delayTIME);

        //截图核心
        CaptureScreenToImage((LPTSTR)srcNAME, inpa, imgBIT, intervalTIME, countNUM);

        //关闭GDI+
        GdiplusShutdown(gdiplustoken);
        return 0;
}
[/code]

phunsukh 发表于 2017-5-21 21:54

开源,   666

HUIANG 发表于 2017-5-23 11:30

不错,不错

页: [1]

Powered by Discuz! Archiver 7.2  © 2001-2009 Comsenz Inc.