如果只是下个截取可视区域的图片,可以用下面代码:
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)) }) }