ちょろわざ集

基本的にリファレンスに載っているんだけどね

tags:python, tips, experiment
created:2007-08-05T20:24:24

良く使うけどリファレンスから探すのメンドクサイ。 ちょろわざ

変換編

n進数文字列から整数へ

>>> int('01010001',  2) # 2進数文字列を整数に
81
>>> int('77feff',   16) # 16進数文字列を整数に
7864063
>>> int('77feFF',  16) # 大文字小文字混在OK
7864063
>>> int('32467102',  8) # 8進数文字列を整数に
6975042
>>> int('XYZ',      36) # 36進数までOK
44027

文字列から文字リストへ

>>> input = 'hoge'
>>> output = list(input)
>>> output
['h', 'o', 'g', 'e']

文字リストから文字列へ

>>> input = ['h', 'o', 'g', 'e']
>>> output = ''.join(input)
>>> output
'hoge'

辞書から「キー・値ペアのリスト」へ

>>> input = {'hoge':123, 'moge':456}
>>> output = input.items()
>>> output
[('moge', 456), ('hoge', 123)]

「キー・値ペアのリスト」から辞書へ

>>> input = [('hoge', 123), ('moge', 456)]
>>> output = dict(input)
>>> output
{'moge': 456, 'hoge': 123}

キーリストと値リストを「キー・値ペアのリスト」へ

>>> key_list = ['hoge', 'moge']
>>> value_list = [123, 456]
>>> output = zip(key_list, value_list)
>>> output
[('hoge', 123), ('moge', 456)]

文字列/パス名/URI加工編

すべて小文字に

>>> input = 'hoge@HOGE.com'
>>> output = input.lower()
>>> output
'hoge@hoge.com'

すべて大文字に

>>> input = 'hoge@hoge.com'
>>> output = input.upper()
>>> output
'HOGE@HOGE.COM'

セパレータの手前だけを取り出す

>>> input = 'hoge@hoge.com'
>>> output = input.split('@',1)[0]
>>> print output
hoge

セパレータが入力に含まれないなら入力のままが出力。

セパレータの後ろだけを取り出す

>>> input = 'hoge@hoge.com'
>>> output = input.rsplit('@',1)[-1]
>>> print output
hoge.com

セパレータが入力に含まれないなら入力のままが出力。

セパレータを含む分割(Py2.5)

>>> 'moge.hoge.com'.partition('.')
('moge', '.', 'hoge.com')
>>> 'moge.hoge.com'.rpartition('.')
('moge.hoge', '.', 'com')

ファイル名から絶対フォルダ名を取得

>>> file_name = '../../moge/hoge.txt'
>>> import os
>>> os.path.dirname(os.path.abspath(file_name))
'C:\\Temp\\Hoge\\moge'

file_nameが相対パスの場合、内部で「os.getcwd()」を 利用して解決してくれます。 パスセパレータにはバックスラッシュ「\」でも スラッシュ「/」でも問題ありませんが、 バックスラッシュ「」を記述する際は Pythonのシンタックスに従い「’\\’」と記述してください。

>>> file_name = u'../../moge/hoge.txt'
>>> import os
>>> os.path.dirname(os.path.abspath(file_name))
u'C:\\Temp\\Hoge\\moge'

このように入力にunicode文字列を利用すると結果もunicode文字列になります。 パス文字列をunicode文字列で扱うようにしておくと、 要所で「sys.getfilesystemencoding()」の値を利用して ファイルアクセスしてくれます。

拡張子を変更する

>>> file_name = '../../moge/hoge.txt'
>>> import os
>>> os.path.splitext(file_name)[0] + '.log'
'../../moge/hoge.log'

ファイル/プロセス操作編

ファイルの作成日時・更新日時を取得

>>> import os
>>> ctime = os.path.getctime('test.txt') # 作成日時
>>> mtime = os.path.getmtime('test.txt') # 更新日時

ファイルの作成日時・更新日時を設定

>>> import os, time
>>> ctime = mtime = time.time()
>>> os.utime('test.txt', (ctime, mtime))

別のプロセスを起動して標準入出力を利用

>>> args = ['python', '-c', 'print raw_input()']
>>> from subprocess import Popen, PIPE
>>> proc = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE)
>>> proc.stdin.write('input text')
>>> proc.stdin.close()
>>> proc.wait()
0
>>> print proc.stdout.read()
input text

>>> print proc.stderr.read()

>>>

イメージ操作編

PILモジュールのインストールが必要です。

フォーマット変換

拡張子からイメージハンドラが自動的に選択されます。 下記の例はPNGからJPEGへ。

>>> from PIL import Image
>>> Image.open('test.png').save('test.jpg', quality=50)

jpegの場合、「quality」オプションが使える。 意味のある値の範囲は1~100。

新規作成

