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 }