mieki256's diary



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

#1 [python] GIMPのパレットファイルをプレビューするPySideのスクリプト

PySideを使って、GIMPのパレットファイル(.gpl)を読み込んで表示できるスクリプトを書いてたり。

_palette_select.py
u"""
GIMPのgplファイルを読み込んでパレットを表示してみるテスト.

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

"""

import os
import re
import sys
from PySide.QtCore import *  # NOQA
from PySide.QtGui import *   # NOQA


class PalettePreview(QGraphicsView):

    u"""パレットプレビュー用QGraphicsView."""

    valueGetted = Signal(QColor)

    def __init__(self, *argv, **keywords):
        """init."""
        super(PalettePreview, self).__init__(*argv, **keywords)
        self.rgb_data = []
        self.w = 256
        self.h = 128
        self.columns = 16
        self.rows = 8
        self.cw = self.w / self.columns
        self.ch = self.h / self.rows
        self.select_color = QColor(Qt.black)

        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setFixedSize(self.w, self.h)
        self.setBackgroundBrush(QBrush(self.get_bg_chip_image()))

        self.setScene(QGraphicsScene(self))
        pm = QPixmap(self.w, self.h)
        pm.fill(Qt.black)
        self.pal_canvas_item = QGraphicsPixmapItem(pm)
        self.scene().addItem(self.pal_canvas_item)
        self.pal_canvas_item.setOffset(0, 0)

    def make_palette_preview(self, columns, rgb_data):
        u"""パレットプレビュー画像を生成."""
        self.rgb_data = rgb_data
        self.columns = columns
        n = len(rgb_data)
        self.rows = n / columns
        if n % columns != 0 or n < columns:
            self.rows += 1
        self.cw = self.w / self.columns
        self.ch = self.h / self.rows

        # QPixmapに描画
        pm = QPixmap(self.w, self. h)
        pm.fill(QColor(0, 0, 0, 0))
        x, y = 0, 0
        for d in self.rgb_data:
            r, g, b, _ = d
            self.draw_one_palette(pm, x, y, self.cw, self.ch, (r, g, b))
            x += self.cw
            if x >= self.w or x + self.cw > self.w:
                x = 0
                y += self.ch

        self.pal_canvas_item.setPixmap(pm)
        self.scene().setSceneRect(QRectF(0, 0, self.w, self.h))

    def draw_one_palette(self, pm, x, y, w, h, rgb):
        r, g, b = rgb
        brush = QPixmap(w, h)
        brush.fill(QColor(r, g, b, 255))
        qp = QPainter()
        qp.begin(pm)
        qp.drawPixmap(x, y, brush)
        qp.end()
        del qp
        del brush

    def get_bg_chip_image(self):
        u"""背景塗りつぶし用のパターンを作成して返す."""
        c0, c1 = 128, 80
        im = QImage(16, 16, QImage.Format_ARGB32)
        qp = QPainter()
        qp.begin(im)
        qp.fillRect(0, 0, 16, 16, QColor(c0, c0, c0, 255))
        qp.fillRect(0, 0, 8, 8, QColor(c1, c1, c1, 255))
        qp.fillRect(8, 8, 8, 8, QColor(c1, c1, c1, 255))
        qp.end()
        del qp
        return im

    def mousePressEvent(self, event):
        u"""マウスボタンが押された時の処理."""
        if event.button() == Qt.LeftButton:
            scene_pos = self.mapToScene(event.pos())
            x = int(scene_pos.x())
            y = int(scene_pos.y())
            if x < 0 or x >= self.w or y < 0 or y >= self.h:
                return
            idx = (y / self.ch) * self.columns + (x / self.cw)
            if idx < len(self.rgb_data):
                r, g, b, _ = self.rgb_data[idx]
                self.select_color.setRgb(r, g, b, 255)
                self.valueGetted.emit(self.select_color)

    @Slot(QColor)
    def changedValue(self, value):
        """get color."""
        pass


