左键拖动选择屏幕范围 v1

/*
------------------------------------------
  左键拖动选择屏幕范围 v1.5  By FeiYue

  说明:
      按热键“F1”开始左键拖动选择范围,
      然后点击范围确定,点其他位置取消
------------------------------------------
*/

F1:: MsgBox, 4096,, % GetRange(x,y,w,h) "范围:" x "," y "," w "," h

F2::         ;保存图片
file := A_ScriptDir . "\test.png"
GetRange(x,y,w,h)
SaveScreenshotToFile(x,y,w,h, file, Cursor:=1)
; SaveScreenshotToFile(0, 0, A_ScreenWidth, A_ScreenHeight, file, Cursor:=1)
Run, % file
return




GetRange(ByRef x="",ByRef y="",ByRef w="",ByRef h="")
{
  Hotkey, *LButton, LButton_Return, On
  CoordMode, Mouse
  Ptr:=A_PtrSize ? "UPtr":"UInt", int:="int"
  nW:=A_ScreenWidth, nH:=A_ScreenHeight





  ;-- 生成画布窗口和选框窗口
  Gui, Canvas:New, +AlWaysOnTop +ToolWindow -Caption -DPIScale
  Gui, Canvas:Add, Picture, x0 y0 w%nW% h%nH% +0xE HwndpicID
  range_create("Red","Canvas")





  ;-- 截屏到内存图像并关联到画布窗口的图片控件
  hDC:=DllCall("GetDC", Ptr,0, Ptr)
  mDC:=DllCall("CreateCompatibleDC", Ptr,hDC, Ptr)
  hBM:=DllCall("CreateCompatibleBitmap", Ptr,hDC, int,nW, int,nH, Ptr)
  oBM:=DllCall("SelectObject", Ptr,mDC, Ptr,hBM, Ptr)
  DllCall("BitBlt", Ptr,mDC, int,0, int,0, int,nW, int,nH
    , Ptr,hDC, int,0, int,0, int,0x00CC0020|0x40000000)
  SendMessage, 0x172, 0, hBM,, ahk_id %picID%
  if ( E:=ErrorLevel )
    DllCall("DeleteObject", Ptr,E)
  DllCall("SelectObject", Ptr,mDC, Ptr,oBM)
  DllCall("DeleteDC", Ptr,mDC)
  DllCall("ReleaseDC", Ptr,0, Ptr,hDC)




  ;-- 显示画布窗口,开始等待选择范围
  Gui, Canvas:Show, NA x0 y0 w%nW% h%nH%
  ok:=w:=h:=0
  ListLines, Off
  Loop {
    Sleep, 100
    MouseGetPos, x2, y2
    if GetkeyState("LButton","P")!=ok
    {
      ToolTip
      ok:=!ok, x1:=x2, y1:=y2
      if (ok and x2>x and y2>y and x2<x+w-1 and y2<y+h-1)
        Break
    }
    if (ok=0)
    {
      ToolTip, % w+h>5 ? "点击范围确定,点其他位置取消"
        : "请按下鼠标左键并拖动选择范围"
      Continue
    }
    x:=x1<x2 ? x1:x2, y:=y1<y2 ? y1:y2
    w:=Abs(x1-x2)+1, h:=Abs(y1-y2)+1
    if (w+h>5)
      range_show(x,y,w,h)
    else
      range_hide()
  }
  ListLines, On
  range_delete()
  Gui, Canvas:Destroy




  ;-- 不需要了才清除内存图像
  DllCall("DeleteObject", Ptr,hBM)

  KeyWait, LButton
  Hotkey, *LButton, LButton_Return, Off
  LButton_Return:
  Return
}




range_create(color="Red", Owner="") {
  j:=Owner ? "+Owner" Owner : "+ToolWindow"
  Loop 4 {
    i:=A_Index
    Gui,range_%i%:+AlWaysOnTop -Caption %j% -DPIScale +E0x08000000
    Gui,range_%i%:Color, %color%
  }
  Gui, Range:+LastFound +AlWaysOnTop -Caption %j% -DPIScale +E0x08000000
  WinSet, Transparent, 50
  Gui, Range:Color, Yellow
}




