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 }