Golang实现图片与视频的缩略图生成

图片与视频的缩略图是一个十分常见的需求,比如即时消息。这里摘取了Golang项目中的相关代码,分享图片与视频相关处理的开发经验。

图片缩略图

缩略图的尺寸分为两种规则:

1)边长模式,生成正方形缩略图;

2)宽高模式,又分三种:指定宽高、指定宽(高等比缩放)、指定高(宽等比缩放)。

如果原图为png或gif,缩略图则采用png格式;否则,都采用jpeg格式。

func createPhotoThumbnail(src string, thumbnail string, side int, width int, height int) (err error) {
	// open image
	srcFile, err := os.Open(src)
	if err != nil {
		return fmt.Errorf("opening image failed")
	}
	defer srcFile.Close()
	img, format, err := image.Decode(srcFile)
	if err != nil {
		return fmt.Errorf("decode image failed %v", err)
	}

	// process image
	var thumbnailImg image.Image
	if side > 0 {	// 指定边长
		var canvas image.Image
        s := side
		sz := img.Bounds().Size()
        // 等比缩小
		if sz.X > sz.Y {
			canvas = resize.Thumbnail(uint(sz.X), uint(s), img, resize.Lanczos2)
		} else {
			canvas = resize.Thumbnail(uint(s), uint(sz.Y), img, resize.Lanczos2)
		}
		sz = canvas.Bounds().Size()
		var l, t, r, b int
		if sz.X > s {
			l = (sz.X - s) / 2
			r = l + s
		} else {
			l = 0
			r = sz.X
		}
		if sz.Y > s {
			t = (sz.Y - s) / 2
			b = t + s
		} else {
			t = 0
			b = sz.Y
		}
        // 裁剪
		thumbnailImg = canvas.(*image.YCbCr).SubImage(image.Rect(l, t, r, b)).(*image.YCbCr)
	} else {	// 指定宽和高
        w := width
        h := height
		if w > 0 && h > 0 {
		} else if w > 0 {
			h = img.Bounds().Dy()
		} else {
			w = img.Bounds().Dx()
		}
		thumbnailImg = resize.Thumbnail(uint(w), uint(h), img, resize.Lanczos2)
	}

	// save thumbnail
	err = os.MkdirAll(filepath.Dir(thumbnail), os.ModePerm)
	if err != nil {
		return
	}
	thumbnailFile, err := os.Create(thumbnail)
	if err != nil {
		return
	}
	defer thumbnailFile.Close()
	if format == "png" || format == "gif" {
		err = png.Encode(thumbnailFile, thumbnailImg)
	} else {
		err = jpeg.Encode(thumbnailFile, thumbnailImg, &jpeg.Options{Quality: 80})
	}
	return
}

视频缩略图

生成视频的缩略图,需要先用ffmpeg命令行程序从视频中截取2秒之后的单帧图片,这里以Linux为例。然后,用上面的图片缩略图生成函数再生成指定尺寸的缩略图。

func createVideoThumbnail(src string, thumbnail string, side int, width int, height int) (err error) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(25)*time.Second)
	defer cancel()
	dir := filepath.Dir(thumbnail)
	os.MkdirAll(dir, os.ModePerm)
	tmp := thumbnail + ".tmp"
	c := exec.CommandContext(ctx, "./ffmpeg",
		"-loglevel", "error",
		"-y",
		"-ss", "2",
		"-accurate_seek", "-i", src,
		"-vframes", "1",
		"-f", "image2",
		tmp)
	var stderr bytes.Buffer
	c.Stderr = &stderr
	err = c.Run()
	errStr := ""
	if err != nil {
		errStr = fmt.Sprintf("ffmpeg cmderr(%v) ", err)
	}
	if stderr.Len() != 0 {
		errStr += fmt.Sprintf("ffmpeg stderr(%v) ", stderr.String())
	}
	if ctx.Err() != nil {
		errStr += fmt.Sprintf("ffmpeg ctxerr(%v)", ctx.Err())
	}
	if errStr != "" {
		err = errors.New(errStr)
		return
	}
	err = createPhotoThumbnail(tmp, thumbnail, side, width, height)
	os.Remove(tmp)
	return
}

你可能感兴趣的:(golang,音视频,开发语言)