|
| 1 | +package heic |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "image" |
| 6 | + "image/color" |
| 7 | + "io" |
| 8 | + "sync" |
| 9 | +) |
| 10 | + |
| 11 | +var modPool = sync.Pool{New: func() any { return newModuleRaw() }} |
| 12 | + |
| 13 | +func decode(r io.Reader, configOnly bool) (image.Image, image.Config, error) { |
| 14 | + var cfg image.Config |
| 15 | + |
| 16 | + mod := modPool.Get().(*module) |
| 17 | + defer modPool.Put(mod) |
| 18 | + |
| 19 | + var data []byte |
| 20 | + var err error |
| 21 | + if configOnly { |
| 22 | + data, err = io.ReadAll(io.LimitReader(r, heifMaxHeaderSize)) |
| 23 | + } else { |
| 24 | + data, err = io.ReadAll(r) |
| 25 | + } |
| 26 | + if err != nil { |
| 27 | + return nil, cfg, fmt.Errorf("read: %w", err) |
| 28 | + } |
| 29 | + |
| 30 | + inSize := len(data) |
| 31 | + |
| 32 | + inPtr := mod.Xmalloc(int32(inSize)) |
| 33 | + if inPtr == 0 { |
| 34 | + return nil, cfg, ErrMemWrite |
| 35 | + } |
| 36 | + defer mod.Xfree(inPtr) |
| 37 | + if !mod.write(inPtr, data) { |
| 38 | + return nil, cfg, ErrMemWrite |
| 39 | + } |
| 40 | + |
| 41 | + info := mod.Xmalloc(2 * 4) |
| 42 | + if info == 0 { |
| 43 | + return nil, cfg, ErrMemWrite |
| 44 | + } |
| 45 | + defer mod.Xfree(info) |
| 46 | + |
| 47 | + cfgOnly := int32(0) |
| 48 | + if configOnly { |
| 49 | + cfgOnly = 1 |
| 50 | + } |
| 51 | + |
| 52 | + out := mod.Xdecode(inPtr, int32(inSize), cfgOnly, info) |
| 53 | + |
| 54 | + width := load32(mod.memory[info:]) |
| 55 | + height := load32(mod.memory[info+4:]) |
| 56 | + |
| 57 | + cfg.Width = int(width) |
| 58 | + cfg.Height = int(height) |
| 59 | + cfg.ColorModel = color.NRGBAModel |
| 60 | + |
| 61 | + if configOnly { |
| 62 | + if width == 0 { |
| 63 | + return nil, image.Config{}, ErrDecode |
| 64 | + } |
| 65 | + return nil, cfg, nil |
| 66 | + } |
| 67 | + |
| 68 | + if out == 0 { |
| 69 | + return nil, cfg, ErrDecode |
| 70 | + } |
| 71 | + defer mod.Xfree(out) |
| 72 | + |
| 73 | + size := int(width) * int(height) * 4 |
| 74 | + pix, ok := mod.read(out, int32(size)) |
| 75 | + if !ok { |
| 76 | + return nil, cfg, ErrMemRead |
| 77 | + } |
| 78 | + |
| 79 | + img := image.NewNRGBA(image.Rect(0, 0, int(width), int(height))) |
| 80 | + copy(img.Pix, pix) |
| 81 | + |
| 82 | + return img, cfg, nil |
| 83 | +} |
| 84 | + |
| 85 | +func (m *module) write(ptr int32, data []byte) bool { |
| 86 | + if ptr < 0 || int(ptr)+len(data) > len(m.memory) { |
| 87 | + return false |
| 88 | + } |
| 89 | + copy(m.memory[ptr:], data) |
| 90 | + return true |
| 91 | +} |
| 92 | + |
| 93 | +func (m *module) read(ptr, size int32) ([]byte, bool) { |
| 94 | + if ptr < 0 || size < 0 || int(ptr)+int(size) > len(m.memory) { |
| 95 | + return nil, false |
| 96 | + } |
| 97 | + return m.memory[ptr : ptr+size : ptr+size], true |
| 98 | +} |
0 commit comments