summaryrefslogtreecommitdiff
path: root/vendor/github.com/dsoprea/go-png-image-structure/v2/png.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/dsoprea/go-png-image-structure/v2/png.go')
-rw-r--r--vendor/github.com/dsoprea/go-png-image-structure/v2/png.go416
1 files changed, 0 insertions, 416 deletions
diff --git a/vendor/github.com/dsoprea/go-png-image-structure/v2/png.go b/vendor/github.com/dsoprea/go-png-image-structure/v2/png.go
deleted file mode 100644
index fbb022887..000000000
--- a/vendor/github.com/dsoprea/go-png-image-structure/v2/png.go
+++ /dev/null
@@ -1,416 +0,0 @@
-package pngstructure
-
-import (
- "bytes"
- "errors"
- "fmt"
- "io"
-
- "encoding/binary"
- "hash/crc32"
-
- "github.com/dsoprea/go-exif/v3"
- "github.com/dsoprea/go-exif/v3/common"
- "github.com/dsoprea/go-logging"
- "github.com/dsoprea/go-utility/v2/image"
-)
-
-var (
- PngSignature = [8]byte{137, 'P', 'N', 'G', '\r', '\n', 26, '\n'}
- EXifChunkType = "eXIf"
- IHDRChunkType = "IHDR"
-)
-
-var (
- ErrNotPng = errors.New("not png data")
- ErrCrcFailure = errors.New("crc failure")
-)
-
-// ChunkSlice encapsulates a slice of chunks.
-type ChunkSlice struct {
- chunks []*Chunk
-}
-
-func NewChunkSlice(chunks []*Chunk) *ChunkSlice {
- if len(chunks) == 0 {
- log.Panicf("ChunkSlice must be initialized with at least one chunk (IHDR)")
- } else if chunks[0].Type != IHDRChunkType {
- log.Panicf("first chunk in any ChunkSlice must be an IHDR")
- }
-
- return &ChunkSlice{
- chunks: chunks,
- }
-}
-
-func NewPngChunkSlice() *ChunkSlice {
-
- ihdrChunk := &Chunk{
- Type: IHDRChunkType,
- }
-
- ihdrChunk.UpdateCrc32()
-
- return NewChunkSlice([]*Chunk{ihdrChunk})
-}
-
-func (cs *ChunkSlice) String() string {
- return fmt.Sprintf("ChunkSlize<LEN=(%d)>", len(cs.chunks))
-}
-
-// Chunks exposes the actual slice.
-func (cs *ChunkSlice) Chunks() []*Chunk {
- return cs.chunks
-}
-
-// Write encodes and writes all chunks.
-func (cs *ChunkSlice) WriteTo(w io.Writer) (err error) {
- defer func() {
- if state := recover(); state != nil {
- err = log.Wrap(state.(error))
- }
- }()
-
- _, err = w.Write(PngSignature[:])
- log.PanicIf(err)
-
- // TODO(dustin): !! This should respect the safe-to-copy characteristic.
- for _, c := range cs.chunks {
- _, err := c.WriteTo(w)
- log.PanicIf(err)
- }
-
- return nil
-}
-
-// Index returns a map of chunk types to chunk slices, grouping all like chunks.
-func (cs *ChunkSlice) Index() (index map[string][]*Chunk) {
- index = make(map[string][]*Chunk)
- for _, c := range cs.chunks {
- if grouped, found := index[c.Type]; found == true {
- index[c.Type] = append(grouped, c)
- } else {
- index[c.Type] = []*Chunk{c}
- }
- }
-
- return index
-}
-
-// FindExif returns the the segment that hosts the EXIF data.
-func (cs *ChunkSlice) FindExif() (chunk *Chunk, err error) {
- defer func() {
- if state := recover(); state != nil {
- err = log.Wrap(state.(error))
- }
- }()
-
- index := cs.Index()
-
- if chunks, found := index[EXifChunkType]; found == true {
- return chunks[0], nil
- }
-
- log.Panic(exif.ErrNoExif)
-
- // Never called.
- return nil, nil
-}
-
-// Exif returns an `exif.Ifd` instance with the existing tags.
-func (cs *ChunkSlice) Exif() (rootIfd *exif.Ifd, data []byte, err error) {
- defer func() {
- if state := recover(); state != nil {
- err = log.Wrap(state.(error))
- }
- }()
-
- chunk, err := cs.FindExif()
- log.PanicIf(err)
-
- im, err := exifcommon.NewIfdMappingWithStandard()
- log.PanicIf(err)
-
- ti := exif.NewTagIndex()
-
- // TODO(dustin): Refactor and support `exif.GetExifData()`.
-
- _, index, err := exif.Collect(im, ti, chunk.Data)
- log.PanicIf(err)
-
- return index.RootIfd, chunk.Data, nil
-}
-
-// ConstructExifBuilder returns an `exif.IfdBuilder` instance (needed for
-// modifying) preloaded with all existing tags.
-func (cs *ChunkSlice) ConstructExifBuilder() (rootIb *exif.IfdBuilder, err error) {
- defer func() {
- if state := recover(); state != nil {
- err = log.Wrap(state.(error))
- }
- }()
-
- rootIfd, _, err := cs.Exif()
- log.PanicIf(err)
-
- ib := exif.NewIfdBuilderFromExistingChain(rootIfd)
-
- return ib, nil
-}
-
-// SetExif encodes and sets EXIF data into this segment.
-func (cs *ChunkSlice) SetExif(ib *exif.IfdBuilder) (err error) {
- defer func() {
- if state := recover(); state != nil {
- err = log.Wrap(state.(error))
- }
- }()
-
- // Encode.
-
- ibe := exif.NewIfdByteEncoder()
-
- exifData, err := ibe.EncodeToExif(ib)
- log.PanicIf(err)
-
- // Set.
-
- exifChunk, err := cs.FindExif()
- if err == nil {
- // EXIF chunk already exists.
-
- exifChunk.Data = exifData
- exifChunk.Length = uint32(len(exifData))
- } else {
- if log.Is(err, exif.ErrNoExif) != true {
- log.Panic(err)
- }
-
- // Add a EXIF chunk for the first time.
-
- exifChunk = &Chunk{
- Type: EXifChunkType,
- Data: exifData,
- Length: uint32(len(exifData)),
- }
-
- // Insert it after the IHDR chunk (it's a reliably appropriate place to
- // put it).
- cs.chunks = append(cs.chunks[:1], append([]*Chunk{exifChunk}, cs.chunks[1:]...)...)
- }
-
- exifChunk.UpdateCrc32()
-
- return nil
-}
-
-// PngSplitter hosts the princpal `Split()` method uses by `bufio.Scanner`.
-type PngSplitter struct {
- chunks []*Chunk
- currentOffset int
-
- doCheckCrc bool
- crcErrors []string
-}
-
-func (ps *PngSplitter) Chunks() *ChunkSlice {
- return NewChunkSlice(ps.chunks)
-}
-
-func (ps *PngSplitter) DoCheckCrc(doCheck bool) {
- ps.doCheckCrc = doCheck
-}
-
-func (ps *PngSplitter) CrcErrors() []string {
- return ps.crcErrors
-}
-
-func NewPngSplitter() *PngSplitter {
- return &PngSplitter{
- chunks: make([]*Chunk, 0),
- doCheckCrc: true,
- crcErrors: make([]string, 0),
- }
-}
-
-// Chunk describes a single chunk.
-type Chunk struct {
- Offset int
- Length uint32
- Type string
- Data []byte
- Crc uint32
-}
-
-func (c *Chunk) String() string {
- return fmt.Sprintf("Chunk<OFFSET=(%d) LENGTH=(%d) TYPE=[%s] CRC=(%d)>", c.Offset, c.Length, c.Type, c.Crc)
-}
-
-func calculateCrc32(chunk *Chunk) uint32 {
- c := crc32.NewIEEE()
-
- c.Write([]byte(chunk.Type))
- c.Write(chunk.Data)
-
- return c.Sum32()
-}
-
-func (c *Chunk) UpdateCrc32() {
- c.Crc = calculateCrc32(c)
-}
-
-func (c *Chunk) CheckCrc32() bool {
- expected := calculateCrc32(c)
- return c.Crc == expected
-}
-
-// Bytes encodes and returns the bytes for this chunk.
-func (c *Chunk) Bytes() []byte {
- defer func() {
- if state := recover(); state != nil {
- err := log.Wrap(state.(error))
- log.Panic(err)
- }
- }()
-
- if len(c.Data) != int(c.Length) {
- log.Panicf("length of data not correct")
- }
-
- preallocated := make([]byte, 0, 4+4+c.Length+4)
- b := bytes.NewBuffer(preallocated)
-
- err := binary.Write(b, binary.BigEndian, c.Length)
- log.PanicIf(err)
-
- _, err = b.Write([]byte(c.Type))
- log.PanicIf(err)
-
- if c.Data != nil {
- _, err = b.Write(c.Data)
- log.PanicIf(err)
- }
-
- err = binary.Write(b, binary.BigEndian, c.Crc)
- log.PanicIf(err)
-
- return b.Bytes()
-}
-
-// Write encodes and writes the bytes for this chunk.
-func (c *Chunk) WriteTo(w io.Writer) (count int, err error) {
- defer func() {
- if state := recover(); state != nil {
- err = log.Wrap(state.(error))
- }
- }()
-
- if len(c.Data) != int(c.Length) {
- log.Panicf("length of data not correct")
- }
-
- err = binary.Write(w, binary.BigEndian, c.Length)
- log.PanicIf(err)
-
- _, err = w.Write([]byte(c.Type))
- log.PanicIf(err)
-
- _, err = w.Write(c.Data)
- log.PanicIf(err)
-
- err = binary.Write(w, binary.BigEndian, c.Crc)
- log.PanicIf(err)
-
- return 4 + len(c.Type) + len(c.Data) + 4, nil
-}
-
-// readHeader verifies that the PNG header bytes appear next.
-func (ps *PngSplitter) readHeader(r io.Reader) (err error) {
- defer func() {
- if state := recover(); state != nil {
- err = log.Wrap(state.(error))
- }
- }()
-
- len_ := len(PngSignature)
- header := make([]byte, len_)
-
- _, err = r.Read(header)
- log.PanicIf(err)
-
- ps.currentOffset += len_
-
- if bytes.Compare(header, PngSignature[:]) != 0 {
- log.Panic(ErrNotPng)
- }
-
- return nil
-}
-
-// Split fulfills the `bufio.SplitFunc` function definition for
-// `bufio.Scanner`.
-func (ps *PngSplitter) Split(data []byte, atEOF bool) (advance int, token []byte, err error) {
- defer func() {
- if state := recover(); state != nil {
- err = log.Wrap(state.(error))
- }
- }()
-
- // We might have more than one chunk's worth, and, if `atEOF` is true, we
- // won't be called again. We'll repeatedly try to read additional chunks,
- // but, when we run out of the data we were given then we'll return the
- // number of bytes fo rthe chunks we've already completely read. Then,
- // we'll be called again from theend ofthose bytes, at which point we'll
- // indicate that we don't yet have enough for another chunk, and we should
- // be then called with more.
- for {
- len_ := len(data)
- if len_ < 8 {
- return advance, nil, nil
- }
-
- length := binary.BigEndian.Uint32(data[:4])
- type_ := string(data[4:8])
- chunkSize := (8 + int(length) + 4)
-
- if len_ < chunkSize {
- return advance, nil, nil
- }
-
- crcIndex := 8 + length
- crc := binary.BigEndian.Uint32(data[crcIndex : crcIndex+4])
-
- content := make([]byte, length)
- copy(content, data[8:8+length])
-
- c := &Chunk{
- Length: length,
- Type: type_,
- Data: content,
- Crc: crc,
- Offset: ps.currentOffset,
- }
-
- ps.chunks = append(ps.chunks, c)
-
- if c.CheckCrc32() == false {
- ps.crcErrors = append(ps.crcErrors, type_)
-
- if ps.doCheckCrc == true {
- log.Panic(ErrCrcFailure)
- }
- }
-
- advance += chunkSize
- ps.currentOffset += chunkSize
-
- data = data[chunkSize:]
- }
-
- return advance, nil, nil
-}
-
-var (
- // Enforce interface conformance.
- _ riimage.MediaContext = new(ChunkSlice)
-)