media_parser.go (2389B)
1 package pngstructure 2 3 import ( 4 "bufio" 5 "bytes" 6 "image" 7 "io" 8 "os" 9 10 "image/png" 11 12 "github.com/dsoprea/go-logging" 13 "github.com/dsoprea/go-utility/v2/image" 14 ) 15 16 // PngMediaParser knows how to parse a PNG stream. 17 type PngMediaParser struct { 18 } 19 20 // NewPngMediaParser returns a new `PngMediaParser` struct. 21 func NewPngMediaParser() *PngMediaParser { 22 23 // TODO(dustin): Add test 24 25 return new(PngMediaParser) 26 } 27 28 // Parse parses a PNG stream given a `io.ReadSeeker`. 29 func (pmp *PngMediaParser) Parse(rs io.ReadSeeker, size int) (mc riimage.MediaContext, err error) { 30 defer func() { 31 if state := recover(); state != nil { 32 err = log.Wrap(state.(error)) 33 } 34 }() 35 36 // TODO(dustin): Add test 37 38 ps := NewPngSplitter() 39 40 err = ps.readHeader(rs) 41 log.PanicIf(err) 42 43 s := bufio.NewScanner(rs) 44 45 // Since each segment can be any size, our buffer must be allowed to grow 46 // as large as the file. 47 buffer := []byte{} 48 s.Buffer(buffer, size) 49 s.Split(ps.Split) 50 51 for s.Scan() != false { 52 } 53 54 log.PanicIf(s.Err()) 55 56 return ps.Chunks(), nil 57 } 58 59 // ParseFile parses a PNG stream given a file-path. 60 func (pmp *PngMediaParser) ParseFile(filepath string) (mc riimage.MediaContext, err error) { 61 defer func() { 62 if state := recover(); state != nil { 63 err = log.Wrap(state.(error)) 64 } 65 }() 66 67 f, err := os.Open(filepath) 68 log.PanicIf(err) 69 70 defer f.Close() 71 72 stat, err := f.Stat() 73 log.PanicIf(err) 74 75 size := stat.Size() 76 77 chunks, err := pmp.Parse(f, int(size)) 78 log.PanicIf(err) 79 80 return chunks, nil 81 } 82 83 // ParseBytes parses a PNG stream given a byte-slice. 84 func (pmp *PngMediaParser) ParseBytes(data []byte) (mc riimage.MediaContext, err error) { 85 defer func() { 86 if state := recover(); state != nil { 87 err = log.Wrap(state.(error)) 88 } 89 }() 90 91 // TODO(dustin): Add test 92 93 br := bytes.NewReader(data) 94 95 chunks, err := pmp.Parse(br, len(data)) 96 log.PanicIf(err) 97 98 return chunks, nil 99 } 100 101 // LooksLikeFormat returns a boolean indicating whether the stream looks like a 102 // PNG image. 103 func (pmp *PngMediaParser) LooksLikeFormat(data []byte) bool { 104 return bytes.Compare(data[:len(PngSignature)], PngSignature[:]) == 0 105 } 106 107 // GetImage returns an image.Image-compatible struct. 108 func (pmp *PngMediaParser) GetImage(r io.Reader) (img image.Image, err error) { 109 img, err = png.Decode(r) 110 log.PanicIf(err) 111 112 return img, nil 113 } 114 115 var ( 116 // Enforce interface conformance. 117 _ riimage.MediaParser = new(PngMediaParser) 118 )