mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-24 21:42:51 -05:00
screenshot/colorpicker: handle 24-bit frames from compositor
This commit is contained in:
@@ -16,6 +16,8 @@ const (
|
||||
FormatXRGB8888 = shm.FormatXRGB8888
|
||||
FormatABGR8888 = shm.FormatABGR8888
|
||||
FormatXBGR8888 = shm.FormatXBGR8888
|
||||
FormatRGB888 = shm.FormatRGB888
|
||||
FormatBGR888 = shm.FormatBGR888
|
||||
)
|
||||
|
||||
type SurfaceState struct {
|
||||
@@ -80,8 +82,9 @@ func (s *SurfaceState) OnScreencopyBuffer(format PixelFormat, width, height, str
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if stride < width*4 {
|
||||
return fmt.Errorf("invalid stride %d for width %d", stride, width)
|
||||
bpp := format.BytesPerPixel()
|
||||
if stride < width*bpp {
|
||||
return fmt.Errorf("invalid stride %d for width %d (bpp=%d)", stride, width, bpp)
|
||||
}
|
||||
|
||||
if s.screenBuf != nil {
|
||||
@@ -95,6 +98,7 @@ func (s *SurfaceState) OnScreencopyBuffer(format PixelFormat, width, height, str
|
||||
}
|
||||
|
||||
s.screenBuf = buf
|
||||
s.screenBuf.Format = format
|
||||
s.screenFormat = format
|
||||
return nil
|
||||
}
|
||||
@@ -125,6 +129,15 @@ func (s *SurfaceState) OnScreencopyReady() {
|
||||
return
|
||||
}
|
||||
|
||||
if s.screenFormat.Is24Bit() {
|
||||
converted, newFormat, err := s.screenBuf.ConvertTo32Bit(s.screenFormat)
|
||||
if err == nil && converted != s.screenBuf {
|
||||
s.screenBuf.Close()
|
||||
s.screenBuf = converted
|
||||
s.screenFormat = newFormat
|
||||
}
|
||||
}
|
||||
|
||||
s.recomputeScale()
|
||||
s.ensureRenderBuffers()
|
||||
s.readyForDisplay = true
|
||||
|
||||
@@ -382,9 +382,12 @@ func (r *RegionSelector) preCaptureOutput(output *WaylandOutput, pc *PreCapture,
|
||||
|
||||
var capturedBuf *ShmBuffer
|
||||
|
||||
var capturedFormat PixelFormat
|
||||
frame.SetBufferHandler(func(e wlr_screencopy.ZwlrScreencopyFrameV1BufferEvent) {
|
||||
if int(e.Stride) < int(e.Width)*4 {
|
||||
log.Error("invalid stride from compositor", "stride", e.Stride, "width", e.Width)
|
||||
capturedFormat = PixelFormat(e.Format)
|
||||
bpp := capturedFormat.BytesPerPixel()
|
||||
if int(e.Stride) < int(e.Width)*bpp {
|
||||
log.Error("invalid stride from compositor", "stride", e.Stride, "width", e.Width, "bpp", bpp)
|
||||
return
|
||||
}
|
||||
buf, err := CreateShmBuffer(int(e.Width), int(e.Height), int(e.Stride))
|
||||
@@ -394,7 +397,7 @@ func (r *RegionSelector) preCaptureOutput(output *WaylandOutput, pc *PreCapture,
|
||||
}
|
||||
|
||||
capturedBuf = buf
|
||||
pc.format = e.Format
|
||||
buf.Format = capturedFormat
|
||||
|
||||
pool, err := r.shm.CreatePool(buf.Fd(), int32(buf.Size()))
|
||||
if err != nil {
|
||||
@@ -429,6 +432,19 @@ func (r *RegionSelector) preCaptureOutput(output *WaylandOutput, pc *PreCapture,
|
||||
return
|
||||
}
|
||||
|
||||
if capturedFormat.Is24Bit() {
|
||||
converted, newFormat, err := capturedBuf.ConvertTo32Bit(capturedFormat)
|
||||
if err != nil {
|
||||
log.Error("convert 24-bit to 32-bit failed", "err", err)
|
||||
} else if converted != capturedBuf {
|
||||
capturedBuf.Close()
|
||||
capturedBuf = converted
|
||||
capturedFormat = newFormat
|
||||
}
|
||||
}
|
||||
|
||||
pc.format = uint32(capturedFormat)
|
||||
|
||||
if pc.yInverted {
|
||||
capturedBuf.FlipVertical()
|
||||
pc.yInverted = false
|
||||
|
||||
@@ -717,8 +717,10 @@ func (s *Screenshoter) processFrame(frame *wlr_screencopy.ZwlrScreencopyFrameV1,
|
||||
failed := false
|
||||
|
||||
frame.SetBufferHandler(func(e wlr_screencopy.ZwlrScreencopyFrameV1BufferEvent) {
|
||||
if int(e.Stride) < int(e.Width)*4 {
|
||||
log.Error("invalid stride from compositor", "stride", e.Stride, "width", e.Width)
|
||||
format = PixelFormat(e.Format)
|
||||
bpp := format.BytesPerPixel()
|
||||
if int(e.Stride) < int(e.Width)*bpp {
|
||||
log.Error("invalid stride from compositor", "stride", e.Stride, "width", e.Width, "bpp", bpp)
|
||||
return
|
||||
}
|
||||
var err error
|
||||
@@ -727,7 +729,6 @@ func (s *Screenshoter) processFrame(frame *wlr_screencopy.ZwlrScreencopyFrameV1,
|
||||
log.Error("failed to create buffer", "err", err)
|
||||
return
|
||||
}
|
||||
format = PixelFormat(e.Format)
|
||||
buf.Format = format
|
||||
})
|
||||
|
||||
@@ -790,6 +791,19 @@ func (s *Screenshoter) processFrame(frame *wlr_screencopy.ZwlrScreencopyFrameV1,
|
||||
return nil, fmt.Errorf("frame capture failed")
|
||||
}
|
||||
|
||||
if format.Is24Bit() {
|
||||
converted, newFormat, err := buf.ConvertTo32Bit(format)
|
||||
if err != nil {
|
||||
buf.Close()
|
||||
return nil, fmt.Errorf("convert 24-bit to 32-bit: %w", err)
|
||||
}
|
||||
if converted != buf {
|
||||
buf.Close()
|
||||
buf = converted
|
||||
}
|
||||
format = newFormat
|
||||
}
|
||||
|
||||
return &CaptureResult{
|
||||
Buffer: buf,
|
||||
Region: region,
|
||||
|
||||
@@ -9,6 +9,8 @@ const (
|
||||
FormatXRGB8888 = shm.FormatXRGB8888
|
||||
FormatABGR8888 = shm.FormatABGR8888
|
||||
FormatXBGR8888 = shm.FormatXBGR8888
|
||||
FormatRGB888 = shm.FormatRGB888
|
||||
FormatBGR888 = shm.FormatBGR888
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -13,8 +13,23 @@ const (
|
||||
FormatXRGB8888 PixelFormat = 1
|
||||
FormatABGR8888 PixelFormat = 0x34324241
|
||||
FormatXBGR8888 PixelFormat = 0x34324258
|
||||
FormatRGB888 PixelFormat = 0x34324752
|
||||
FormatBGR888 PixelFormat = 0x34324742
|
||||
)
|
||||
|
||||
func (f PixelFormat) BytesPerPixel() int {
|
||||
switch f {
|
||||
case FormatRGB888, FormatBGR888:
|
||||
return 3
|
||||
default:
|
||||
return 4
|
||||
}
|
||||
}
|
||||
|
||||
func (f PixelFormat) Is24Bit() bool {
|
||||
return f == FormatRGB888 || f == FormatBGR888
|
||||
}
|
||||
|
||||
type Buffer struct {
|
||||
fd int
|
||||
data []byte
|
||||
@@ -78,6 +93,46 @@ func (b *Buffer) Close() error {
|
||||
return firstErr
|
||||
}
|
||||
|
||||
func (b *Buffer) ConvertTo32Bit(srcFormat PixelFormat) (*Buffer, PixelFormat, error) {
|
||||
if !srcFormat.Is24Bit() {
|
||||
return b, srcFormat, nil
|
||||
}
|
||||
|
||||
dstFormat := FormatXRGB8888
|
||||
dstStride := b.Width * 4
|
||||
|
||||
dst, err := CreateBuffer(b.Width, b.Height, dstStride)
|
||||
if err != nil {
|
||||
return nil, srcFormat, err
|
||||
}
|
||||
dst.Format = dstFormat
|
||||
|
||||
srcData := b.data
|
||||
dstData := dst.data
|
||||
isRGB := srcFormat == FormatRGB888
|
||||
|
||||
for y := 0; y < b.Height; y++ {
|
||||
srcRow := y * b.Stride
|
||||
dstRow := y * dstStride
|
||||
for x := 0; x < b.Width; x++ {
|
||||
si := srcRow + x*3
|
||||
di := dstRow + x*4
|
||||
if isRGB {
|
||||
dstData[di+0] = srcData[si+2] // B
|
||||
dstData[di+1] = srcData[si+1] // G
|
||||
dstData[di+2] = srcData[si+0] // R
|
||||
} else {
|
||||
dstData[di+0] = srcData[si+0] // B
|
||||
dstData[di+1] = srcData[si+1] // G
|
||||
dstData[di+2] = srcData[si+2] // R
|
||||
}
|
||||
dstData[di+3] = 0xFF
|
||||
}
|
||||
}
|
||||
|
||||
return dst, dstFormat, nil
|
||||
}
|
||||
|
||||
func (b *Buffer) GetPixelRGBA(x, y int) (r, g, b2, a uint8) {
|
||||
if x < 0 || x >= b.Width || y < 0 || y >= b.Height {
|
||||
return
|
||||
@@ -88,7 +143,12 @@ func (b *Buffer) GetPixelRGBA(x, y int) (r, g, b2, a uint8) {
|
||||
return
|
||||
}
|
||||
|
||||
return b.data[off+2], b.data[off+1], b.data[off], b.data[off+3]
|
||||
switch b.Format {
|
||||
case FormatXBGR8888, FormatABGR8888:
|
||||
return b.data[off], b.data[off+1], b.data[off+2], 0xFF
|
||||
default:
|
||||
return b.data[off+2], b.data[off+1], b.data[off], 0xFF
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Buffer) GetPixelBGRA(x, y int) (b2, g, r, a uint8) {
|
||||
|
||||
Reference in New Issue
Block a user