range_show(x, y, w, h, r:=2) {
  Loop 4 {  ; 顺时针上右下左
    i:=A_Index
    , x1:=i=2 ? x+w-r : x
    , y1:=i=3 ? y+h-r : y
    , w1:=i=1 or i=3 ? w : r
    , h1:=i=1 or i=3 ? r : h
    Gui, range_%i%:Show, NA x%x1% y%y1% w%w1% h%h1%
  }
  x+=r, y+=r, w-=2*r, h-=2*r
  Gui, Range:Show, NA x%x% y%y% w%w% h%h%
}



range_hide() {
  Loop 4
    Gui, range_%A_Index%:Hide
  Gui, Range:Hide
}



range_delete() {
  Loop 4
    Gui, range_%A_Index%:Destroy
  Gui, Range:Destroy
}



;

;------------------------
;  截屏代码
;------------------------

SaveScreenshotToFile(x, y, w, h, filePath, captureCursor:=false)
{
   gdip := new GDIplus
   hBitmap:=GetHBitmapFromScreen(x, y, w, h, captureCursor)
   pBitmap := gdip.BitmapFromHBitmap(hBitmap)
   DllCall("DeleteObject", Ptr, hBitmap)
   gdip.SaveBitmapToFile(pBitmap, filePath)
   gdip.DisposeImage(pBitmap)
}

GetHBitmapFromScreen(x, y, w, h, captureCursor)  {
   hDC := DllCall("GetDC", Ptr, 0, Ptr)
   hBM := DllCall("CreateCompatibleBitmap", Ptr, hDC, Int, w, Int, h, Ptr)
   pDC := DllCall("CreateCompatibleDC", Ptr, hDC, Ptr)
   oBM := DllCall("SelectObject", Ptr, pDC, Ptr, hBM, Ptr)
   DllCall("BitBlt", Ptr, pDC, Int, 0, Int, 0, Int, w, Int, h
     , Ptr, hDC, Int, x, Int, y, UInt, 0x00CC0020)
   ( captureCursor && CaptureCursor(pDC, x, y) )
   DllCall("SelectObject", Ptr, pDC, Ptr, oBM)
   DllCall("DeleteDC", Ptr, pDC)
   DllCall("ReleaseDC", Ptr, 0, Ptr, hDC)
   Return hBM  ; should be deleted with DllCall("DeleteObject", Ptr, hBM)
}

CaptureCursor(hDC, x, y)  {
   VarSetCapacity(CURSORINFO, szCI := 4*2 + A_PtrSize + 8, 0)
   NumPut(szCI, CURSORINFO)
   DllCall("GetCursorInfo", Ptr, &CURSORINFO)
   bShow   := NumGet(CURSORINFO, 4, "UInt")
   hCursor := NumGet(CURSORINFO, 4*2)
   xCursor := NumGet(CURSORINFO, 4*2 + A_PtrSize, "Int")
   yCursor := NumGet(CURSORINFO, 4*2 + A_PtrSize + 4, "Int")

   if bShow && hCursor := DllCall("CopyIcon", Ptr, hCursor, Ptr)
   {
      VarSetCapacity(ICONINFO, 4*2 + A_PtrSize*3, 0)
      DllCall("GetIconInfo", Ptr, hCursor, Ptr, &ICONINFO)
      bIcon    := NumGet(ICONINFO, "UInt")
      xHotspot := NumGet(ICONINFO, 4, "UInt")
      yHotspot := NumGet(ICONINFO, 4*2, "UInt")
      hBMMask  := NumGet(ICONINFO, 4*2 + A_PtrSize)
      hBMColor := NumGet(ICONINFO, 4*2 + A_PtrSize*2)

      DllCall("DrawIcon", Ptr, hDC, Int, xCursor - xHotspot - x
        , Int, yCursor - yHotspot - y, Ptr, hCursor)
      DllCall("DestroyIcon", Ptr, hCursor)
      ( hBMMask && DllCall("DeleteObject", Ptr, hBMMask) )
      ( hBMColor && DllCall("DeleteObject", Ptr, hBMColor) )
   }
}