class PaletteSelect(QWidget):

    u"""パレット選択ウィジェット."""

    PAL_DIR = "./palettes"
    DEF_PAL_NAME = "pet2015"

    valueGetted = Signal(QColor)

    def __init__(self, *argv, **keywords):
        """init."""
        super(PaletteSelect, self).__init__(*argv, **keywords)
        self.gpl_data = self.get_gpl_data()

        self.gview = PalettePreview(self)

        idx = 0
        self.combo = QComboBox(self)
        lst = sorted(self.gpl_data.keys())
        for (i, key) in enumerate(lst):
            self.combo.addItem(key)
            if key == PaletteSelect.DEF_PAL_NAME:
                idx = i

        vl = QVBoxLayout()
        vl.addWidget(self.combo)
        vl.addWidget(self.gview)
        self.setLayout(vl)

        self.combo.activated[str].connect(self.change_combo)
        self.gview.valueGetted[QColor].connect(self.clicked_palette_view)

        self.combo.setCurrentIndex(idx)
        self.update_preview(PaletteSelect.DEF_PAL_NAME)

    def change_combo(self, str):
        u"""comboboxが変更された時に呼ばれる処理."""
        self.update_preview(str)

    def clicked_palette_view(self, col):
        u"""パレットプレビューがクリックされた時に呼ばれる処理."""
        self.valueGetted.emit(col)

    def update_preview(self, pal_name):
        u"""パレットプレビューを更新."""
        _, columns, rgb_data = self.gpl_data[pal_name]
        self.gview.make_palette_preview(columns, rgb_data)

    def get_gpl_data(self):
        u"""パレットファイル(.gpl)を読み込み."""
        dir = PaletteSelect.PAL_DIR
        dt = {}
        for fname in os.listdir(dir):
            path, ext = os.path.splitext(fname)
            if ext.lower() == ".gpl":
                d = self.read_gpl_file(dir, fname)
                if d is not None:
                    fname, name, columns, rgb_data = d
                    name = name.lower()
                    dt[name] = (fname, columns, rgb_data)
        return dt

    def read_gpl_file(self, dir, fname):
        u"""gplファイルを1つ読み込んで内容をタブルで返す."""
        name = fname
        columns = 16
        rgb_data = []
        fpath = os.path.join(dir, fname).replace(os.path.sep, '/')

        r1 = re.compile(r"Name:\s+(.+)$")
        r2 = re.compile(r"Columns:\s+(\d+)$")
        r4 = re.compile(r"^\s*(\d+)\s+(\d+)\s+(\d+)\s+(.+)$")
        r5 = re.compile(r"^\s*$")

        f = open(fpath, 'r')
        for (i, s) in enumerate(f):
            s = s.rstrip()
            if i == 0:
                if s != "GIMP Palette":
                    return None
            elif i == 1:
                m = r1.match(s)
                if m:
                    name = m.group(1)
                else:
                    print("Error : %s" & s)
                    return None
            elif i == 2:
                m = r2.match(s)
                if m:
                    columns = int(m.group(1))
                else:
                    print("Error : %s" & s)
                    return None
            elif s.find("#") == 0:
                continue
            elif r5.match(s):
                continue
            else:
                m = r4.match(s)
                if m:
                    r, g, b, colname = m.groups()
                    rgb_data.append([int(r), int(g), int(b), colname])
                else:
                    print("Error : %s" & s)
                    return None
        f.close()
        return (fname, name, columns, rgb_data)


class MyWidget(QWidget):

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

    def __init__(self, *argv, **keywords):
        """init."""
        super(MyWidget, self).__init__(*argv, **keywords)
        self.palview = PaletteSelect(self)
        self.lbl = QLabel("Ready.")
        l = QVBoxLayout()
        l.addWidget(self.palview)
        l.addWidget(self.lbl)
        self.setLayout(l)

        self.palview.valueGetted[QColor].connect(self.clicked_palette)

    def clicked_palette(self, col):
        u"""パレットプレビューがクリックされた時の処理."""
        r, g, b = col.red(), col.green(), col.blue()
        self.lbl.setText("RGB=(%d, %d, %d)" % (r, g, b))


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

palette_select_ss01.gif


スクリプト + パレットファイル群(*.gpl)を、zipでまとめて置いておくです。スクリプトは CC0 / Public Domain ってことで。

_paletteselect_20161121.zip

以上、1 日分です。

過去ログ表示

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