package util
|
|
import (
|
"bufio"
|
"bytes"
|
"errors"
|
"fmt"
|
"image"
|
"image/color"
|
"image/jpeg"
|
|
"basic.com/pubsub/protomsg.git"
|
"github.com/llgcode/draw2d/draw2dimg"
|
)
|
|
// 按尺寸去切图
|
func SubCutImg(src *protomsg.Image, rect *protomsg.Rect, enlarge int) ([]byte, error) {
|
bkImg, _ := ToImage(src.Data, int(src.Width), int(src.Height), 3)
|
|
rectNew := image.Rect(EnlargeCut(rect, int(src.Width), int(src.Height), enlarge))
|
subImg := bkImg.(*image.RGBA).SubImage(rectNew)
|
|
bytes, err := ImageToJpeg(subImg, nil)
|
if err != nil {
|
return nil, err
|
}
|
return bytes, nil
|
}
|
|
// 长宽变为一比一,每边各扩百分之...
|
func EnlargeCut(rect *protomsg.Rect, maxW, maxH int, enlargePer int) (x0_new, y0_new, x1_new, y1_new int) {
|
// 先把长宽变为一比一
|
x0 := int(rect.Left)
|
y0 := int(rect.Top)
|
x1 := int(rect.Right)
|
y1 := int(rect.Bottom)
|
|
chazhi := (y1 - y0) - (x1 - x0)
|
x0 = x0 - chazhi/2
|
if x0 < 0 {
|
x0 = 0
|
}
|
x1 = x1 + chazhi/2
|
if x1 > maxW {
|
x1 = maxW
|
}
|
|
// 再把每边各扩大百分之...
|
enlarge := float32(enlargePer / 100)
|
x0_new = int((1+enlarge)*float32(x0) - enlarge*float32(x1))
|
if x0_new < 0 {
|
x0_new = 0
|
}
|
x1_new = int((1+enlarge)*float32(x1) - enlarge*float32(x0))
|
if x1_new > maxW {
|
x1_new = maxW
|
}
|
y0_new = int((1+enlarge)*float32(y0) - enlarge*float32(y1))
|
if y0_new < 0 {
|
y0_new = 0
|
}
|
y1_new = int((1+enlarge)*float32(y1) - enlarge*float32(y0))
|
if y1_new > maxH {
|
y1_new = maxH
|
}
|
|
return x0_new, y0_new, x1_new, y1_new
|
}
|
|
// 长宽变为一比一,每边各扩百分之20
|
func EnlargeSizeForCar(x0, y0, x1, y1 int, i protomsg.Image) (x0_new, y0_new, x1_new, y1_new int) {
|
// 先把长宽变为一比一
|
chazhi := (y1 - y0) - (x1 - x0)
|
x0 = x0 - chazhi/2
|
if x0 < 0 {
|
x0 = 0
|
}
|
x1 = x1 + chazhi/2
|
if x1 > int(i.Width) {
|
x1 = int(i.Width)
|
}
|
|
// 再把每边各扩大百分之20
|
enlarge := float32(0.2)
|
x0_new = int((1+enlarge)*float32(x0) - enlarge*float32(x1))
|
if x0_new < 0 {
|
x0_new = 0
|
}
|
x1_new = int((1+enlarge)*float32(x1) - enlarge*float32(x0))
|
if x1_new > int(i.Width) {
|
x1_new = int(i.Width)
|
}
|
y0_new = int((1+enlarge)*float32(y0) - enlarge*float32(y1))
|
if y0_new < 0 {
|
y0_new = 0
|
}
|
y1_new = int((1+enlarge)*float32(y1) - enlarge*float32(y0))
|
if y1_new > int(i.Height) {
|
y1_new = int(i.Height)
|
}
|
return
|
}
|
|
// 不扩边
|
func EnlargeSize(x0, y0, x1, y1 int, i protomsg.Image) (int, int, int, int) {
|
|
// 先把长宽变为一比一
|
chazhi := (y1 - y0) - (x1 - x0)
|
x0 = x0 - chazhi/2
|
if x0 < 0 {
|
x0 = 0
|
}
|
x1 = x1 + chazhi/2
|
if x1 > int(i.Width) {
|
x1 = int(i.Width)
|
}
|
|
if y0 < 0 {
|
y0 = 0
|
}
|
|
if y1 > int(i.Height) {
|
y1 = int(i.Height)
|
}
|
|
return x0, y0, x1, y1
|
}
|
|
// 长宽变为一比一,每边各扩百分之50
|
func EnlargeSizeForTem(x0, y0, x1, y1 int, i protomsg.Image) (x0_new, y0_new, x1_new, y1_new int) {
|
// 先把长宽变为一比一
|
chazhi := (y1 - y0) - (x1 - x0)
|
x0 = x0 - chazhi/2
|
if x0 < 0 {
|
x0 = 0
|
}
|
x1 = x1 + chazhi/2
|
if x1 > int(i.Width) {
|
x1 = int(i.Width)
|
}
|
|
// 再把每边各扩大百分之50
|
enlarge := float32(0.5)
|
x0_new = int((1+enlarge)*float32(x0) - enlarge*float32(x1))
|
if x0_new < 0 {
|
x0_new = 0
|
}
|
x1_new = int((1+enlarge)*float32(x1) - enlarge*float32(x0))
|
if x1_new > int(i.Width) {
|
x1_new = int(i.Width)
|
}
|
y0_new = int((1+enlarge)*float32(y0) - enlarge*float32(y1))
|
if y0_new < 0 {
|
y0_new = 0
|
}
|
y1_new = int((1+enlarge)*float32(y1) - enlarge*float32(y0))
|
if y1_new > int(i.Height) {
|
y1_new = int(i.Height)
|
}
|
return
|
}
|
|
func drawLine(img *image.RGBA, x0, y0, x1, y1 int, c color.Color) {
|
var dx int
|
if x1 > x0 {
|
dx = x1 - x0
|
} else {
|
dx = x0 - x1
|
}
|
var dy int
|
if y1 > y0 {
|
dy = y1 - y0
|
} else {
|
dy = y0 - y1
|
}
|
|
sx, sy := 1, 1
|
if x0 >= x1 {
|
sx = -1
|
}
|
if y0 >= y1 {
|
sy = -1
|
}
|
err := dx - dy
|
|
for {
|
img.Set(x0, y0, c)
|
if x0 == x1 && y0 == y1 {
|
return
|
}
|
e2 := err * 2
|
if e2 > -dy {
|
err -= dy
|
x0 += sx
|
}
|
if e2 < dx {
|
err += dx
|
y0 += sy
|
}
|
}
|
}
|
|
func DrawRect(img *image.RGBA, x0, y0, x1, y1 int, c color.Color) {
|
drawLine(img, x0, y0, x1, y0, c)
|
drawLine(img, x1, y0, x1, y1, c)
|
drawLine(img, x1, y1, x0, y1, c)
|
drawLine(img, x0, y1, x0, y0, c)
|
}
|
|
// ToImage bgr -> image.Image
|
func ToImage(data []byte, w, h, channels int) (image.Image, error) {
|
if len(data) != w*h*channels {
|
return nil, fmt.Errorf("data length does not match dimensions and channels. data %d, w %d, h %d, channels %d", len(data), w, h, channels)
|
}
|
|
img := image.NewRGBA(image.Rect(0, 0, w, h))
|
step := w * channels
|
|
for y := 0; y < h; y++ {
|
for x := 0; x < w; x++ {
|
i := y*step + x*channels
|
var c color.RGBA
|
|
switch channels {
|
case 3: // BGR 格式
|
c = color.RGBA{
|
R: data[i+2], // 红色通道
|
G: data[i+1], // 绿色通道
|
B: data[i], // 蓝色通道
|
A: 255, // 不透明
|
}
|
case 4: // BGRA 格式
|
c = color.RGBA{
|
R: data[i+2], // 红色通道
|
G: data[i+1], // 绿色通道
|
B: data[i], // 蓝色通道
|
A: data[i+3], // Alpha 通道
|
}
|
default:
|
return nil, errors.New("unsupported number of channels")
|
}
|
|
img.Set(x, y, c)
|
}
|
}
|
|
return img, nil
|
}
|
|
// Image2BGR img->bgr
|
func Image2BGR(img image.Image) []byte {
|
bounds := img.Bounds()
|
x := bounds.Dx()
|
y := bounds.Dy()
|
data := make([]byte, 0, x*y*3)
|
for j := bounds.Min.Y; j < bounds.Max.Y; j++ {
|
for i := bounds.Min.X; i < bounds.Max.X; i++ {
|
r, g, b, _ := img.At(i, j).RGBA()
|
data = append(data, byte(b>>8), byte(g>>8), byte(r>>8))
|
}
|
}
|
return data
|
}
|
|
// DrawRectangle draw rect
|
func DrawRectangle(img image.Image, rc image.Rectangle, clr color.RGBA, lw float64) error {
|
|
l, t, r, b := rc.Min.X, rc.Min.Y, rc.Max.X, rc.Max.Y
|
|
pt := []image.Point{
|
image.Pt(l, t),
|
image.Pt(l, r),
|
image.Pt(r, b),
|
image.Pt(r, l),
|
}
|
|
return DrawPolygon(img, pt, clr, lw)
|
}
|
|
// DrawPolygon draw polygon
|
func DrawPolygon(img image.Image, pt []image.Point, clr color.RGBA, lw float64) error {
|
rgba, ok := img.(*image.RGBA)
|
if !ok {
|
return errors.New("IMAGE CONVERT TO RGBA ERROR")
|
}
|
|
pt = append(pt, pt[0])
|
|
gc := draw2dimg.NewGraphicContext(rgba)
|
gc.SetStrokeColor(clr)
|
gc.SetLineWidth(lw)
|
|
gc.BeginPath()
|
start := pt[0]
|
pt = pt[1:]
|
gc.MoveTo((float64)(start.X), (float64)(start.Y))
|
for _, v := range pt {
|
gc.LineTo((float64)(v.X), (float64)(v.Y))
|
}
|
// gc.QuadCurveTo(100, 10, 10, 10)
|
gc.Close()
|
gc.Stroke()
|
return nil
|
}
|
|
// ToJpeg bgr -> jpeg file
|
func ToJpeg(bgr []byte, w, h int, quality *int) ([]byte, error) {
|
img, err := ToImage(bgr, w, h, 3)
|
if err != nil {
|
return nil, err
|
}
|
return ImageToJpeg(img, quality)
|
}
|
|
// ImageToJpeg save to jpeg data
|
func ImageToJpeg(img image.Image, quality *int) ([]byte, error) {
|
var o *jpeg.Options
|
|
if quality != nil {
|
o = &jpeg.Options{Quality: *quality}
|
}
|
var b bytes.Buffer
|
w := bufio.NewWriter(&b)
|
err := jpeg.Encode(w, img, o)
|
if err != nil {
|
return nil, err
|
}
|
return b.Bytes(), err
|
}
|