问题场景:在同时使用go image.DecodeConfig 和image.Decode获取图片信息时,报错提示:
无法读取图像配置 image: unknown format
package mainimport ("fmt""github.com/golang/freetype""image""image/draw""image/jpeg""os""time"
)func main() {// 打开原始图片file, err := os.Open("004.jpeg")if err != nil {panic(err)}defer file.Close()// 解码图片img, _, err := image.Decode(file)if err != nil {panic(err)}// 创建一个画布bounds := img.Bounds()canvas := image.NewRGBA(bounds)// 打开图像文件fileInfo, err := os.Stat("004.jpeg")if err != nil {fmt.Sprintf("无法获取文件信息:%v", err)}fmt.Println("文件名:",fileInfo.Name())// 读取图像信息//image.Config{ Width: image.DecodeConfig()}config, _, err := image.DecodeConfig(file)if err != nil {fmt.Println("无法读取图像配置", err)}width := config.Widthheight := config.Heightfmt.Println("图片宽度为:", width)fmt.Println("图片高度为:", height)//s,err:=file.Stat()//fmt.Println(file.Name(),s.Size(),s.Sys(),s.Mode(),s.ModTime())// 绘制原始图片到画布上draw.Draw(canvas, bounds, img, image.Point{}, draw.Src)// 添加文字fontBytes, err := os.ReadFile("../ttf/kaiti.TTF") //解析中文//fontBytes, err := os.ReadFile("../ttf/luxisr.ttf") //不解析中文if err != nil {panic(err)}font, err := freetype.ParseFont(fontBytes)if err != nil {panic(err)}context := freetype.NewContext()context.SetDPI(72)context.SetFont(font)context.SetFontSize(25)context.SetClip(bounds)context.SetDst(canvas)context.SetSrc(image.Opaque)pt := freetype.Pt(0, 5+int(context.PointToFixed(24)>>6))context.DrawString("来源公众号:【码农编程进阶笔记】", pt)// 保存处理后的图片filename := fmt.Sprintf("output_%d.jpg", time.Now().Unix())output, err := os.Create(filename)if err != nil {panic(err)}defer output.Close()// 编码保存到文件jpeg.Encode(output, canvas, nil)
}
原因:
试图从同一个io.reader(文件)读取两次。
解决:
//在image.DecodeConfig 和image.Decode两者之间,添加该行问题解决file.Seek(0, io.SeekStart)
完整代码:
package mainimport ("fmt""github.com/golang/freetype""image""image/draw""image/jpeg""io""os""time"
)func main() {// 打开原始图片file, err := os.Open("004.jpeg")if err != nil {panic(err)}defer file.Close()// 解码图片img, _, err := image.Decode(file)if err != nil {panic(err)}// 创建一个画布bounds := img.Bounds()canvas := image.NewRGBA(bounds)// 打开图像文件fileInfo, err := os.Stat("004.jpeg")if err != nil {fmt.Sprintf("无法获取文件信息:%v", err)}fmt.Println("文件名:",fileInfo.Name())//添加该行问题解决file.Seek(0, io.SeekStart)// 读取图像信息//image.Config{ Width: image.DecodeConfig()}config, _, err := image.DecodeConfig(file)if err != nil {fmt.Println("无法读取图像配置", err)}width := config.Widthheight := config.Heightfmt.Println("图片宽度为:", width)fmt.Println("图片高度为:", height)//s,err:=file.Stat()//fmt.Println(file.Name(),s.Size(),s.Sys(),s.Mode(),s.ModTime())// 绘制原始图片到画布上draw.Draw(canvas, bounds, img, image.Point{}, draw.Src)// 添加文字fontBytes, err := os.ReadFile("../ttf/kaiti.TTF") //解析中文//fontBytes, err := os.ReadFile("../ttf/luxisr.ttf") //不解析中文if err != nil {panic(err)}font, err := freetype.ParseFont(fontBytes)if err != nil {panic(err)}context := freetype.NewContext()context.SetDPI(72)context.SetFont(font)context.SetFontSize(25)context.SetClip(bounds)context.SetDst(canvas)context.SetSrc(image.Opaque)pt := freetype.Pt(0, 5+int(context.PointToFixed(24)>>6))context.DrawString("来源公众号:【码农编程进阶笔记】", pt)// 保存处理后的图片filename := fmt.Sprintf("output_%d.jpg", time.Now().Unix())output, err := os.Create(filename)if err != nil {panic(err)}defer output.Close()// 编码保存到文件jpeg.Encode(output, canvas, nil)
}
方法一:(代码简洁,亲测可用)
解释:大概意思,
将下一个读取或写入文件的偏移量设置为偏移量,根据以下内容进行解释:0表示相对于文件原点,1表示相对于当前偏移量,2表示相对于终点。它返回新的偏移量和一个错误(如果有的话)。
在使用O_APPEND打开的文件上,未指定Seek的行为。
如果f是一个目录,则Seek的行为因操作而异
系统您可以在类Unix操作系统上查找目录的开头,但不能在Windows上查找。
最终,还是再次读取文件。
// Seek sets the offset for the next Read or Write on file to offset, interpreted
// according to whence: 0 means relative to the origin of the file, 1 means
// relative to the current offset, and 2 means relative to the end.
// It returns the new offset and an error, if any.
// The behavior of Seek on a file opened with O_APPEND is not specified.
//
// If f is a directory, the behavior of Seek varies by operating
// system; you can seek to the beginning of the directory on Unix-like
// operating systems, but not on Windows.
func (f *File) Seek(offset int64, whence int) (ret int64, err error) {if err := f.checkValid("seek"); err != nil {return 0, err}r, e := f.seek(offset, whence)if e == nil && f.dirinfo != nil && r != 0 {e = syscall.EISDIR}if e != nil {return 0, f.wrapErr("seek", e)}return r, nil
}
方法二:(有点麻烦)
您试图从同一个io.reader(文件)读取两次。
image.DecodeConfig(file)
第二次在
image.Decode(file)
第二次尝试从同一个io.reader读取时,将得到EOF
当Read在成功阅读n〉0字节后遇到错误或文件结束条件时,它返回读取的字节数。它可以返回(non-nil)来自同一调用的错误或返回错误这种一般情况的一个示例是,在输入流的末尾返回非零字节数的Reader可以返回err == 0(并且n == 0)。EOF或err == nil。下一次读取应返回0,EOF。
在这里关于它https://golang.org/pkg/io/#Reader
一些快速和简单的你可以做的是打开文件两次
file, err := os.Open("test2.png")
if err != nil {fmt.Println("0 ", err)return
}
imageInConfig, _, err := image.DecodeConfig(file)
if err != nil {fmt.Println("1 ", err)return
}
file2, err := os.Open("test2.png")
if err != nil {fmt.Println("3 ", err)return
}
imageIn, _, err := image.Decode(file2)
if err != nil {fmt.Println("4 ", err)return
}
或者,您可以尝试多次阅读同一个文件。How to read multiple times from same io.Reader
参考:Go语言 image.decode在解码.png文件时返回错误 _大数据知识库