gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

png.go (2591B)


      1 /*
      2    exif-terminator
      3    Copyright (C) 2022 SuperSeriousBusiness admin@gotosocial.org
      4 
      5    This program is free software: you can redistribute it and/or modify
      6    it under the terms of the GNU Affero General Public License as published by
      7    the Free Software Foundation, either version 3 of the License, or
      8    (at your option) any later version.
      9 
     10    This program is distributed in the hope that it will be useful,
     11    but WITHOUT ANY WARRANTY; without even the implied warranty of
     12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13    GNU Affero General Public License for more details.
     14 
     15    You should have received a copy of the GNU Affero General Public License
     16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 */
     18 
     19 package terminator
     20 
     21 import (
     22 	"encoding/binary"
     23 	"io"
     24 
     25 	pngstructure "github.com/dsoprea/go-png-image-structure/v2"
     26 )
     27 
     28 type pngVisitor struct {
     29 	ps               *pngstructure.PngSplitter
     30 	writer           io.Writer
     31 	lastWrittenChunk int
     32 }
     33 
     34 func (v *pngVisitor) split(data []byte, atEOF bool) (int, []byte, error) {
     35 	// execute the ps split function to read in data
     36 	advance, token, err := v.ps.Split(data, atEOF)
     37 	if err != nil {
     38 		return advance, token, err
     39 	}
     40 
     41 	// if we haven't written anything at all yet, then write the png header back into the writer first
     42 	if v.lastWrittenChunk == -1 {
     43 		if _, err := v.writer.Write(pngstructure.PngSignature[:]); err != nil {
     44 			return advance, token, err
     45 		}
     46 	}
     47 
     48 	// check if the splitter has any new chunks in it that we haven't written yet
     49 	chunkSlice := v.ps.Chunks()
     50 	chunks := chunkSlice.Chunks()
     51 	for i, chunk := range chunks {
     52 		// look through all the chunks in the splitter
     53 		if i > v.lastWrittenChunk {
     54 			// we've got a chunk we haven't written yet! write it...
     55 			if err := v.writeChunk(chunk); err != nil {
     56 				return advance, token, err
     57 			}
     58 			// then remove the data
     59 			chunk.Data = chunk.Data[:0]
     60 			// and update
     61 			v.lastWrittenChunk = i
     62 		}
     63 	}
     64 
     65 	return advance, token, err
     66 }
     67 
     68 func (v *pngVisitor) writeChunk(chunk *pngstructure.Chunk) error {
     69 	if err := binary.Write(v.writer, binary.BigEndian, chunk.Length); err != nil {
     70 		return err
     71 	}
     72 
     73 	if _, err := v.writer.Write([]byte(chunk.Type)); err != nil {
     74 		return err
     75 	}
     76 
     77 	if chunk.Type == pngstructure.EXifChunkType {
     78 		blank := make([]byte, len(chunk.Data))
     79 		if _, err := v.writer.Write(blank); err != nil {
     80 			return err
     81 		}
     82 	} else {
     83 		if _, err := v.writer.Write(chunk.Data); err != nil {
     84 			return err
     85 		}
     86 	}
     87 
     88 	if err := binary.Write(v.writer, binary.BigEndian, chunk.Crc); err != nil {
     89 		return err
     90 	}
     91 
     92 	return nil
     93 }