mieki256's diary



2016/11/27() [n年前の日記]

#2 [python] PySide + Pillow(PIL) で塗り潰し

Pillow(PIL)の、ImageDraw.floodfill(PILImage, (x, y), (r, g, b, a)) を利用して、PySideのウインドウ上で塗り潰し処理を試したり。

_qimage2pil_test2.py
u"""
QPixmap → QImage → PIL Image に変換して塗り潰しの処理をしてみる.

ImageQtに相当するクラスをスクリプト内に置いてみた版。
Pillow のバージョンが上がれば、このクラスは不要になるかもしれない。

動作確認環境 : Windows10 x64 + Python 2.7.12 + PySide 1.2.4 + Pillow 3.4.2
"""

import cStringIO
import sys

# ここでPyQt4を使わないようにしているはず…なのだが…
from PySide import QtGui
from PySide import QtCore
sys.modules['PyQt4.QtGui'] = QtGui
sys.modules['PyQt4.QtCore'] = QtCore

from PySide.QtCore import *  # NOQA
from PySide.QtGui import *   # NOQA

from PIL import Image
from PIL import ImageDraw
# from PIL import ImageQt


class ImageQtPoor(QImage):

    u"""ImageQt substitute. Supports only RGBA image."""

    def __init__(self, im):
        """convert PIL Image to PySide QImage."""
        self.org_mode = im.mode
        if im.mode != "RGBA":
            im = im.convert("RGBA")
        w, h = im.size
        fmt = QImage.Format_ARGB32
        self.__data = im.tobytes("raw", "BGRA")
        super(ImageQtPoor, self).__init__(self.__data, w, h, fmt)

    @staticmethod
    def fromqimage(qim):
        """convert PySide QImage ro PIL Image."""
        buf = QBuffer()
        buf.open(QIODevice.ReadWrite)
        qim.save(buf, "PNG")
        fp = cStringIO.StringIO()
        fp.write(buf.data())
        buf.close()
        fp.seek(0)
        return Image.open(fp)

    @staticmethod
    def toqimage(pim):
        """convert PIL Image to PySide QImage."""
        fp = cStringIO.StringIO()
        pim.save(fp, "PNG")
        qim = QImage()
        qim.loadFromData(fp.getvalue(), "PNG")
        return qim


class GView(QGraphicsView):

    u"""画像アイテム表示用."""

    def __init__(self, *argv, **keywords):
        """init."""
        super(GView, self).__init__(*argv, **keywords)
        self.setBackgroundBrush(Qt.gray)
        scene = QGraphicsScene(self)
        self.setScene(scene)

        pm = QPixmap("./tmp_rgba.png")
        self.pm_item = QGraphicsPixmapItem(pm)
        scene.addItem(self.pm_item)

    def mousePressEvent(self, event):
        u"""マウスクリックした際に呼ばれる処理."""
        p = self.mapToScene(event.pos())
        x, y = int(p.x()), int(p.y())

        pm = self.pm_item.pixmap()         # QPixmapを取得
        qim = pm.toImage()                 # QImageに変換
        pim = ImageQtPoor.fromqimage(qim)  # PIL Imageに変換
        if pim.mode != "RGBA":
            pim = pim.convert("RGBA")

        # 塗り潰し(Flood Fill)をする
        ImageDraw.floodfill(pim, (x, y), (128, 0, 64, 255))

        qim2 = ImageQtPoor(pim)            # PIL Image → QImageに変換
        # qim2 = ImageQtPoor.toqimage(pim)

        pm2 = QPixmap.fromImage(qim2)      # QPixmapに変換
        self.pm_item.setPixmap(pm2)


class MyWidget(QWidget):

    u"""メインウインドウ相当."""

    def __init__(self, *argv, **keywords):
        """init."""
        super(MyWidget, self).__init__(*argv, **keywords)
        gv = GView(self)
        l = QVBoxLayout()
        l.addWidget(gv)
        self.setLayout(l)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MyWidget()
    w.show()
    sys.exit(app.exec_())

qimage2pil_test2_ss01.gif

クリックすると、クリックした位置から塗り潰しができる。今回は只の動作確認なので、塗り潰し色は固定。

現状、PySide 1.2.4 と Pillow(PIL) 3.4.2 の組み合わせでは、ImageQt を使って PIL Image から QImage へ変換すると Python が死んでしまう不具合が発生する時があるけど。RGBA しか使わないという前提にすれば、処理内容が数行で済むので、各スクリプト内に処理を書けそうだな、と思えてきたので上記のスクリプトではそのように書いてみたり。

以上です。

過去ログ表示

Prev - 2016/11 - Next
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project