画像ファイルのエンコード
以前作成したSTGもそうですが、友達に配布する時に使用している画像が丸見えになっています。
ゲームを作成した、作成したい人なら一度は検索するワードかもしれません。
exeひとまとめ
画像隠す
などなど。
exeの中にひとまとめにする方法は良くわからなかったので、
画像ファイルをエンコードして見えないようにしたいと思います。
今回は簡単なものを自作します。
そもそもエンコードってなんだというお話し
エンコード(英: encode)、符号化(ふごうか)とは、アナログ信号やデジタルデータに特定の方法で、後に元の(あるいは類似の)信号またはデータに戻せるような変換を加えることである。
今回で言うと 画像データに特定の方法で、元に戻せるような変換を加えること
まずは変換した画像データは一般ユーザーに画像として認識されない事を目標とします。
最近流行りのいらすとやからお借りしたこの画像でテストしてみたいと思います
目次
今回はstract.packを利用しました。 プログラム自体はとても簡単なものとなっています 生成された
読めなくなりました 拡張子をpngに変更してみても
何の画像か分かりません この訳の分からないデータから元の画像に戻せないとエンコードとは言えません。 作成するといってもエンコーダが簡単だったのでデコーダも簡単です。 バイナリを反転するエンコーダを作成したので、バイナリを反転するデコーダを作成すればいいわけです。 完成しました。
入力ファイルと出力ファイルの名前が変わっただけです。 きちんと元に戻せているのか確認しましょう
元の画像に戻せていました エンコーダとデコーダの そんな立派なものではないので全く知らない人でも さて、エンコード/デコードができるようになりました。
が、先ほどのプログラムでは以下の問題点があります ゲーム作成で画像ファイルが一つという事は滅多にないと思うので、
特定のフォルダ以下の画像ファイルを全てエンコードするようにしましょう。 今回のフォルダ構成は以下です imgディレクトリ以下に画像がまとまっているので、これらすべてをエンコードします。
複数の拡張子も同時に出来るようにplayerとenemyで敢えて拡張子を変えています。 画像データを取得するにはパスがわからないとどうしようもないのでまずはパスを取得します。 pathlibを使えば簡単に取得できるとのこと srcディレクトリの中で実行した結果です。 一旦このままいきます。。 先ほどのpath listの中にはディレクトリやtxtファイルも含まれています。 ぴったりな記事がありました。 いけました。 ですが、img_filesの要素は このままではpathのみ抽出(拡張子の変更)ができないので文字列に変換します。 こちらの記事を参考にさせていただきました。 右端からのソートには これをこれまでのソースコードに追加します。 このようになりました これで 全ての画像ファイルがエンコードされるようになりましたが、 このような感じです。 今回のケースであれば が、エラーが出るはずです。 こちらを参考に完成したプログラムがこちらになります 完成です単一画像データの決め打ちでエンコード
import struct
key = 0b11111111 # keyは一例
infile = open('syachiku.png', 'rb')
outfile = open('img.en', 'wb')
data = infile.read()
for i in range(len(data)):
outfile.write(struct.pack("B", (data[i] ^ key)))
infile.close()
outfile.close()
data
として画像データを読み込みます。(1Byteの配列)
その data
ひとつひとつに対し適当なkeyでxorします(今回はビット反転)
あとはそのデータを outfile
に書き出して終了ですimg.en
を開いてみると
次はデコーダを作成しましょう単一画像データの決め打ちでデコーダ
import struct
key = 0b11111111 # keyはエンコーダで使ったモノと一緒のモノ
infile = open('img.en', 'rb')
outfile = open('out_img.png', 'wb')
data = infile.read()
for i in range(len(data)):
outfile.write(struct.pack("B", (data[i] ^ key)))
infile.close()
outfile.close()
key
の部分を変更することでいろいろなエンコーダ/デコーダとして利用できます。
当然ですがエンコーダと違う key
をデコーダで使うと、きちんとデコードできません。key
の特定ができそうですが、
友達に配布する程度でしか考えてないのでこれで十分です。複数画像のエンコード
program
├─src
│ └─main.py #本プログラム
└─img
├─player
│ ├─player1.jpg
│ └─player2.jpg
├─enemy
│ ├─enemy1.png
│ ├─enemy2.png
│ └─enemy2.png
└─test.txt
test.txtも変換しないように置いておきますパスの取得
from pathlib import Path
p = Path("./../img/")
for file_path in list(p.glob("**/*")):
print(file_path)
[出力結果]
..\img\enemy
..\img\player
..\img\test.txt
..\img\enemy\enemy1.png
..\img\enemy\enemy2.png
..\img\enemy\enemy3.png
..\img\player\player1.jpg
..\img\player\player2.jpg
programディレクトリの中で実行するとうまくいきません `program$py src/main.py'画像ファイ以外は除外する
これらはエンコードしたくないので除外します。from pathlib import Path
p = Path("./../img/")
in_extension = ['.jpg', '.png', '.bmp']
img_files = [img for img in p.glob('**/*') if img.suffix in in_extension]
for file_path in img_files:
print(file_path)
[出力結果]
..\img\enemy\enemy1.png
..\img\enemy\enemy2.png
..\img\enemy\enemy3.png
..\img\player\player1.jpg
..\img\player\player2.jpg
in_extension
に取り出したい拡張子を入れることによって、
好きなファイルを取り出すことができます。WindowsPath
クラスのインスタンスとなっています
as_posix
という関数が用意されているのでそれを用います。from pathlib import Path
p = Path("./../img/")
in_extension = ['.jpg', '.png', '.bmp']
img_files = [img for img in p.glob('**/*') if img.suffix in in_extension]
for file_path in img_files:
file_path = file_path + " " # error
print(file_path)
file_path = file_path.as_posix()
file_path = file_path + " " # ok
print(file_path)
複数画像のエンコード
..\img\enemy\enemy1.png
から ..\img\enemy\enemy1.en
のように拡張子部分を変更します。
もとの文字列( ..\img\enemy\enemy1.png
)を右端から捜査していき、
初めにピリオドが出てきた個所から後ろを全て削除しますrfind
関数を使います
file_path[:i]
で前半部分を抽出し、拡張子を結合しますout_extension = '.en'
for file_path in img_files:
file_path = file_path.as_posix()
print(file_path)
i = file_path.rfind(".")
en_file_path = file_path[:i] + out_extension
print(en_file_path)
[出力結果]
../img/enemy/enemy1.png
../img/enemy/enemy1.en
../img/enemy/enemy2.png
../img/enemy/enemy2.en
../img/enemy/enemy3.png
../img/enemy/enemy3.en
../img/player/player1.jpg
../img/player/player1.en
../img/player/player2.jpg
../img/player/player2.en
from pathlib import Path
import struct
p = Path("./../img/")
key = 0b11111111 # keyは一例
in_extension = ['.jpg', '.png', '.bmp']
out_extension = '.en'
img_files = [img for img in p.glob('**/*') if img.suffix in in_extension]
for file_path in img_files:
file_path = file_path.as_posix()
# 出力先ファイル名の拡張子を変更
i = file_path.rfind(".")
en_file_path = file_path[:i] + out_extension
infile = open(file_path, 'rb')
outfile = open(en_file_path, 'wb')
data = infile.read()
for i in range(len(data)):
outfile.write(struct.pack("B", (data[i] ^ key)))
infile.close()
outfile.close()
img
フォルダ下の全ての画像ファイルがエンコードされるようになりました。出力フォルダの変更
個人的にもとの画像とエンコードしたデータは別のフォルダにしたいです。program
├─src
│ └─main.py #本プログラム
├─img
│ ├─player
│ │ ├─player1.jpg
│ │ └─player2.jpg
│ ├─enemy
│ │ ├─enemy1.png
│ │ ├─enemy2.png
│ │ └─enemy2.png
│ └─test.txt
└─en_img
├─player
│ ├─player1.en
│ └─player2.en
└─enemy
├─enemy1.en
├─enemy2.en
└─enemy2.en
i = file_path.rfind(".")
en_file_path = file_path[:i] + out_extension
+ en_file_path = en_file_path.replace('img', 'en_img')
infile = open(file_path, 'rb')
outfile = open(en_file_path, 'wb')
replace
関数を用いることで簡単に置換できます
これで出力先のパスを変更できたので実行しますprogram/src$ py path.py
Traceback (most recent call last):
File "path.py", line 20, in <module>
outfile = open(en_file_path, 'wb')
FileNotFoundError: [Errno 2] No such file or directory: '../en_img/enemy/enemy1.en'
en_img
というフォルダが存在しないからです。open
は出力先ファイルを作成することはできますが、フォルダは作成できません。
makedirs
を使ってフォルダを作成しましょう。from pathlib import Path
import struct
import os
p = Path("./../img/")
key = 0b11111111 # keyは一例
in_extension = ['.jpg', '.png', '.bmp']
out_extension = '.en'
img_files = [img for img in p.glob('**/*') if img.suffix in in_extension]
for file_full_path in img_files:
file_full_path = file_full_path.as_posix()
# 出力先ファイル名の拡張子を変更
i = file_full_path.rfind(".")
en_file_full_path = file_full_path[:i] + out_extension
en_file_full_path = en_file_full_path.replace('img', 'en_img')
# 出力先フォルダの作成
i = en_file_full_path.rfind("/")
en_file_path = en_file_full_path[:i]
if not os.path.exists(en_file_path):
os.makedirs(en_file_path)
infile = open(file_full_path, 'rb')
outfile = open(en_file_full_path, 'wb')
data = infile.read()
for i in range(len(data)):
outfile.write(struct.pack("B", (data[i] ^ key)))
infile.close()
outfile.close()