Webã§ãã䜿ãããPNGç»å圢åŒãšããã®ã¯ãæ¯èŒçåçŽã§æ¡åŒµæ§ã®é«ããã¡ã€ã«åœ¢åŒãšãªã£ãŠããŸããä»åã¯æ¡åŒµæ§ã®é«ããæŽ»ãããŠãPNGç»åã®äžã«æå·æãæžã蟌ããšããããã°ã©ã ãäœã£ãŠã¿ãŸãããã
PNGç»åã®æå·æãåã蟌ãããã°ã©ã ãäœãã
ååãPNGç»åãäŸã«Goèšèªã§ãã€ããªæäœãè¡ãæ¹æ³ã玹ä»ããŸãããããããååäœã£ãããã°ã©ã ã¯ããã ãã¡ã€ã«ãèªã¿èŸŒã¿ãç»åãã¡ã€ã«ã®ãµã€ãºã衚瀺ããã ãã§ãããããã§ãä»åã¯PNGç»åã®æ¡åŒµæ§ã®é«ããå©çšããŠç»åã«æå·æãæžã蟌ããšããããã°ã©ã ãäœã£ãŠã¿ãŸãããã
PNGç»åã«ããã¹ããåã蟌ãããšãåºæ¥ãã°ãç»åã«èŠããããç§å¯ã®ã¡ãã»ãŒãžãéåä¿¡ããããã¡ãã»ãŒãžä»ãã®PNGç»åãäœãã®ã«å©çšã§ããŸãã
PNGç»åã«ã€ããŠåŸ©ç¿
æ¢ã«åå玹ä»ããŠããŸãããPNGç»åã®ä»æ§ãæ¹ããŠç¢ºèªããŠã¿ãŸããããPNGãã¡ã€ã«ãšããã®ã¯ã以äžã®ããã«ãPNGã·ã°ããã£ã«ç¶ããŠè€æ°ã®ãã£ã³ã¯ãšåŒã°ããããŒã¿ãããã¯ãé£ç¶ãããšããä»çµã¿ã«ãªã£ãŠããŸããã
ããã§ãä»åãæå·åããããã¹ããPNGç»åã«åã蟌ãã®ã§ãããé©åœãªãxANGããšãããã£ã³ã¯ãç¬èªå®çŸ©ããŠãPNGãã¡ã€ã«ã«ãã®ãã£ã³ã¯ãåã蟌ãããã«ããŸãããããŠããã®ãã£ã³ã¯ã«ã¯ãXORã§ç°¡ææå·åããããã¹ããããŒã¿éšåã«èšå®ããããã«ããŸãã
ããããé©åœãªç¬èªãã£ã³ã¯ãåã蟌ãã§ããŸã£ãŠãåé¡ãªãã®ã§ãããããå€ãã®PNGç»åã衚瀺ããç»åãã¥ãŒã¯ãŒã§ã¯ãPNGãã¡ã€ã«ãèªãã§ããæãäžæãªãã£ã³ã¯ãèŠã€ããŠãããã®ãã£ã³ã¯ãèªã¿é£ã°ãããšã«ãªã£ãŠããŸãããã®ãããé©åœã«ç¬èªãã£ã³ã¯ãã§ã£ã¡äžããŠã倧äžå€«ãšããèš³ãªã®ã§ãã
ä»åäœã£ãããã°ã©ã ã§äœæããPNGãã¡ã€ã«ããWebãã©ãŠã¶ãOSæšæºã®ç»åãã¥ãŒã¯ãŒãªã©ã§è¡šç€ºããŠã¿ãŸããããå šãåé¡ãªã衚瀺ã§ããŸãã
PNGç»åãèªã¿èŸŒãããã«æ§é äœãæºå
ããã§ã¯ãããã°ã©ã ã®äœæã«åãããããŸããããååãPNGãã¡ã€ã«ãèªã¿èŸŒã¿ãŸããããPNGãã¡ã€ã«ãèªãã ãã§æžã蟌ãããšãèããŠããŸããã§ãããããã§ãPNGã®ãã£ã³ã¯ãèŠããŠããããã«ãChunkæ§é äœãå®çŸ©ããŠãèªã¿èŸŒãã ããŒã¿ããã®æ§é äœã«ä¿åããŠããããã«ããŸããããããã§å®çŸ©ããChunkæ§é äœã¯ã以äžã®ãããªãã®ã«ããŸãã
type Chunk struct {
Size uint32 // ãã£ã³ã¯ãµã€ãº(4byte)
Type []byte // ãã£ã³ã¯ã¿ã€ã(4byte)
Data []byte // ããŒã¿æ¬äœ(å¯å€é·)
Crc uint32 // CRC32ã®å€(4byte)
}
æ§é äœã®å®çŸ©ãèŠãŠåããããã«PNGã®åãã£ã³ã¯ã¯åºå®é·ã§ã¯ãããŸããããã ããæ¬æ¥Typeã®åã¯ãã¹ã©ã€ã¹ã§ã¯ãªãã[4]byteã®ããã«åºå®é åã«ããã®ãæ£ããã®ã§ãããããã°ã©ã ã®ç°¡æåã®ããã«byteåã®ã¹ã©ã€ã¹ãšããŠå®çŸ©ããŠããŸãã
PNGãã¡ã€ã«ãèªã¿èŸŒãã
ããã§ã¯ãPNGãã¡ã€ã«ãèªã¿èŸŒã¿ãæ§é äœChunkã®ã¹ã©ã€ã¹ãšããŠè¿ãããã°ã©ã ã¯ã以äžã®ããã«ãªããŸãã
// PNGã®ã·ã°ããã£
const pngSignature = "\x89PNG\r\n\x1a\n"
func ReadPNGFile(fname string) ([]Chunk, error) {
// ãã¡ã€ã«ãå
šéšã¡ã¢ãªã«èªã¿èŸŒã --- (*1)
buf, err := ioutil.ReadFile(fname)
if err != nil {
return nil, fmt.Errorf("ãã¡ã€ã«èªã¿èŸŒã¿ãšã©ãŒ")
}
// å
é ã®PNGã·ã°ããã£ãåã蟌ã --- (*2)
r := bytes.NewReader(buf)
if string(readN(r, 8)) != pngSignature {
return nil, fmt.Errorf("PNGãã¡ã€ã«ã§ã¯ãããŸãã")
}
// è€æ°ã®ãã£ã³ã¯ãç¹°ãè¿ãèªã --- (*3)
res := []Chunk{}
for {
// ãµã€ãºãã¿ã€ããããŒã¿ãCRCãé ã«èªã --- (*4)
chunk := Chunk{}
chunk.Size = readInt32(r)
chunk.Type = readN(r, 4)
chunk.Data = readN(r, int(chunk.Size))
chunk.Crc = readInt32(r) // CRC32
if len(chunk.Type) == 0 {
break
}
// æå·æãåã蟌ãŸããŠããã°ç»é¢ã«è¡šç€º --- (*5)
if string(chunk.Type) == "xANG" {
text := xorText(string(chunk.Data), password)
println("[TEXT]", text)
}
res = append(res, chunk) # --- (*6)
}
return res, nil
}
ããã°ã©ã ã®(ïŒ1)ã®éšåã§ã¯ãPNGãã¡ã€ã«ã®å 容ãã¡ã¢ãªã«èªã¿èŸŒã¿ãŸãããããŠã(ïŒ2)ã§ã¯PNGã·ã°ããã£ãæ£ãããã©ããã確èªããŸãããããŠã(ïŒ3)ã®éšåã§ã¯ç¹°ãè¿ããã£ã³ã¯ãèªã¿èŸŒã¿ãŸãã(ïŒ4)ã®éšåã§å®éã«ã¡ã¢ãªããããã£ã³ã¯ãµã€ãºãã¿ã€ããããŒã¿ãCRCã®åå€ãèªã¿èŸŒã¿ãŸãããããŠãèªã¿èŸŒãã ãã£ã³ã¯ã(*6)ã§ã¹ã©ã€ã¹ã«è¿œå ããŸãã
ãã®ãšãã(ïŒ5)ã®éšåã«ããããã«ããã£ã³ã¯ã¿ã€ãããxANGããšããç¬èªãã£ã³ã¯ã§ããã°ãæå·ãè§£é€ããŠç»é¢ã«è¡šç€ºããããã«ããŠããŸãã
PNGãã¡ã€ã«ãäœæããã
次ã«ããã¡ã€ã«ããèªã¿èŸŒãã ããŒã¿ïŒChunkæ§é äœã®ã¹ã©ã€ã¹ïŒãå ã«ããŠãæ°ãã«PNGãã¡ã€ã«ã«ä¿åããããã°ã©ã ãèŠãŠã¿ãŸããããèªã¿èŸŒã¿ãããæžã蟌ã¿ã®æ¹ãç°¡åã§ãã
func WritePNGFile(fname string, chunks []Chunk) error {
// æžã蟌ã¿çšã®ãããã¡ãäœã --- (*1)
buf := bytes.NewBuffer([]byte{})
// ã·ã°ããã£ãæžã蟌ã --- (*2)
buf.Write([]byte(pngSignature))
// ç¹°ãè¿ããã£ã³ã¯ãæžã蟌ã --- (*3)
for _, chunk := range chunks {
if string(chunk.Type) == "IEND" {
continue
}
writeUInt32(buf, chunk.Size) // ãµã€ãºãæžã蟌ã
buf.Write(chunk.Type) // ã¿ã€ããæžã蟌ã
buf.Write(chunk.Data) // ããŒã¿ãæžã蟌ã
writeUInt32(buf, chunk.Crc) // CRCãæžã蟌ã
println("write:", string(chunk.Type))
}
// IENDãæåŸã«æžã蟌ã --- (*4)
writeUInt32(buf, 0)
buf.Write([]byte("IEND"))
buf.Write([]byte{0xAE, 0x42, 0x60, 0x82})
return ioutil.WriteFile(fname, buf.Bytes(), 0644)
}
ããã°ã©ã ã®(ïŒ1)ã®éšåã§ã¯ãæžã蟌ã¿çšã®ãããã¡ãçšæããŸãããããŠã(ïŒ2)ã§ã¯PNGã·ã°ããã£ãæžã蟌ã¿ãŸãã
ãããŠã(*3)ã®éšåã§ç¹°ãè¿ããã£ã³ã¯ãæžã蟌ãã§è¡ããŸãããã£ã³ã¯ã®ãµã€ãºãã¿ã€ããããŒã¿ãCRCå€ãšèªã¿èŸŒãã æãšåãããã«æžã蟌ãã ãã§ãããããŠãæåŸ(ïŒ4)ã«PNGãã¡ã€ã«ã®çµç«¯ã瀺ãIENDãã£ã³ã¯ã远å ããŠãããã¡ã€ã«ã«æžã蟌ã¿ãŸãããã ããPNGãã¡ã€ã«ã®äžçªæåŸã«IENDãã£ã³ã¯ãé 眮ãããããšã«ãªã£ãŠããŸãããã®ããã(ïŒ3)ã®foræã®äžã§ã¯ãIENDãã£ã³ã¯ãæžã蟌ãããšããããforæã®åŸã(ïŒ4)ã§IENDãã£ã³ã¯ãæžã蟌ãããã«ããŠããŸãã
ç¬èªãã£ã³ã¯ã远èšããã
ç¶ããŠãç¬èªãã£ã³ã¯ã远èšããããã°ã©ã ãèŠãŠã¿ãŸããããPNGãã¡ã€ã«ããChunkæ§é äœã®ã¹ã©ã€ã¹ãèªã¿èŸŒãåŸã§ã以äžã®appendAngouChunk颿°ãçšããŠãããã¹ããæå·åããŠè¿œèšããŸãã
// ç¬èªãã£ã³ã¯ã远å
func appendAngouChunk(chunks []Chunk, text string) []Chunk {
chunk := Chunk{ // æ§é äœã«åæå€ãèšå®
Size: uint32(len(text)),
Type: []byte("xANG"),
Data: []byte(xorText(text, password)),
}
checkData := append(chunk.Type, chunk.Data...)
chunk.Crc = crc32.ChecksumIEEE(checkData)
return append(chunks, chunk)
}
ããã§ã¯ãChunkæ§é äœãäœæãããµã€ãºãã¿ã€ããããŒã¿ãCRCå€ãèšå®ãããããã¡ã€ã«ããèªã¿åºãããã£ã³ã¯ã®ã¹ã©ã€ã¹ã«ããã远å ãããšãããã®ã«ãªã£ãŠããŸããããã§ã¯ãç¬èªã®"xANG"ã远èšãããã®ã§ããããã®éšåãèªåã§æžãæãããªããç¬èªã®ãã£ã³ã¯ã¿ã€ããå©çšããŠãPNGã«ç¬èªããŒã¿ãåã蟌ãããšãã§ããŸãã
ããã°ã©ã ãå®è¡ããŠã¿ãã
以äžããããŸã§äœã£ãããã°ã©ã ãåããããã®ãããã¡ãã«ã¢ããããŠããŸããZIPãã¡ã€ã«ãããŠã³ããŒãããŠè§£åãããšãGoã®ãœãŒã¹ãã¡ã€ã«ãpngangou.goããšãã¹ãçšã®PNGç»åãtea.pngããçæãããŸãã
以äžãã³ãã³ãã©ã€ã³äžã§æäœãè¡ããŸããWindowsã§ã¯PowerShellã§ãmacOSã§ã¯ã¿ãŒããã«.appãå©çšããŠæäœããŠãã ããã
ã³ãã³ãã©ã€ã³ã«ä»¥äžã®ã³ãã³ããå®è¡ãããšãWindowsã§ã¯ãpngangou.exeã(macOSã§ã¯ãpngangouã)ãšããå®è¡ãã¡ã€ã«ãçæãããŸãã
go build pngangou.go
ããã§ãçæãããå®è¡ãã¡ã€ã«ã«å¯ŸããŠãã(å ¥åãã¡ã€ã«) (åºåãã¡ã€ã«) (ããã¹ã)ãã®ãããªåŒæ°ãäžãããšãããã¹ããæå·åããŠPNGãã¡ã€ã«ã«åã蟌ã¿ãŸããäŸãã°ããtea.pngãã«ãæãã®ã«æããã 諊ããã®ã«æãããããšããããã¹ããæå·åããŠåã蟌ãã§ã¿ãŸãããã
# Windowsã®å Žå
.\pngangou.exe tea.png out.png "æãã®ã«æããã 諊ããã®ã«æããã"
# macOSã®å Žå
./pngangou tea.png out.png "æãã®ã«æããã 諊ããã®ã«æããã"
ãããŠãåã蟌ãã ããã¹ãã埩å·åããŠèªãã«ã¯ã以äžã®ãããªã³ãã³ããå®è¡ããŸããã€ãŸããå®è¡æåŒæ°ã3ã€ããå Žåã¯ãã¡ã€ã«ãæå·åãã1ã€ã®å Žåã¯åŸ©å·åããŠè¡šç€ºããŸãã
# Windowsã®å Žå
.\pngangou.exe out.png
# macOSã®å Žå
./pngangou out.png
ããã°ã©ã ãå®è¡ãããšãPNGãã¡ã€ã«ã«åã蟌ãã ããã¹ããåãåºããŠåŸ©å·åããŠä»¥äžã®ããã«ç»é¢ã«è¡šç€ºããŸãã
ãŸãšã
以äžãä»åã¯PNGç»åã«ããã¹ããæå·åããŠåã蟌ãããã°ã©ã ãäœã£ãŠã¿ãŸãããPNGã®æ¡åŒµæ§ã®é«ããå©çšãããã®ãªã®ã§ãç»åãã¡ã€ã«ã®äžã«äœãããã®èšå®ããŒã¿ãåã蟌ãããã°ã©ã ã®åèã«ãªãã§ãããããŸããããã§ã¯ãã³ãã³ãã©ã€ã³ããããã¹ããåã蟌ããšããããã°ã©ã ãäœããŸããããæ¹è¯ããŠä»»æã®ãã¡ã€ã«ãªã©ãåã蟌ããããã«ãããšãããå®çšåºŠãé«ããªããšæããŸããåèã«ããŠãã ããã
èªç±åããã°ã©ããŒããããã¯ãã©ã«ãŠãããã°ã©ãã³ã°ã®æ¥œãããäŒããæŽ»åãããŠããã代衚äœã«ãæ¥æ¬èªããã°ã©ãã³ã°èšèªããªã§ããã ãããã¹ã鳿¥œããµã¯ã©ããªã©ã2001幎ãªã³ã©ã€ã³ãœãã倧è³å ¥è³ã2004幎床æªèžãŠãŒã¹ ã¹ãŒããŒã¯ãªãšãŒã¿ã2010幎 OSSè²¢ç®è ç« åè³ãæè¡æžãå€ãå·çããŠããã



