feat(app): implement basic function
General - 配置界面支持配置对象存储桶 - 快捷键进入截图 - 一键上传截图 & 复制截图链接 MacOS - 状态栏指示器和应用图标
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
package screencapture
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/png"
|
||||
)
|
||||
|
||||
// CropPNG decodes the supplied PNG, crops it to rect (in PHYSICAL pixels of
|
||||
// the source image — i.e. the same coordinate system the PNG itself uses),
|
||||
// and re-encodes the result.
|
||||
//
|
||||
// Why an extra abstraction: the overlay flow captures the entire screen as
|
||||
// one big PNG and lets the user pick a region in the WebView. The selection
|
||||
// rectangle the WebView reports is in CSS pixels, so callers must scale by
|
||||
// the display's backing factor before invoking CropPNG. Splitting "scale"
|
||||
// from "crop" keeps this helper focused and unit-testable.
|
||||
func CropPNG(pngBytes []byte, rect image.Rectangle) ([]byte, error) {
|
||||
if rect.Dx() <= 0 || rect.Dy() <= 0 {
|
||||
return nil, fmt.Errorf("invalid crop rectangle: %v", rect)
|
||||
}
|
||||
img, err := png.Decode(bytes.NewReader(pngBytes))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decode source png: %w", err)
|
||||
}
|
||||
// Clip the requested rectangle to the source bounds — defensive guard
|
||||
// against off-by-one errors from CSS-px → physical-px scaling.
|
||||
src := img.Bounds()
|
||||
clipped := rect.Intersect(src)
|
||||
if clipped.Empty() {
|
||||
return nil, fmt.Errorf("crop rectangle %v has no overlap with source %v", rect, src)
|
||||
}
|
||||
|
||||
// SubImage is documented on most concrete image types; the standard
|
||||
// library decodes PNGs into one of those, so this assertion is safe in
|
||||
// practice. Fall back to a manual copy otherwise.
|
||||
type subImager interface {
|
||||
SubImage(r image.Rectangle) image.Image
|
||||
}
|
||||
var cropped image.Image
|
||||
if si, ok := img.(subImager); ok {
|
||||
cropped = si.SubImage(clipped)
|
||||
} else {
|
||||
dst := image.NewRGBA(image.Rect(0, 0, clipped.Dx(), clipped.Dy()))
|
||||
for y := 0; y < clipped.Dy(); y++ {
|
||||
for x := 0; x < clipped.Dx(); x++ {
|
||||
dst.Set(x, y, img.At(clipped.Min.X+x, clipped.Min.Y+y))
|
||||
}
|
||||
}
|
||||
cropped = dst
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := png.Encode(&buf, cropped); err != nil {
|
||||
return nil, fmt.Errorf("encode cropped png: %w", err)
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
Reference in New Issue
Block a user