>>> from PIL import Image
>>> new_image = Image.new('RGB', (4,4), 0x434241)

色指定は下位8ビットが赤の輝度で、下位から「RGBA」の順番です。

注釈

主なフォーマット

‘1’
モノクロ2値画像
‘L’
グレースケール画像
‘P’
パレットインデックス画像(2色~256色)
‘RGB’
24ビットカラー画像
‘RGBA’
24ビットカラー+8ビットアルファ画像
‘YCbCr’
YUV444フォーマット画像(輝度、色相B、色相R各8ビット)

生データの取り出し

>>> from PIL import Image
>>> new_image = Image.new('RGB', (4,4), 0x434241)
>>> new_image.tostring()
'ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABC'

「RGBフォーマット」なら「RGB」で、 「RGBAフォーマット」なら「RGBA」の順番です。

長さは「len(フォーマット名)×横幅×高さ」になります。

1BPP画像を反転マスク生データに変換

>>> from PIL import Image
>>> new_image = Image.new('1', (8,8), 0)
>>> new_image.tostring()
'\x00\x00\x00\x00\x00\x00\x00\x00'
>>> new_image.tostring('raw', '1;I', 4, -1)
'\xff\x00\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00\xff\x00\x00\x00'

前者のtostringでは画像の上端から順番に2値画像データを出力します。 後者のtostringではエンコーダーに細かい指定をしています。

Windowsのマスクパターンデータなどは面倒な制約がいろいろありますが、 この対応策が「PIL」には備えられていました。

2番目のパラメータに普通は元画像のフォーマット「‘1’」を指定しますが、 反転マスクを出力するには「‘1;I’」を指定します。 すると、ピクセルの「0」と「1」が反転します。

3番目のパラメータには「ストライド」、 つまりバイトアライメント値を指定します。 4を指定するとライン単位で4バイト境界に足りない部分を0で埋めます。

4番目のパラメータには画像の出力方向を指定します。 内部でラインカウントする時の増分値です。 省略時は「1」になります。 Windowsビットマップなどでは上下が逆ですので 「-1」を指定してやると上下逆に出力します。

今回の例は「1BPP画像」に「rawエンコーダ」を 指定した時だけに使える例です。 元画像のフォーマットとエンコーダの組み合わせ毎に 指定できるパラメータ範囲が変わります。

警告

いくつかのケースでストライドを 0以外にしたときランタイムエラーが。

というわけで、自力でアライメント補正するコード。

def get_windows1bpp_stream(img):
  stream = img.tostring('raw','1', 0, -1)
  step = (img.size[0]+7)/8
  fix = (4-(img.size[0]+7)/8)%4
  res = []
  for i in range(0, len(stream), step):
    res.append(stream[i:i+step])
    res.append('\x00'*fix)
  return 1, '', ''.join(res)

生データからの作成および確認

>>> from PIL import Image
>>> stream = 'ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABC'
>>> new_image = Image.fromstring('RGB', (4,4), stream)
>>> new_image.show()

streamに期待される長さは「len(フォーマット名)×横幅×高さ」で、 この長さに満たない場合エラーになります。(余計な分は無視されます。)

Windowsの場合イメージビューアが起動します。 show()メソッドはビューアが閉じられるまで ブロックします(リターンしてこない)。

アルファチャネルを使った貼り付け

サンプル画像「’test.png’」:
../../_images/test1.png

(このPNG画像にはアルファチャネルを含んでいます。)

>>> from PIL import Image
>>> image = Image.open('test.png')
>>> new_image = Image.new('RGB', image.size, 0xffffff)
>>> new_image.paste(image, mask=image)
>>> new_image.save('test.bmp')
出力結果「’test.bmp’」:
../../_images/test.bmp

maskパラメータを指定するのがミソ。 maskとして渡された場合アルファチャネルデータのみ参照します。 mask指定しないとアルファチャネルごと貼り付けられます。

ちなみにmaskに1BPP画像を指定すると、切り抜き合成されます。 (カラーキー合成と同等の低クオリティ)

減色処理

サンプル画像「’main_icon.png’」:
../../_images/main_icon.png
>>> from PIL import Image
>>> image = Image.open('main_icon.png')
>>> image.convert('RGB').quantize(16).save('main_icon.bmp')
16色画像「’main_icon.bmp’」:
../../_images/main_icon.bmp

quantizeの最初のパラメータには2~256が使えます。 quantizeが返すイメージはパレットイメージになります。

閾値を使った2値化

サンプル画像「’test2a.png’」:
../../_images/test2a.png
>>> from PIL import Image
>>> image = Image.open('test2a.png')
>>> def filter(col):
...   if col>220:
...     return 255
...   else:
...     return 0
...
>>> new_image = image.point(filter)
>>> new_image.save('test2b.png')
出力結果「’test2b.png’」:
../../_images/test2b.png