Created
June 2, 2017 00:48
-
-
Save rtgnx/05626bd14545ad7ca76bd57687a2a813 to your computer and use it in GitHub Desktop.
Solution to challenge from live stream (https://goo.gl/jRPkth)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
/* | |
Solution to challenge from live stream (https://goo.gl/jRPkth) | |
Generate colormap | |
perl -e ' print "\xff\x00\x00\x00\xff\x00\x00\x00\xff\xff\xff\x00"; print "\x00"x12;' > colormap.bin | |
$: go run png_fix.go file.png colormap.bin | |
*/ | |
import ( | |
"bytes" | |
"encoding/binary" | |
"fmt" | |
"hash/crc32" | |
"io" | |
"io/ioutil" | |
"os" | |
) | |
const ( | |
CHUNK_START_OFFSET = 8 | |
) | |
type chunk struct { | |
Length uint32 | |
Type [4]byte | |
Data []byte | |
CRC uint32 | |
} | |
func Decode(r io.ReadSeeker) []chunk { | |
var chunks = make([]chunk, 0, 0) | |
r.Seek(CHUNK_START_OFFSET, os.SEEK_SET) | |
for { | |
var ch chunk | |
err := binary.Read(r, binary.BigEndian, &ch.Length) | |
if err != nil { | |
break | |
} | |
err = binary.Read(r, binary.BigEndian, &ch.Type) | |
if err != nil { | |
break | |
} | |
ch.Data = make([]byte, ch.Length) | |
err = binary.Read(r, binary.BigEndian, ch.Data) | |
if err != nil { | |
break | |
} | |
err = binary.Read(r, binary.BigEndian, &ch.CRC) | |
chunks = append(chunks, ch) | |
} | |
return chunks | |
} | |
func is_png(fd *os.File) bool { | |
fd.Seek(1, os.SEEK_SET) | |
buf := make([]byte, 3) | |
if _, err := fd.Read(buf); err != nil { | |
return false | |
} | |
if string(buf) == "PNG" { | |
return true | |
} | |
return false | |
} | |
func main() { | |
if len(os.Args) < 3 { | |
fmt.Printf("file.png colormap.bin\n") | |
os.Exit(-1) | |
} | |
path := os.Args[1] | |
fd, err := os.Open(path) | |
if err != nil { | |
os.Exit(-2) | |
} | |
defer fd.Close() | |
chunks := Decode(fd) | |
fd_plte, err := os.Open(os.Args[2]) | |
if err != nil { | |
panic(err.Error()) | |
} | |
buff, err := ioutil.ReadAll(fd_plte) | |
if err != nil { | |
panic(err.Error()) | |
} | |
fmt.Printf("Color map loaded\n") | |
fmt.Printf("[%x]\n", buff) | |
save_png(chunks, "mod.png", buff) | |
} | |
func save_png(chunks []chunk, fname string, plte []byte) { | |
fd, err := os.OpenFile(fname, os.O_WRONLY|os.O_CREATE, 0660) | |
if err != nil { | |
panic(err.Error()) | |
} | |
defer fd.Close() | |
header := []byte{0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a} | |
_, err = fd.Write(header) | |
if err != nil { | |
panic(err.Error()) | |
} | |
fmt.Printf("CHUNK\tCRC32\n") | |
fmt.Printf("--------------\n") | |
for _, ch := range chunks { | |
fmt.Printf("%s: 0x%x\n", ch.Type, ch.CRC) | |
binary.Write(fd, binary.BigEndian, ch.Length) | |
binary.Write(fd, binary.BigEndian, ch.Type) | |
// I know right, it ain't perfect. | |
if ch.Type[0] == 0x50 && plte != nil { | |
binary.Write(fd, binary.BigEndian, plte) | |
table := crc32.MakeTable(crc32.IEEE) | |
var buffer bytes.Buffer | |
binary.Write(&buffer, binary.BigEndian, ch.Type) | |
buffer.Write(plte) | |
crc := crc32.Checksum(buffer.Bytes(), table) | |
binary.Write(fd, binary.BigEndian, crc) | |
fmt.Printf("PLTE: 0x%x [UPDATE]\n", crc) | |
continue | |
} | |
binary.Write(fd, binary.BigEndian, ch.Data) | |
binary.Write(fd, binary.BigEndian, ch.CRC) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment