原理:将数据的二进制形式写入图像红色通道数据二进制的低位
只支持png格式的输出
写入数据
go run shadow.go -in="c.jpg" -data="hide me" -out="out.png"
读取数据
go run shadow.go -in="out.png"
package main
import (
"errors"
"flag"
"fmt"
"image"
"image/color"
_ "image/jpeg"
"image/png"
"log"
"math"
"os"
)
var FLAG = [4]byte{0x13, 0x14, 0x52, 0x00} //shadow flag.
//byte to 8 bits
func Byte2bits(b byte) (a [8]byte) {
var c uint8 = 7
var i uint8
for i = 0; i < 8; i++ {
a[i] = b >> (c - i) & 1
}
return
}
//8 bits to byte.
func Bits2Byte(a [8]byte) (b byte) {
for i := 0; i < 8; i++ {
b += a[i] * uint8(math.Pow(2, float64(7-i)))
}
return
}
//uint32 to 4 bytes.
func Uint32ToBytes(i uint32) (b [4]byte) {
b[0] = uint8(i >> 24)
b[1] = uint8(i >> 16 & 0xffff)
b[2] = uint8(i >> 8 & 0xff)
b[3] = uint8(i & 0xff)
return
}
//4 bytes to uint32.
func Bytes2Uint32(b [4]byte) (i uint32) {
var j uint32
for ; j < 4; j++ {
i += uint32(b[j]) << (24 - j*8)
}
return
}
func BuildShadowHeader(length uint32) (b [8]byte) {
var i int
for ; i < 4; i++ {
b[i] = FLAG[i]
}
a := Uint32ToBytes(length)
for ; i < 8; i++ {
b[i] = a[i-4]
}
return
}
func WriteShadow(b []byte, im image.Image) (out image.Image, err error) {
max := im.Bounds().Max.X*im.Bounds().Max.Y/8 - 64
b_len := len(b)
if len(b) > max {
return nil, errors.New("image does not have enough space for shadow.")
}
head := BuildShadowHeader(uint32(b_len))
var bb byte
var bs [8]byte
var i int
out, err = SetImage(im, func(index, x, y int, in, out image.Image) {
rgba := readRGBAColor(im.At(x, y))
if index < b_len*8+64 {
if index < 64 {
bb = head[index/8]
} else {
bb = b[index/8-8]
}
bs = Byte2bits(bb)
i = index % 8
if bs[i] != rgba.R&1 {
if bs[i] == 0 {
rgba.R -= 1
} else {
rgba.R += 1
}
}
}
if v := out.(*image.RGBA); v != nil {
v.SetRGBA(x, y, rgba)
}
})
if err != nil {
return nil, err
}
return
}
func ReadShadowData(im image.Image) (b []byte, err error) {
head, err := ReadShadowHeader(im)
if err != nil {
return nil, err
}
length#B"#ТffffffffrVfV2#Тfffffff&WGWТfff
|