Golang生成WebP格式文件的缩略图实现方法

Golang生成WebP格式文件的缩略图实现方法 以下代码使用 github.com/disintegration/imaging 包来创建缩略图,对于典型的图像格式(如 JPEG)效果很好,但对于 webp 文件格式则效果不佳。

使用下面的代码时,我遇到了错误 imaging: unsupported image format

是否有更健壮的方法来为典型图像类型(jpg、gif、tiff、bmp 等)和 webp 生成缩略图?

package main

import (
	"bytes"
	"fmt"
	"github.com/disintegration/imaging"
	"github.com/chai2010/webp"
	"io/ioutil"
)

//https://stackoverflow.com/questions/8340751/webp-encoder-decoder-in-go
func main() {
	//img, _ := imaging.Open("ml/input/apple.jpg")

	// Load webp
	data, _ := ioutil.ReadFile("ml/input/waterski2.webp")
	// Decode webp
	img, _ := webp.Decode(bytes.NewReader(data))
	//Create thumbnail
	dstImage := imaging.Thumbnail(img, 400, 400, imaging.Lanczos)

	err1:=imaging.Save(dstImage, "ml/output/waterski2.webp")
	if err1!=nil{
		fmt.Println(err1)
	}
}

更多关于Golang生成WebP格式文件的缩略图实现方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

这个怎么样?

https://pkg.go.dev/golang.org/x/image/webp

既然解码功能可用,编码功能应该也不是不可能实现。

更多关于Golang生成WebP格式文件的缩略图实现方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


是的,你可能是对的。我对图像格式的编码/解码了解不够深入,无法断定这个包是否可用于转换。

不过,我要辩解一下,看起来那是大约一周前发布的 0.0.0 版本,所以我之前并不知道它 😊

只要我有时间,我一定会为我的项目研究一下它。至于它是否对 @jack1234 有帮助,我就不知道了。

据我所知,Go 语言目前尚未支持 WEBP 格式。我最终通过调用外部程序 dwebp(Linux 系统)来将 WEBP 转换为 JPG 或 PNG。它很可能也可以用于反向转换。我相信在 Windows 或 Mac 系统上也存在类似的程序。

对于WebP格式的缩略图生成,imaging包确实存在格式支持限制。以下是更健壮的实现方法,支持包括WebP在内的多种图像格式:

package main

import (
    "bytes"
    "fmt"
    "image"
    "image/gif"
    "image/jpeg"
    "image/png"
    "os"
    "path/filepath"
    "strings"

    "github.com/disintegration/imaging"
    "golang.org/x/image/bmp"
    "golang.org/x/image/tiff"
    "github.com/chai2010/webp"
)

// 支持的图像格式解码器映射
var decoders = map[string]func([]byte) (image.Image, error){
    ".jpg":  decodeJPEG,
    ".jpeg": decodeJPEG,
    ".png":  decodePNG,
    ".gif":  decodeGIF,
    ".bmp":  decodeBMP,
    ".tiff": decodeTIFF,
    ".tif":  decodeTIFF,
    ".webp": decodeWebP,
}

// 支持的图像格式编码器映射
var encoders = map[string]func(string, image.Image) error{
    ".jpg":  encodeJPEG,
    ".jpeg": encodeJPEG,
    ".png":  encodePNG,
    ".gif":  encodeGIF,
    ".bmp":  encodeBMP,
    ".tiff": encodeTIFF,
    ".tif":  encodeTIFF,
    ".webp": encodeWebP,
}

// 解码函数实现
func decodeJPEG(data []byte) (image.Image, error) {
    return jpeg.Decode(bytes.NewReader(data))
}

func decodePNG(data []byte) (image.Image, error) {
    return png.Decode(bytes.NewReader(data))
}

func decodeGIF(data []byte) (image.Image, error) {
    return gif.Decode(bytes.NewReader(data))
}

func decodeBMP(data []byte) (image.Image, error) {
    return bmp.Decode(bytes.NewReader(data))
}

func decodeTIFF(data []byte) (image.Image, error) {
    return tiff.Decode(bytes.NewReader(data))
}

