画像にデータを色情報として埋め込むテスト

twitterでちょっとしたスクリプトみたいなものを共有したくても
文字数の関係でできなかったりするので画像に情報に埋め込んで共有できないかテストです

可逆圧縮フォーマットならピクセル単位で細かく詰め込むこともできるところですが
~~twitterでは一定サイズ以上は強制的にJPEGになるためJPEGの圧縮単位の８ピクセルを塗りつぶしたデータを作成するようにしています~~ 
追記：８×８でも色情報は可逆にならないようで復元できませんでした
JPEGはモノクロでしかテストしていなかったので失敗です　とりあえず記事はそのままにします

Blenderのツールの部品としてのテストなので テキスト読み書きとイメージ作成はBlenderの機能ですが
他の環境でも大きな違いはないかと思います

```py:text2imsge
import bpy
import zlib
import struct
import math
import numpy as np
# 画像にデータを色情報として埋め込む
def pack_data(bin_data):
    check_sum = zlib.crc32(bin_data)
    chunk_data = struct.pack('>q',check_sum)
    chunk_data += struct.pack('>i',len(bin_data))
    chunk_data += bin_data
    return(chunk_data)

def hex2pixelarray(byte_data, width, block_size):
    tile_u = width // block_size
    tile_v = math.ceil( len(byte_data) /tile_u /3 ) 
    # 諧調数
    n = 1/15
    pix_data = [n * int(b, 16) for b in byte_data]
    pix_len = tile_u*tile_v
    pix_array = np.ones( pix_len *3)
    pix_array[:len(pix_data)] = pix_data
    pix_array = pix_array.reshape(pix_len, 3)
    # アルファ情報を付加
    alpha_array = np.ones(pix_len).reshape(pix_len,1)
    pix_array = np.append(pix_array, alpha_array, axis= 1)
    pix_array = pix_array.reshape(tile_v,tile_u, 4)    
    # 8*8のブロックに拡大
    block_image = pix_array.repeat(block_size, axis=0).repeat(block_size, axis=1)
    return(block_image)

img_name = 'rasyoumon.png'
width = 1000
block_size = 8
# ファイル内のrasyoumon.txt のテキストを読み込み
txt_data = bpy.data.texts['rasyoumon.txt'].as_string()
# 文字データを圧縮バイナリデータに
bin_data = zlib.compress(txt_data.encode('utf-8'))
# 16進文字列に変換
byte_data = pack_data(bin_data).hex()
# 16s進データを画像情報に
block_image = hex2pixelarray(byte_data, width, block_size)
height = block_image.shape[0]
# 画像データの作成
image_object = bpy.data.images.new(name=img_name, width=width, height=height)
image_object.pixels = list(block_image.flatten())
```
テキストデータをZlib圧縮の上、データの長さとチェックサムを加えて　色情報にしています

同じ.blendファイル内に青空文庫にある[芥川龍之介の羅生門のテキスト](https://www.aozora.gr.jp/cards/000879/files/127_15260.html)をrasyoumon.txtとして読み込み
上記スクリプトで変換した画像はこうなりました
![rasyoumon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/80e29087-be8c-db9c-f9c8-4a7731ad5b47.png)
このモザイク状の画像からテキストデータを復元するのは

```py:img2text.py
import bpy
import struct
import zlib
import numpy as np

block_size = 8
image_name = 'rasyoumon.png'

def img_to_nparray(img):
    bit_len = len(img.pixels)
    (width,height) = img.size
    channels = img.channels #色数
    pix_array = np.array(img.pixels)
    pix_array = pix_array.reshape( height, width, channels)
    return( pix_array )

def pix2bin(pix_array):
    '''画像の値をバイナリに変換'''
    byte_data = ''
    n = 1/15
    for i in range(len(pix_array)):
        byte_data += hex(int(round(pix_array[i]/n)))[2]
    return( bytes.fromhex(byte_data) )
# 画像の読み込み
image_object = bpy.data.images[image_name]
data_array = img_to_nparray(image_object)
# 画像から情報部分のみ取り出し
data_array = data_array[0::block_size, 0::block_size, :3].flatten()
# データの変換
checksum = struct.unpack('>q',pix2bin(data_array[:16]) )[0]
data_length = struct.unpack('>i',pix2bin(data_array[16:24]) )[0]
pix_data = pix2bin(data_array[24:24 + data_length*2])
 
if checksum == zlib.crc32(pix_data):
    decomp_data = zlib.decompress(pix_data)
    text_data = decomp_data.decode('utf-8')
    # テキストデータの書き出し
    text_obj = bpy.data.texts.new('test_output')
    text_obj.write(text_data)
```
こんな感じになりました。
何かの参考になれば幸いです