分享
  1. 首页
  2. 文章

io.Reader游标引发的血案

xialeistudio · · 3990 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

背景

线上运行了一个图片合成程序,默认的小程序二维码中奖是小程序LOGO,不满足需求,所以将微信小程序二维码和用户头像合成在一张图片。
由于微信图片有时候返回的Content-Type不对应(比如内容是PNG的,头确是image/jpeg)所以使用jpeg/png/gif的顺序进行图片数据解析,哪个成功就返回解析结果。

问题

总是出现诸如invalid JPEG format: missing SOI marker

解决过程

我去查看jpeg.Decode的源码,如下:

func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
 d.r = r
 // Check for the Start Of Image marker.
 if err := d.readFull(d.tmp[:2]); err != nil {
 return nil, err
 }
 if d.tmp[0] != 0xff || d.tmp[1] != soiMarker {
 return nil, FormatError("missing SOI marker")
 }
...

soiMarker常量

 soiMarker = 0xd8 // Start Of Image.

可以看到判断了第1个字节如果不是0xff或者第2个字节不是0xd8就报错。打印图片的bytes前几个字节如下:

[]byte{0xff, 0xd8, 0xff, 0xe0, 0x0, 0x10}

可以看到第1个字节和第2个字节满足要求,按理说不会出现这个问题,无奈只能求助于Google,搜索了
invalid JPEG format: missing SOI marker关键字出现一篇Covert base64 string to JPG引起了我的注意。
打开看到答案

You need to create a new reader for each decoder:
pngI, errPng := png.Decode(bytes.NewReader(unbased))
// ...
jpgI, errJpg := jpeg.Decode(bytes.NewReader(unbased))

原来需要重新创建读取器,重新创建读取器后问题解决。

后续

抱着打破砂锅问到底的心态,查看了一下bytes.Reader的源码,发现游标读取完后并未重置

// Read implements the io.Reader interface.
func (r *Reader) Read(b []byte) (n int, err error) {
 if r.i >= int64(len(r.s)) {
 return 0, io.EOF
 }
 r.prevRune = -1
 n = copy(b, r.s[r.i:])
 r.i += int64(n)
 return
}

Reader定义

type Reader struct {
 s []byte
 i int64 // current reading index
 prevRune int // index of previous rune; or < 0
}

可以看到r.i就是游标了。问题圆满解决


有疑问加站长微信联系(非本文作者)

本文来自:Segmentfault

感谢作者:xialeistudio

查看原文:io.Reader游标引发的血案

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
3990 次点击 ∙ 1 赞
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