• 浏览器截图

  • 如果只是下个截取可视区域的图片,可以用下面代码:

       window.RunOnMainThread(func() {
                dc := rtl.GetDC(0)
                // 一定要释放
                defer rtl.ReleaseDC(0, dc)
    
                // 位图
                bmp := lcl.NewBitmap()
                defer bmp.Free()
                bmp.LoadFromDevice(dc)
    
                // 可以 保存到本地 bmp
                wd := consts.CurrentExecuteDir
                bmp.SaveToFile(filepath.Join(wd, "sc.bmp"))
    
                // 可以 显示截屏图片窗口
                if schotForm != nil {
                    schotForm.Show()
                    image.Picture().Assign(bmp)
                }
            })



    如果想截取完整页面,需要用osr模式 的bufferPanel ,获取完整页面截图:

    // 创建 bufferPanel
    bufferPanel := cef.NewBufferPanel(Sbox)
    bufferPanel.SetCaption(caption)
    
    bufferPanel.SetParent(Sbox)
    bufferPanel.SetColor(colors.ClAqua)
    
    // 这里设置的宽高还未生效,chromium.SetOnGetViewRect 函数里设置生效
    bufferPanel.SetTop(0)
    bufferPanel.SetLeft(int32(iPos)*(kuandu+1) + 1)
    bufferPanel.SetWidth(kuandu)
    bufferPanel.SetHeight(1000)
    bufferPanel.SetAnchors(types.NewSet(types.AkTop, types.AkLeft))
    
    // 如果用户不需要“输入法编辑器”,则可以跳过此操作
    bufferPanel.CreateIMEHandler()
    
    bufferPanel.Show()


    我们需要截图的时候,这样:

    BS[iBs].bufferPnl.SaveToFile(jj.Appdir() + "img/" + jj.ToS(iBs) + ".png")



    OSR一些需要初始化的事件:

    // 获取修改器
    func getModifiers(shift types.TShiftState) consts.TCefEventFlags {
       var result = consts.EVENTFLAG_NONE
       if shift.In(types.SsShift) {
          result = result | consts.EVENTFLAG_SHIFT_DOWN
       } else if shift.In(types.SsAlt) {
          result = result | consts.EVENTFLAG_ALT_DOWN
       } else if shift.In(types.SsCtrl) {
          result = result | consts.EVENTFLAG_CONTROL_DOWN
       } else if shift.In(types.SsLeft) {
          result = result | consts.EVENTFLAG_LEFT_MOUSE_BUTTON
       } else if shift.In(types.SsRight) {
          result = result | consts.EVENTFLAG_RIGHT_MOUSE_BUTTON
       } else if shift.In(types.SsMiddle) {
          result = result | consts.EVENTFLAG_MIDDLE_MOUSE_BUTTON
       }
       return result
    }
    
    // 获取点击的鼠标按钮
    func getButton(Button types.TMouseButton) (result consts.TCefMouseButtonType) {
       switch Button {
       case types.MbRight:
          result = consts.MBT_RIGHT
       case types.MbMiddle:
          result = consts.MBT_MIDDLE
       default:
          result = consts.MBT_LEFT
       }
       return
    }
    
    // 浏览器的事件
    func chromiumEvent(m *tbs) {
       var (
          popUpBitmap                  *lcl.TBitmap
          tempBitMap                   *lcl.TBitmap
          tempWidth, tempHeight        int32
          tempLineSize                 int
          tempSrcOffset, tempDstOffset int
          src, dst                     uintptr
       )
       m.chrome.SetOnLoadStart(func(sender lcl.IObject, browser *cef.ICefBrowser, frame *cef.ICefFrame, transitionType consts.TCefTransitionType) {
          //fmt.Println("SetOnLoadStart", frame.Url())
       })
       m.chrome.SetOnLoadEnd(func(sender lcl.IObject, browser *cef.ICefBrowser, frame *cef.ICefFrame, httpStatusCode int32) {
          //fmt.Println("加载完毕啦", frame.Url())
          //m.bufferPnl.SaveToFile(jj.Appdir() + "img/" + jj.MD516(frame.Url()) + ".png")
    
       })
       m.chrome.SetOnCursorChange(func(sender lcl.IObject, browser *cef.ICefBrowser, cursor consts.TCefCursorHandle, cursorType consts.TCefCursorType, customCursorInfo *cef.TCefCursorInfo) bool {
          m.bufferPnl.SetCursor(cef.CefCursorToWindowsCursor(cursorType))
          return true
       })
       m.chrome.SetOnBeforePopup(func(sender lcl.IObject, browser *cef.ICefBrowser, frame *cef.ICefFrame, beforePopupInfo *cef.BeforePopupInfo, popupFeatures *cef.TCefPopupFeatures, windowInfo *cef.TCefWindowInfo, resultClient *cef.ICefClient, settings *cef.TCefBrowserSettings, resultExtraInfo *cef.ICefDictionaryValue, noJavascriptAccess *bool) bool {
          return true // 阻止弹出窗口
       })
       m.chrome.SetOnTooltip(func(sender lcl.IObject, browser *cef.ICefBrowser, text *string) (result bool) {
          //fmt.Println("SetOnTooltip", *text)
          result = true
          m.bufferPnl.SetHint(*text)
          m.bufferPnl.SetShowHint(len(*text) > 0)
          return
       })
       // 得到显示大小, 这样bufferPanel就显示实际大小
       m.chrome.SetOnGetViewRect(func(sender lcl.IObject, browser *cef.ICefBrowser) *cef.TCefRect {
          var scale = float64(m.bufferPnl.ScreenScale())
          var rect = &cef.TCefRect{}
          rect.X = 0
          rect.Y = 0
          rect.Width = cef.DeviceToLogicalInt32(m.bufferPnl.Width(), scale)
          rect.Height = cef.DeviceToLogicalInt32(m.bufferPnl.Height(), scale)
          return rect
       })
       // 获取设置屏幕信息
       m.chrome.SetOnGetScreenInfo(func(sender lcl.IObject, browser *cef.ICefBrowser) (screenInfo *cef.TCefScreenInfo, result bool) {
          var scale = float64(m.bufferPnl.ScreenScale())
          var rect = &cef.TCefRect{}
          screenInfo = new(cef.TCefScreenInfo)
          rect.Width = cef.DeviceToLogicalInt32(m.bufferPnl.Width(), scale)
          rect.Height = cef.DeviceToLogicalInt32(m.bufferPnl.Height(), scale)
          screenInfo.DeviceScaleFactor = t.Single(scale)
          screenInfo.Depth = 0
          screenInfo.DepthPerComponent = 0
          screenInfo.IsMonochrome = 0
          screenInfo.Rect = *rect
          screenInfo.AvailableRect = *rect
          result = true
          return
       })
       // 获取设置屏幕点
       m.chrome.SetOnGetScreenPoint(func(sender lcl.IObject, browser *cef.ICefBrowser, viewX, viewY int32) (screenX, screenY int32, result bool) {
          var scale = float64(m.bufferPnl.ScreenScale())
          var viewPoint = types.TPoint{}
          viewPoint.X = cef.LogicalToDeviceInt32(viewX, scale)
          viewPoint.Y = cef.LogicalToDeviceInt32(viewY, scale)
          var screenPoint = m.bufferPnl.ClientToScreen(viewPoint)
          result = true
          screenX = screenPoint.X
          screenY = screenPoint.Y
          return
       })
       //创建完毕后打开百度
       m.chrome.SetOnAfterCreated(func(sender lcl.IObject, browser *cef.ICefBrowser) {
          //m.chrome.LoadUrl("https://www.baidu.com")
       })
       m.chrome.SetOnPopupShow(func(sender lcl.IObject, browser *cef.ICefBrowser, show bool) {
          if m.chrome != nil {
             m.chrome.Invalidate(consts.PET_VIEW)
          }
       })
       m.chrome.SetOnPopupSize(func(sender lcl.IObject, browser *cef.ICefBrowser, rect *cef.TCefRect) {
          screenScale := m.bufferPnl.ScreenScale()
          fmt.Println("PopupSize - rect:", rect, "screenScale:", screenScale)
          cef.LogicalToDeviceRect(rect, float64(screenScale))
          fmt.Println("PopupSize - rect:", rect, "screenScale:", screenScale)
       })
       // windows IME
       m.chrome.SetOnIMECompositionRangeChanged(func(sender lcl.IObject, browser *cef.ICefBrowser, selectedRange *cef.TCefRange, characterBoundsCount uint32, characterBounds *cef.TCefRect) {
          fmt.Println("SetOnIMECompositionRangeChanged", *selectedRange, characterBoundsCount, *characterBounds)
       })
    
       // 在Paint内展示内容到窗口中
       // 使用 bitmap
       m.chrome.SetOnPaint(func(sender lcl.IObject, browser *cef.ICefBrowser, kind consts.TCefPaintElementType, dirtyRects *cef.TCefRectArray, buffer uintptr, width, height int32) {
    
          if m.bufferPnl.BeginBufferDraw() {
             if kind == consts.PET_POPUP {
                if popUpBitmap == nil || popUpBitmap.Width() != width || popUpBitmap.Height() != height {
                   if popUpBitmap != nil {
                      popUpBitmap.Free()
                   }
                   popUpBitmap = lcl.NewBitmap()
                   popUpBitmap.SetPixelFormat(types.Pf32bit)
                   popUpBitmap.SetHandleType(types.BmDIB)
                   popUpBitmap.SetWidth(width)
                   popUpBitmap.SetHeight(height)
                }
                tempBitMap = popUpBitmap
                tempBitMap.BeginUpdate(false)
                tempWidth, tempHeight = popUpBitmap.Width(), popUpBitmap.Height()
             } else {
                m.bufferPnl.UpdateBufferDimensions(width, height)
                m.bufferPnl.BufferIsResized(false)
                tempBitMap = m.bufferPnl.Buffer()
                tempBitMap.BeginUpdate(false)
                tempWidth = m.bufferPnl.BufferWidth()
                tempHeight = m.bufferPnl.BufferHeight()
             }
             rgbSizeOf := int(unsafe.Sizeof(cef.TRGBQuad{}))
             srcStride := int(width) * rgbSizeOf
             for i := 0; i < dirtyRects.Count(); i++ {
                rect := dirtyRects.Get(i)
                if rect.X >= 0 && rect.Y >= 0 {
                   tempLineSize = int(math.Min(float64(rect.Width), float64(tempWidth-rect.X))) * rgbSizeOf
                   if tempLineSize > 0 {
                      tempSrcOffset = int((rect.Y*width)+rect.X) * rgbSizeOf
                      tempDstOffset = int(rect.X) * rgbSizeOf
                      //src := @pbyte(buffer)[TempSrcOffset];
                      src = uintptr(common.GetParamPtr(buffer, tempSrcOffset)) // 拿到src指针, 实际是 byte 指针
                      j := int(math.Min(float64(rect.Height), float64(tempHeight-rect.Y)))
                      for ii := 0; ii < j; ii++ {
                         tempBufferBits := tempBitMap.ScanLine(rect.Y + int32(ii))
                         dst = uintptr(common.GetParamPtr(tempBufferBits, tempDstOffset)) //拿到dst指针, 实际是 byte 指针
                         rtl.Move(src, dst, tempLineSize)                                 //  也可以自己实现字节复制
                         src = src + uintptr(srcStride)
                      }
                   }
                }
             }
             tempBitMap.EndUpdate(false)
             //if FShowPopup and (FPopUpBitmap <> nil) then
             //begin
             //TempSrcRect := Rect(0, 0, min(FPopUpRect.Right - FPopUpRect.Left, FPopUpBitmap.Width), min(FPopUpRect.Bottom - FPopUpRect.Top, FPopUpBitmap.Height));
             //
             //Panel1.BufferDraw(FPopUpBitmap, TempSrcRect, FPopUpRect);
             //end;
             if popUpBitmap != nil {
    
             }
    
             m.bufferPnl.EndBufferDraw()
    
             if bw.HandleAllocated() {
                m.bufferPnl.Invalidate()
             }
          }
       })
    }
    
    // 事件
    func bufferPanelEvent(m *tbs) {
    
       m.bufferPnl.SetOnClick(func(sender lcl.IObject) {
          fmt.Println("点击了bufferPanelEvent")
          m.bufferPnl.SetFocus()
       })
       m.bufferPnl.SetOnEnter(func(sender lcl.IObject) {
          m.chrome.SetFocus(true)
       })
       m.bufferPnl.SetOnExit(func(sender lcl.IObject) {
          m.chrome.SetFocus(false)
       })
       // panel Align 设置为 client 时, 如果调整窗口大小
       // 该函数被回调, 需要调用 WasResized 调整页面同步和主窗口一样
       m.bufferPnl.SetOnResize(func(sender lcl.IObject) {
          if m.bufferPnl.BufferIsResized(false) {
             m.chrome.Invalidate(consts.PET_VIEW)
          } else {
             m.chrome.WasResized()
          }
       })
       // 鼠标移动
       m.bufferPnl.SetOnMouseMove(func(sender lcl.IObject, shift types.TShiftState, x, y int32) {
          mouseEvent := &cef.TCefMouseEvent{}
          mouseEvent.X = x
          mouseEvent.Y = y
          mouseEvent.Modifiers = getModifiers(shift)
          cef.DeviceToLogicalMouse(mouseEvent, float64(m.bufferPnl.ScreenScale()))
          m.chrome.SendMouseMoveEvent(mouseEvent, false)
       })
       var (
          // 自己简单处理一下单击·双击·时间和点击次数控制
          // 一搬使用系统的消息时间
          clickTime  int64 = 300 // N 毫秒内连续点击 = 双击
          preTime    int64 = 0
          clickCount int32
       )
       // 鼠标事件 点击按下
       m.bufferPnl.SetOnMouseDown(func(sender lcl.IObject, button types.TMouseButton, shift types.TShiftState, x, y int32) {
          fmt.Println("OnMouseDown:", clickTime, button, shift, x, y)
          if (time.Now().UnixMilli() - preTime) > clickTime {
             clickCount = 1
          } else if clickCount == 2 {
             clickCount = 1 //连续双击 > 恢复单击
          } else {
             clickCount = 2
          }
          preTime = time.Now().UnixMilli()
          mouseEvent := &cef.TCefMouseEvent{}
          mouseEvent.X = x
          mouseEvent.Y = y
          mouseEvent.Modifiers = getModifiers(shift)
          cef.DeviceToLogicalMouse(mouseEvent, float64(m.bufferPnl.ScreenScale()))
          m.chrome.SendMouseClickEvent(mouseEvent, getButton(button), false, clickCount)
       })
       // 鼠标事件 点击抬起
       m.bufferPnl.SetOnMouseUp(func(sender lcl.IObject, button types.TMouseButton, shift types.TShiftState, x, y int32) {
          //fmt.Println("SetOnMouseUp:", clickTime, button, shift, x, y)
          mouseEvent := &cef.TCefMouseEvent{}
          mouseEvent.X = x
          mouseEvent.Y = y
          mouseEvent.Modifiers = getModifiers(shift)
          cef.DeviceToLogicalMouse(mouseEvent, float64(m.bufferPnl.ScreenScale()))
          m.chrome.SendMouseClickEvent(mouseEvent, getButton(button), true, clickCount)
       })
       // 鼠标滚轮事件
       m.bufferPnl.SetOnMouseWheel(func(sender lcl.IObject, shift types.TShiftState, wheelDelta, x, y int32, handled *bool) {
          //fmt.Println("SetOnMouseWheel:", shift, wheelDelta, x, y)
          mouseEvent := &cef.TCefMouseEvent{}
          mouseEvent.X = x
          mouseEvent.Y = y
          mouseEvent.Modifiers = getModifiers(shift)
          cef.DeviceToLogicalMouse(mouseEvent, float64(m.bufferPnl.ScreenScale()))
          m.chrome.SendMouseWheelEvent(mouseEvent, 0, wheelDelta)
       })
       // 键盘事件 按下
       m.bufferPnl.SetOnOnKeyDown(func(sender lcl.IObject, key *types.Char, shift types.TShiftState) {
          //fmt.Println("SetOnOnKeyDown", *key, shift)
          keyEvent := &cef.TCefKeyEvent{}
          if *key != 0 {
             keyEvent.Kind = consts.KEYEVENT_RAW_KEYDOWN
             keyEvent.Modifiers = getModifiers(shift)
             keyEvent.WindowsKeyCode = t.Int32(*key)
             keyEvent.NativeKeyCode = 0
             keyEvent.IsSystemKey = 0           // 0=false, 1=true
             keyEvent.Character = '0'           // #0
             keyEvent.UnmodifiedCharacter = '0' // '#0`
             keyEvent.FocusOnEditableField = 0  // 0=false, 1=true
             m.chrome.SendKeyEvent(keyEvent)
             //if (Key in [VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN, VK_TAB]) then Key = 0;
          }
       })
       // 键盘事件 抬起
       m.bufferPnl.SetOnOnKeyUp(func(sender lcl.IObject, key *types.Char, shift types.TShiftState) {
          //fmt.Println("SetOnOnKeyUp", *key, shift)
          keyEvent := &cef.TCefKeyEvent{}
          if *key != 0 {
             keyEvent.Kind = consts.KEYEVENT_KEYUP
             keyEvent.Modifiers = getModifiers(shift)
             keyEvent.WindowsKeyCode = t.Int32(*key)
             keyEvent.NativeKeyCode = 0
             keyEvent.IsSystemKey = 0           // 0=false, 1=true
             keyEvent.Character = '0'           // #0
             keyEvent.UnmodifiedCharacter = '0' // #0
             keyEvent.FocusOnEditableField = 0  // 0=false, 1=true
             m.chrome.SendKeyEvent(keyEvent)
             //if (Key in [VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN, VK_TAB]) then Key = 0;
          }
       })
       // 键盘事件, 上字
       m.bufferPnl.SetOnUTF8KeyPress(func(sender lcl.IObject, utf8key *types.TUTF8Char) {
          //fmt.Println("SetOnUTF8KeyPress", utf8key.ToString(), m.bufferPnl.Focused())
          if m.bufferPnl.Focused() {
             if utf8key.Len > 0 {
                var asciiCode int
                fmt.Sscanf(utf8key.ToString(), "%c", &asciiCode)
                keyEvent := &cef.TCefKeyEvent{}
                keyEvent.Kind = consts.KEYEVENT_CHAR
                keyEvent.Modifiers = cef.GetCefKeyboardModifiers(t.WPARAM(asciiCode), 0)
                keyEvent.WindowsKeyCode = t.Int32(asciiCode)
                keyEvent.NativeKeyCode = 0
                keyEvent.IsSystemKey = 0
                keyEvent.Character = '0'
                keyEvent.UnmodifiedCharacter = '0'
                keyEvent.FocusOnEditableField = 0
                m.chrome.SendKeyEvent(keyEvent)
                //if (Key in [VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN, VK_TAB]) then Key := 0;
             }
          }
       })
       m.bufferPnl.SetOnIMESetComposition(func(sender lcl.IObject, text string, underlines *cef.TCefCompositionUnderlineArray, replacementRange, selectionRange cef.TCefRange) {
          fmt.Println("SetOnIMESetComposition", replacementRange, selectionRange, underlines.Count(), underlines.Get(0))
       })
    }