func decodeWebP(data []byte) (image.Image, error) {
    return webp.Decode(bytes.NewReader(data))
}

// 编码函数实现
func encodeJPEG(filename string, img image.Image) error {
    out, err := os.Create(filename)
    if err != nil {
        return err
    }
    defer out.Close()
    return jpeg.Encode(out, img, &jpeg.Options{Quality: 85})
}

func encodePNG(filename string, img image.Image) error {
    out, err := os.Create(filename)
    if err != nil {
        return err
    }
    defer out.Close()
    return png.Encode(out, img)
}

func encodeGIF(filename string, img image.Image) error {
    out, err := os.Create(filename)
    if err != nil {
        return err
    }
    defer out.Close()
    return gif.Encode(out, img, &gif.Options{})
}

func encodeBMP(filename string, img image.Image) error {
    out, err := os.Create(filename)
    if err != nil {
        return err
    }
    defer out.Close()
    return bmp.Encode(out, img)
}

func encodeTIFF(filename string, img image.Image) error {
    out, err := os.Create(filename)
    if err != nil {
        return err
    }
    defer out.Close()
    return tiff.Encode(out, img, &tiff.Options{})
}

func encodeWebP(filename string, img image.Image) error {
    out, err := os.Create(filename)
    if err != nil {
        return err
    }
    defer out.Close()
    return webp.Encode(out, img, &webp.Options{Lossless: false, Quality: 80})
}

// 通用缩略图生成函数
func GenerateThumbnail(inputPath, outputPath string, width, height int) error {
    // 读取原始图像数据
    data, err := os.ReadFile(inputPath)
    if err != nil {
        return fmt.Errorf("读取文件失败: %v", err)
    }

    // 获取文件扩展名
    ext := strings.ToLower(filepath.Ext(inputPath))
    
    // 查找对应的解码器
    decoder, ok := decoders[ext]
    if !ok {
        return fmt.Errorf("不支持的图像格式: %s", ext)
    }

    // 解码图像
    img, err := decoder(data)
    if err != nil {
        return fmt.Errorf("解码失败: %v", err)
    }

    // 使用imaging生成缩略图
    thumbnail := imaging.Thumbnail(img, width, height, imaging.Lanczos)

    // 获取输出文件扩展名
    outputExt := strings.ToLower(filepath.Ext(outputPath))
    
    // 查找对应的编码器
    encoder, ok := encoders[outputExt]
    if !ok {
        return fmt.Errorf("不支持的输出格式: %s", outputExt)
    }

    // 编码并保存缩略图
    return encoder(outputPath, thumbnail)
}

func main() {
    // 示例:为WebP文件生成缩略图
    err := GenerateThumbnail(
        "ml/input/waterski2.webp",
        "ml/output/waterski2_thumb.webp",
        400,
        400,
    )
    if err != nil {
        fmt.Printf("生成缩略图失败: %v\n", err)
        return
    }
    fmt.Println("缩略图生成成功")

    // 示例:为JPEG文件生成缩略图
    err = GenerateThumbnail(
        "ml/input/apple.jpg",
        "ml/output/apple_thumb.jpg",
        400,
        400,
    )
    if err != nil {
        fmt.Printf("生成缩略图失败: %v\n", err)
        return
    }
    fmt.Println("JPEG缩略图生成成功")
}

这个实现通过以下方式解决WebP支持问题:

  1. 格式检测:基于文件扩展名自动选择正确的解码器
  2. 统一接口:为所有支持的格式提供一致的解码/编码接口
  3. WebP专门处理:使用github.com/chai2010/webp包处理WebP格式
  4. 格式转换支持:支持不同格式之间的转换(如WebP转JPEG)

需要安装的依赖包:

go get github.com/disintegration/imaging
go get github.com/chai2010/webp
go get golang.org/x/image/bmp
go get golang.org/x/image/tiff

这个方案的优势:

  • 支持所有常见图像格式(JPEG、PNG、GIF、BMP、TIFF、WebP)
  • 保持原始代码的缩略图生成逻辑不变
  • 提供统一的错误处理
  • 支持格式转换
  • 易于扩展新的图像格式
回到顶部