2013/12/30(月) [n年前の日記]
#2 [ruby][python] 画像を難読化してみる
画像に変な難読化をかけてみる実験。
とりあえず、Python 2.6.6 + PIL(Pillow)を使って、読み込んだ画像を難読化。
_imgcrypt.py
以下のような画像になった。とりあえず、コレを見てどんな画像か理解できる人は、まず居ないだろうと。
image0_out.png![image0_out.png](img/20131230_imgcrypt/image0_out.png)
image1_out.png
これを Ruby + DXRuby で読み込んで元に戻して表示する。
_imgdecrypt.rb
以下のような結果に。
ちゃんと元の画像に戻せましたな。アルファチャンネルも有効になってる。(ポスト画像がアルファチャンネルを使用。)
もっとも、LLのソースを眺めることができる=どんな難読化をしてるのか容易に分かってしまうので、この手のソレをする意味なんてどの程度あるのか、という気もしますが。まあ、非プログラマーの方に御褒美画像をそのまま見せない、ということぐらいなら、使えるのかもと。
とりあえず、Python 2.6.6 + PIL(Pillow)を使って、読み込んだ画像を難読化。
_imgcrypt.py
#!/usr/bin/env python # -*- coding: utf-8 -*- u""" 画像に変な暗号化をかけてみるPythonスクリプト PIL(Pillow)を使用。 Usage: python imgcrypt.py IN_IMAGE OUT_IMAGE """ import sys import os from PIL import Image next = 1 def rand(): u"""乱数生成器(C言語のソレ)""" global next next = (next * 1103515245 + 12345) & 0xffffffff return int((next / 65536) % 32768) def srand(seed): u"""乱数初期化。種を渡す。""" global next next = seed def encrypt_image(img): u"""画像を難読化。Imageを渡す。""" outimg = img.copy() w, h = img.size srand(0) for y in range(h): rx = rand() for x in range(w): c = img.getpixel(((x + rx) % w, y)) outimg.putpixel((x, y), c) return outimg def decrypt_image(img): u"""画像の難読化の解除。Imageを渡す。""" outimg = img.copy() w, h = img.size srand(0) for y in range(h): rx = rand() for x in range(w): c = img.getpixel(((x - rx) % w, y)) outimg.putpixel((x, y), c) return outimg def main(): if len(sys.argv) < 3: print "Usage: python %s IN_IMAGE OUT_IMAGE" % \ os.path.basename( __file__ ) sys.exit() inimgfn = sys.argv[1] if not os.path.isfile(inimgfn): print "Not Found %s" % inimgfn sys.exit() outimgfn = sys.argv[2] img = Image.open(inimgfn, "r") outimg = encrypt_image(img) if True: # 画像を保存 outimg.save(outimgfn) print "Output %s" % outimgfn else: # 画像を表示して確認 outimg.show() decrypt_image(outimg).show() if __name__ == '__main__': main()
python imgcrypt.py image0.png image0_out.png python imgcrypt.py image1.png image1_out.png画像の難読化も Ruby でやらなかったのは、Ruby でアルファチャンネルつきのpngが出力できるかどうか不明だったので…。Python + PIL(Pillow)ならできることは知ってたので、そちらを使ってみた次第。
以下のような画像になった。とりあえず、コレを見てどんな画像か理解できる人は、まず居ないだろうと。
image0_out.png
![image0_out.png](img/20131230_imgcrypt/image0_out.png)
image1_out.png
これを Ruby + DXRuby で読み込んで元に戻して表示する。
_imgdecrypt.rb
# 画像の難読化を解除して表示するRubyスクリプト # # DXRuby を使用 require 'dxruby' $next = 1 # 乱数生成器(C言語のソレを再現) def c_rand $next = ($next * 1103515245 + 12345) & 0xffffffff return (($next / 65536) % 32768).to_i end # 乱数初期化。種を渡す def c_srand(seed) $next = seed end # 画像の難読化を解除 def decrypt_image(img) w, h = img.width, img.height outimg = Image.new(w, h) c_srand(0) h.times do |y| rx = c_rand() w.times do |x| outimg[x, y] = img[(x - rx) % w, y] end end return outimg end img0 = Image.load("image0_out.png") img1 = Image.load("image1_out.png") img0 = decrypt_image(img0) img1 = decrypt_image(img1) Window.loop do break if Input.keyPush?(K_ESCAPE) Window.draw(0,0, img1) Window.draw(0,0, img0) end
ruby imgdecrypt.rb
以下のような結果に。
ちゃんと元の画像に戻せましたな。アルファチャンネルも有効になってる。(ポスト画像がアルファチャンネルを使用。)
もっとも、LLのソースを眺めることができる=どんな難読化をしてるのか容易に分かってしまうので、この手のソレをする意味なんてどの程度あるのか、という気もしますが。まあ、非プログラマーの方に御褒美画像をそのまま見せない、ということぐらいなら、使えるのかもと。
◎ 参考ページ。 :
乱数生成器(線形合同法)は、以下の記事をそのまま使わせてもらいました。
_Algorithms with Python / 乱数
周期性がある疑似乱数らしいけど、とりあえず Python と Ruby で同じ結果が出てくる簡素な疑似乱数が欲しかったので…。もっとも、Python の乱数(Random)もMT法らしいので、書き方次第で前述のソース内の乱数生成器部分は丸々削除できるかもしれませんが。
_Algorithms with Python / 乱数
周期性がある疑似乱数らしいけど、とりあえず Python と Ruby で同じ結果が出てくる簡素な疑似乱数が欲しかったので…。もっとも、Python の乱数(Random)もMT法らしいので、書き方次第で前述のソース内の乱数生成器部分は丸々削除できるかもしれませんが。
[ ツッコむ ]
以上です。