go语言实现将重要数据写入图片中
作者:hebedich 发布时间:2024-02-10 02:15:38
标签:go语言,写入,图片
原理:将数据的二进制形式写入图像红色通道数据二进制的低位
只支持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 := int(ReadShadowLength(head))
var bk []byte = make([]byte, length*8)
b = make([]byte, length)
_, err = SetImage(im, func(index, x, y int, in, out image.Image) {
if index >= 64 && index < length*8+64 {
R := readRGBAColor(im.At(x, y)).R
bk[index-64] = uint8(R & 1)
}
})
var bb [8]byte
var bs []byte
for i := 0; i < length; i++ {
bs = bk[8*i : 8*(i+1)]
for j := 0; j < 8; j++ {
bb[j] = bs[j]
}
b[i] = Bits2Byte(bb)
}
return
}
func ReadShadowHeader(im image.Image) (b [8]byte, err error) {
var bm [64]byte
_, err = SetImage(im, func(index, x, y int, in, out image.Image) {
rgba := readRGBAColor(im.At(x, y))
if index < 64 {
bm[index] = uint8(rgba.R & 1)
}
})
if err != nil {
return
}
var bb [8]byte
var bs []byte
for i := 0; i < 8; i++ {
bs = bm[8*i : 8*(i+1)]
for j := 0; j < 8; j++ {
bb[j] = bs[j]
}
b[i] = Bits2Byte(bb)
}
return
}
func ReadShadowFlag(b [8]byte) (a [4]byte) {
for i := 0; i < 4; i++ {
a[i] = b[i]
}
return
}
func ReadShadowLength(b [8]byte) uint32 {
var bb [4]byte
for i := 4; i < 8; i++ {
bb[i-4] = b[i]
}
return Bytes2Uint32(bb)
}
func OpenImage(path string) (image.Image, error) {
im_read, err := os.Open(path)
defer im_read.Close()
if err != nil {
return nil, err
}
im, _, err := image.Decode(im_read)
if err != nil {
return nil, err
}
return im, nil
}
//modify image
func SetImage(im image.Image, f func(index, x, y int, in, out image.Image)) (out image.Image, err error) {
if f == nil {
return im, nil
}
index := 0
bounds := im.Bounds()
out = image.NewRGBA(bounds)
var m *image.RGBA = out.(*image.RGBA)
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
m.Set(x, y, im.At(x, y))
f(index, x, y, im, out)
index += 1
}
}
return out, nil
}
//conert any color to RABGA color.
func readRGBAColor(from_color color.Color) color.RGBA {
return color.RGBAModel.Convert(from_color).(color.RGBA)
}
//only write to jpeg formats.
func WriteImage(path string, im image.Image) error {
out, err := os.OpenFile(path, os.O_CREATE, os.ModePerm)
defer out.Close()
if err != nil {
return err
}
err = png.Encode(out, im)
if err != nil {
return err
}
return nil
}
var read_in string
var write_out string
var data string
func init() {
flag.StringVar(&read_in, "in", "", "image path read in.")
flag.StringVar(&write_out, "out", "out.jpg", "image path write out.")
flag.StringVar(&data, "data", "", "data to shadow.")
}
func errHandle(err error) {
if err != nil {
log.Fatal(err)
}
}
func main() {
flag.Parse()
if read_in == "" {
fmt.Println("Options:")
flag.PrintDefaults()
return
}
im, err := OpenImage(read_in)
errHandle(err)
if data != "" {
out, err := WriteShadow([]byte(data), im)
errHandle(err)
err = WriteImage(write_out, out)
errHandle(err)
} else {
head, err := ReadShadowHeader(im)
errHandle(err)
_flag := ReadShadowFlag(head)
if _flag != FLAG {
fmt.Println("image doesn't have shadow data.")
return
}
data, err := ReadShadowData(im)
errHandle(err)
fmt.Println("shadow:", string(data))
}
}
以上所述就是本文的全部内容了,希望大家能够喜欢。
0
投稿
猜你喜欢
- 编写思路:把本地文件在客户端通过base64编码以后发送目的地.测试过程中,上传文件过大,导致超时不成功,后来经过改善.把编码分
- 在这里我们介绍两个拼接数组的方法:np.vstack():在竖直方向上堆叠np.hstack():在水平方向上平铺import numpy
- 目的获得一个首尾不含多余空格的字符串方法 可以使用字符串的以下方法处理:string.lstrip(s[, chars])Return a
- 置信椭圆原理及椭圆图形绘制置信椭圆长短轴计算def confidence_oval(self,factor, ppf_rate): &nbs
- 看到这个文章肯定一点就是你把sql没有装到C盘里,呵呵不用怕看下面在安装的时候要注意:在安装SQL Server 2005 Express时
- 这里介绍了5中python获取window桌面路径的方法,获取这个路径有什么用呢?一般是将程序生成的文档输出到桌面便于查看编辑。前两个方法是
- 需求有多个文件地理数据库(gdb),数据库内有多个面要素类图层,每个图层不能有自重叠,也不能和其他图层重叠。所以,需要为每个文件地理数据库(
- 最近在学习Golang语言,中间遇到一个前辈指点,有一个学习原则:Learning By Doing。跟我之前学习Java的经验高度契合。在
- 当多个事务同时持有和请求同一资源上的锁而产生循环依赖的时候就产生了死锁。死锁发生在事务试图以不同的顺序锁定资源。以StockPrice表上的
- 最常见的XML数据类型有:Element, Attribute,Comment, Text. &nbs
- from flask import requestFlask 是一个人气非常高的Python Web框架,笔者也拿它写过一些大大小小的项目,
- 调用Windows API锁定计算机本来想用Python32直接调用,可是没有发现Python32有Windows API LockWork
- java匹配字符串表达式在我们数据处理方面是及其重要的,现在就把我这几天数据处理比较常用的向大家介绍一下,常规的一些匹配方式就不介绍了,我们
- Mysql慢查询解释MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阀值的语句,具体指运行时间超过
- 迪杰斯特拉(Dijkstra)算法主要是针对没有负值的有向图,求解其中的单一起点到其他顶点的最短路径算法。1 算法原理迪杰斯特拉(Dijks
- class Account(object): "一个简单的类" account_type="Basic&quo
- 该章节将学习关于文件查找的操作,大家都知道,无论是 Linux 系统还是 Windows 系统都有基于文件名实现过滤、查找的功能。但是如果想
- 1. 引言词云图可以让我们方便地识别出文本中的关键词,其中单词的大小代表它们的频率。有了这个,我们甚至在阅读之前就可以很好地了解文本的内容。
- int(整型)在32位机器上,整数的位数为32位,取值范围为-2**31~2**31-1,即-2147483648~2147483647在6
- 前言本文总结了mysql中DCL,常用的一些权限控制,后续使用到其他会继续补充。一、用户控制管理创建用户create user '用