Skip to content

Instantly share code, notes, and snippets.

@rtgnx
Created June 2, 2017 00:48
Show Gist options
  • Save rtgnx/05626bd14545ad7ca76bd57687a2a813 to your computer and use it in GitHub Desktop.
Save rtgnx/05626bd14545ad7ca76bd57687a2a813 to your computer and use it in GitHub Desktop.
Solution to challenge from live stream (https://goo.gl/jRPkth)
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