class GDIplus   {
   __New()  {
      if !DllCall("GetModuleHandle", Str, "gdiplus", Ptr)
         DllCall("LoadLibrary", Str, "gdiplus")
      VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), NumPut(1,si,"char")
      DllCall("gdiplus\GdiplusStartup", PtrP, pToken, Ptr, &si, Ptr, 0)
      this.token := pToken
   }
   
   __Delete()  {
      DllCall("gdiplus\GdiplusShutdown", Ptr, this.token)
      if hModule := DllCall("GetModuleHandle", Str, "gdiplus", Ptr)
         DllCall("FreeLibrary", Ptr, hModule)
   }
   
   BitmapFromHBitmap(hBitmap, Palette := 0)  {
      DllCall("gdiplus\GdipCreateBitmapFromHBITMAP"
        , Ptr, hBitmap, Ptr, Palette, PtrP, pBitmap)
      return pBitmap  ; should be deleted with this.DisposeImage(pBitmap)
   }
   
   SaveBitmapToFile(pBitmap, sOutput, Quality=75)  {
      SplitPath, sOutput,,, Extension
      if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
         return -1

      DllCall("gdiplus\GdipGetImageEncodersSize", UIntP, nCount, UIntP, nSize)
      VarSetCapacity(ci, nSize)
      DllCall("gdiplus\GdipGetImageEncoders", UInt, nCount, UInt, nSize, Ptr, &ci)
      if !(nCount && nSize)
         return -2
      
      Loop, % nCount  {
         idx := (48+7*A_PtrSize)*(A_Index-1)
         sString := StrGet(NumGet(ci, idx+32+3*A_PtrSize), "UTF-16")
         if !InStr(sString, "*." Extension)
            continue
         pCodec := &ci+idx
         break
      }
      
      if !pCodec
         return -3

      if RegExMatch(Extension, "i)^J(PG|PEG|PE|FIF)$") && Quality != 75
      {
         DllCall("gdiplus\GdipGetEncoderParameterListSize"
           , Ptr, pBitmap, Ptr, pCodec, UintP, nSize)
         VarSetCapacity(EncoderParameters, nSize, 0)
         DllCall("gdiplus\GdipGetEncoderParameterList"
           , Ptr, pBitmap, Ptr, pCodec, UInt, nSize, Ptr, &EncoderParameters)
         Loop, % NumGet(EncoderParameters, "UInt")  {
            elem := (24+A_PtrSize)*(A_Index-1) + 4 + (pad := A_PtrSize = 8 ? 4 : 0)
            if (NumGet(EncoderParameters, elem+16, "UInt") = 1)
            && (NumGet(EncoderParameters, elem+20, "UInt") = 6)
            {
               p := elem+&EncoderParameters-pad-4
               NumPut(Quality, NumGet(NumPut(4, NumPut(1, p+0)+20, "UInt")), "UInt")
               break
            }
         }      
      }
      
      if A_IsUnicode
         pOutput := &sOutput
      else  {
         VarSetCapacity(wOutput, StrPut(sOutput, "UTF-16")*2, 0)
         StrPut(sOutput, &wOutput, "UTF-16")
         pOutput := &wOutput
      }
      E := DllCall("gdiplus\GdipSaveImageToFile"
        , Ptr, pBitmap, Ptr, pOutput, Ptr, pCodec, UInt, p ? p : 0)
      return E ? -5 : 0
   }
   
   DisposeImage(pBitmap)  {
      return DllCall("gdiplus\GdipDisposeImage", Ptr, pBitmap)
   }
}

给TA捐赠
共{{data.count}}人
人已捐赠
其他

最小化移出屏幕任务栏激活归位

2021-12-2 16:19:16

其他

左键选中复制2

2021-12-2 16:19:29

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索