问题场景:在同时使用go image.DecodeConfig 和image.Decode获取图片信息时,报错提示:
无法读取图像配置 image: unknown format
package main
import (
"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.Width
height := config.Height
fmt.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 main
import (
"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.Width
height := config.Height
fmt.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文件时返回错误 _大数据知识库