参考サイト
・【Python入門】Pythonにおけるclassの使い方とは? ・Python 3でのファイルのimportのしかたまとめ
前書き
こんにちは。またまたpythonネタです。
今回は以前やったPythonで縦書き文字を画像合成してみたをclassを使うように変更してみました。
phpのクラスとpythonのクラスは結構やり方?が違って調べまくりましたが、なんとか出来ました。
やってみた
ディレクトリツリーは以下です。
$ tree . ├── app.py ├── compositor │ ├── __init__.py │ └── text_compositor.py ├── font.otf ├── image.jpg ├── main.py └── tmp
合成を行うクラスファイル(text_compositor.py)です。
# coding: utf-8 from PIL import ImageFont, ImageDraw import six class TextCompositor: BOLD_LOOP_COUNT = 20 # Boldを再現するループ描画数 def __init__(self, string, font_size, draw_start_x, draw_start_y, is_bold=False, font_color='#ffffff'): self.__string = string # 対象文字列 self.__font_size = font_size # フォントサイズ self.__draw_start_x = draw_start_x # 描画開始位置X self.__draw_start_y = draw_start_y # 描画開始位置Y self.__bold = is_bold # Boldを行うかどうかのフラグ self.__font_color = font_color # 文字色 def getFontfilePath(self): return './font.otf' def getString(self): if (six.PY2 == True): # python2系の場合は、unicode変換をかける return unicode(self.__string, 'utf-8', 'ignore') return self.__string def isBold(self): return self.__bold def composite(self, frame_image, font_color='#ffffff'): # 描画用データを取得 draw_image = ImageDraw.Draw(frame_image) # フォントデータを取得 image_font = ImageFont.truetype(self.getFontfilePath(), self.__font_size) if (self.isBold() == True): # Bold判定の場合は指定回数分ループして同じ箇所に描画し続ける for i in range(self.BOLD_LOOP_COUNT): self.__execute(draw_image, image_font) else: self.__execute(draw_image, image_font) def __execute(self, draw_image, image_font): # 各文字の描画管理変数 ix, iy = 0, 0 for c in self.getString(): x = self.__draw_start_x - ix * self.__font_size y = self.__draw_start_y + (iy * self.__font_size) # 今回描画する1文字の詳細なX, Yを設定 char_width, char_height = image_font.getsize(c) x += (self.__font_size - char_width) / 2 y += self.__draw_start_y # 指定の場所へ文字を描画 draw_image.text((x, y), c, font=image_font, fill=self.__font_color) # 次の文字へ iy += 1
上記のcompositorを実行していくクラス(app.py)です。
# coding: utf-8 from PIL import Image class App: def __init__(self): self.__compositors = [] def addCompositor(self, compositor): self.__compositors.append(compositor); def run(self): frame_image = Image.open(self.getBaseFilePath()) for compositor in self.__compositors: compositor.composite(frame_image) self.__save(frame_image) def getBaseFilePath(self): return './image.jpg' def getOutputFilePath(self): return './tmp/output.jpg' def __save(self, frame_image): frame_image.save(self.getOutputFilePath()) frame_image.show()
実際に実行されるファイル(main.py)です
# coding: utf-8 import sys from app import App from compositor.text_compositor import TextCompositor STRING_DATA = sys.argv[1] app_logic = App() app_logic.addCompositor(TextCompositor(STRING_DATA, 30, 350, 20, False)) app_logic.addCompositor(TextCompositor(STRING_DATA, 60, 200, 20, False)) app_logic.addCompositor(TextCompositor(STRING_DATA, 80, 60, 20, True, "#FF0000")) app_logic.run();
実行してみます。
$ python main.py "餌をください"
こんな感じです。
勉強になったところ
init.py
__init__.py
を使ってディレクトリに入っているものをパッケージとして認識してくれるようです。
イコールimportができるようになるということのようです。
インスタンス変数
phpのメンバ変数的な立ち位置です。
self.AAA は public self._BBB は protected self.__CCCはprivate
みたいなイメージでいるんですが、大丈夫でしょうかね。。。?
あとがき
正直ボリューム的に少ないので、クラス化の恩恵はあんまりないですが、それでもpythonでのクラスの取扱が勉強できて良かったです。
__init__.py
の存在に気づかず結構ハマってしまったのは内緒です。。。
今後pythonでプログラム書く場合は積極的にclass使っていきたいと思います!
このプログラムもgithubに上げときます。