final fixes on resolution and fix build issue on mac and linux
This commit is contained in:
@@ -35,6 +35,8 @@ func Loop(ctx context.Context, env *rt.Env) {
|
|||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
goSafe("capture initial frame", env.Cancel, func() {
|
goSafe("capture initial frame", env.Cancel, func() {
|
||||||
defer close(done)
|
defer close(done)
|
||||||
|
restore := BypassResolutionCap()
|
||||||
|
defer restore()
|
||||||
var err error
|
var err error
|
||||||
if goruntime.GOOS == "windows" && activeDisplays() > 1 {
|
if goruntime.GOOS == "windows" && activeDisplays() > 1 {
|
||||||
err = captureAllDisplaysAndSend(ctx, env)
|
err = captureAllDisplaysAndSend(ctx, env)
|
||||||
@@ -197,12 +199,53 @@ func captureAllDisplaysAndSend(ctx context.Context, env *rt.Env) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas := image.NewRGBA(image.Rect(0, 0, maxX-minX, maxY-minY))
|
// Compute per-monitor scale factors to handle resolution-cap or DPI
|
||||||
for _, part := range parts {
|
// mismatches between displayBounds (virtual coords) and captured pixels.
|
||||||
offX := part.bounds.Min.X - minX
|
type scaledPart struct {
|
||||||
offY := part.bounds.Min.Y - minY
|
img *image.RGBA
|
||||||
dst := image.Rect(offX, offY, offX+part.img.Rect.Dx(), offY+part.img.Rect.Dy())
|
scaleX float64
|
||||||
draw.Draw(canvas, dst, part.img, part.img.Rect.Min, draw.Src)
|
scaleY float64
|
||||||
|
offX int
|
||||||
|
offY int
|
||||||
|
}
|
||||||
|
scaled := make([]scaledPart, len(parts))
|
||||||
|
for i, part := range parts {
|
||||||
|
sx, sy := 1.0, 1.0
|
||||||
|
bw := part.bounds.Dx()
|
||||||
|
bh := part.bounds.Dy()
|
||||||
|
iw := part.img.Rect.Dx()
|
||||||
|
ih := part.img.Rect.Dy()
|
||||||
|
if bw > 0 && iw > 0 {
|
||||||
|
sx = float64(iw) / float64(bw)
|
||||||
|
}
|
||||||
|
if bh > 0 && ih > 0 {
|
||||||
|
sy = float64(ih) / float64(bh)
|
||||||
|
}
|
||||||
|
scaled[i] = scaledPart{
|
||||||
|
img: part.img,
|
||||||
|
scaleX: sx,
|
||||||
|
scaleY: sy,
|
||||||
|
offX: int(float64(part.bounds.Min.X-minX) * sx),
|
||||||
|
offY: int(float64(part.bounds.Min.Y-minY) * sy),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Canvas sized from scaled image placements.
|
||||||
|
cW, cH := 0, 0
|
||||||
|
for _, sp := range scaled {
|
||||||
|
rx := sp.offX + sp.img.Rect.Dx()
|
||||||
|
ry := sp.offY + sp.img.Rect.Dy()
|
||||||
|
if rx > cW {
|
||||||
|
cW = rx
|
||||||
|
}
|
||||||
|
if ry > cH {
|
||||||
|
cH = ry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
canvas := image.NewRGBA(image.Rect(0, 0, cW, cH))
|
||||||
|
for _, sp := range scaled {
|
||||||
|
dst := image.Rect(sp.offX, sp.offY, sp.offX+sp.img.Rect.Dx(), sp.offY+sp.img.Rect.Dy())
|
||||||
|
draw.Draw(canvas, dst, sp.img, sp.img.Rect.Min, draw.Src)
|
||||||
}
|
}
|
||||||
|
|
||||||
quality := jpegQuality()
|
quality := jpegQuality()
|
||||||
|
|||||||
@@ -196,6 +196,10 @@ func drawCursor(img *image.RGBA, cursorX, cursorY int32, bounds image.Rectangle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func DrawCursorOnDC(hdc uintptr, captureBounds image.Rectangle) bool {
|
func DrawCursorOnDC(hdc uintptr, captureBounds image.Rectangle) bool {
|
||||||
|
return DrawCursorOnDCScaled(hdc, captureBounds, 1.0, 1.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DrawCursorOnDCScaled(hdc uintptr, captureBounds image.Rectangle, scaleX, scaleY float64) bool {
|
||||||
if !cursorCaptureEnabled.Load() || hdc == 0 {
|
if !cursorCaptureEnabled.Load() || hdc == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -217,8 +221,9 @@ func DrawCursorOnDC(hdc uintptr, captureBounds image.Rectangle) bool {
|
|||||||
defer deleteObject(icon.hbmColor)
|
defer deleteObject(icon.hbmColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
x := int32(ci.ptScreenPos.x) - int32(captureBounds.Min.X) - int32(icon.xHotspot)
|
// Map from screen space into the (possibly scaled) DC space.
|
||||||
y := int32(ci.ptScreenPos.y) - int32(captureBounds.Min.Y) - int32(icon.yHotspot)
|
x := int32(float64(ci.ptScreenPos.x-int32(captureBounds.Min.X))*scaleX) - int32(icon.xHotspot)
|
||||||
|
y := int32(float64(ci.ptScreenPos.y-int32(captureBounds.Min.Y))*scaleY) - int32(icon.yHotspot)
|
||||||
ret, _, _ = procDrawIconEx.Call(
|
ret, _, _ = procDrawIconEx.Call(
|
||||||
hdc,
|
hdc,
|
||||||
uintptr(x),
|
uintptr(x),
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package capture
|
||||||
|
|
||||||
|
func SetMaxResolution(maxH int) {}
|
||||||
|
|
||||||
|
func BypassResolutionCap() (restore func()) {
|
||||||
|
return func() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
func EffectiveScaleForInput() float64 {
|
||||||
|
return 1.0
|
||||||
|
}
|
||||||
@@ -227,7 +227,7 @@ func captureDisplayBitBlt(display int) (*image.RGBA, error) {
|
|||||||
dstH = srcH
|
dstH = srcH
|
||||||
}
|
}
|
||||||
|
|
||||||
useStretch := dstW > 0 && dstH > 0 && (dstW < srcW || dstH < srcH) && !cursorCaptureEnabled.Load()
|
useStretch := dstW > 0 && dstH > 0 && (dstW < srcW || dstH < srcH)
|
||||||
capW := srcW
|
capW := srcW
|
||||||
capH := srcH
|
capH := srcH
|
||||||
if useStretch {
|
if useStretch {
|
||||||
@@ -290,7 +290,11 @@ func captureDisplayBitBlt(display int) (*image.RGBA, error) {
|
|||||||
}
|
}
|
||||||
bitDur := time.Since(bitStart)
|
bitDur := time.Since(bitStart)
|
||||||
cursorDrawn := false
|
cursorDrawn := false
|
||||||
if !useStretch {
|
if useStretch {
|
||||||
|
sx := float64(capW) / float64(srcW)
|
||||||
|
sy := float64(capH) / float64(srcH)
|
||||||
|
cursorDrawn = DrawCursorOnDCScaled(hdcMem, bounds, sx, sy)
|
||||||
|
} else {
|
||||||
cursorDrawn = DrawCursorOnDC(hdcMem, bounds)
|
cursorDrawn = DrawCursorOnDC(hdcMem, bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -544,6 +548,11 @@ func SetMaxResolution(maxH int) {
|
|||||||
log.Printf("capture: max resolution set to %d", maxH)
|
log.Printf("capture: max resolution set to %d", maxH)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BypassResolutionCap() (restore func()) {
|
||||||
|
old := maxResHeight.Swap(-1)
|
||||||
|
return func() { maxResHeight.Store(old) }
|
||||||
|
}
|
||||||
|
|
||||||
func EffectiveScaleForInput() float64 {
|
func EffectiveScaleForInput() float64 {
|
||||||
bits := lastCapScale.Load()
|
bits := lastCapScale.Load()
|
||||||
if bits == 0 {
|
if bits == 0 {
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func HandleScreenshot(ctx context.Context, env *rt.Env, cmdID string, allDisplays bool) error {
|
func HandleScreenshot(ctx context.Context, env *rt.Env, cmdID string, allDisplays bool) error {
|
||||||
|
restore := capture.BypassResolutionCap()
|
||||||
|
defer restore()
|
||||||
|
|
||||||
if allDisplays {
|
if allDisplays {
|
||||||
log.Printf("screenshot: capturing all displays")
|
log.Printf("screenshot: capturing all displays")
|
||||||
} else {
|
} else {
|
||||||
@@ -202,13 +205,41 @@ func captureScreenshotImageWindows(allDisplays bool) (*image.RGBA, int, image.Re
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtualBounds := image.Rect(minX, minY, maxX, maxY)
|
type scaledPart struct {
|
||||||
canvas := image.NewRGBA(image.Rect(0, 0, virtualBounds.Dx(), virtualBounds.Dy()))
|
img *image.RGBA
|
||||||
for _, part := range parts {
|
offX int
|
||||||
offX := part.bounds.Min.X - minX
|
offY int
|
||||||
offY := part.bounds.Min.Y - minY
|
}
|
||||||
dst := image.Rect(offX, offY, offX+part.img.Rect.Dx(), offY+part.img.Rect.Dy())
|
sp := make([]scaledPart, len(parts))
|
||||||
draw.Draw(canvas, dst, part.img, part.img.Rect.Min, draw.Src)
|
for i, part := range parts {
|
||||||
|
sx, sy := 1.0, 1.0
|
||||||
|
if bw := part.bounds.Dx(); bw > 0 {
|
||||||
|
sx = float64(part.img.Rect.Dx()) / float64(bw)
|
||||||
|
}
|
||||||
|
if bh := part.bounds.Dy(); bh > 0 {
|
||||||
|
sy = float64(part.img.Rect.Dy()) / float64(bh)
|
||||||
|
}
|
||||||
|
sp[i] = scaledPart{
|
||||||
|
img: part.img,
|
||||||
|
offX: int(float64(part.bounds.Min.X-minX) * sx),
|
||||||
|
offY: int(float64(part.bounds.Min.Y-minY) * sy),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cW, cH := 0, 0
|
||||||
|
for _, s := range sp {
|
||||||
|
if rx := s.offX + s.img.Rect.Dx(); rx > cW {
|
||||||
|
cW = rx
|
||||||
|
}
|
||||||
|
if ry := s.offY + s.img.Rect.Dy(); ry > cH {
|
||||||
|
cH = ry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas := image.NewRGBA(image.Rect(0, 0, cW, cH))
|
||||||
|
for _, s := range sp {
|
||||||
|
dst := image.Rect(s.offX, s.offY, s.offX+s.img.Rect.Dx(), s.offY+s.img.Rect.Dy())
|
||||||
|
draw.Draw(canvas, dst, s.img, s.img.Rect.Min, draw.Src)
|
||||||
}
|
}
|
||||||
|
|
||||||
return canvas, 0, canvas.Rect, nil
|
return canvas, 0, canvas.Rect, nil
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ export function createRenderer({
|
|||||||
wrapper.className = "flex-shrink-0";
|
wrapper.className = "flex-shrink-0";
|
||||||
const img = document.createElement("img");
|
const img = document.createElement("img");
|
||||||
img.className =
|
img.className =
|
||||||
"w-40 h-24 rounded-lg border border-slate-800 object-cover cursor-pointer thumb-img";
|
"w-40 h-24 rounded-lg object-contain cursor-pointer thumb-img";
|
||||||
img.alt = "preview";
|
img.alt = "preview";
|
||||||
img.src = client.thumbnail;
|
img.src = client.thumbnail;
|
||||||
wrapper.appendChild(img);
|
wrapper.appendChild(img);
|
||||||
|
|||||||
Reference in New Issue
Block a user