Hatena::ブログ(Diary)

分室の分室 このページをアンテナに追加

2016-09-26 Mon

Script-Fu で使えるブラシ関連プロシージャを探る【その1】

【574】


 最新版 Gimp 2.8.16 (Windows版) を起動すると…

f:id:foussin:20160926214411p:image
01-起動直後.png
 ブラシは『2. Hardness 050』、サイズは『20.0』(ピクセル)、描画ツールは『エアブラシ』の状態で立ち上がる。ツールだけ『ブラシ(筆)』に変更し、あとはそのまま適当な図形(6角形)を Script-Fu で描画すると…

f:id:foussin:20160926214535p:image
02-size-20.png
 こんな図形になる。これではシャープな図形が描けないので、次のように設定を変更して、同じ 6角形を再描画すると…

f:id:foussin:20160926214536p:image
03-size-02.png …こうなる。


 以前の Gimp では、Script-Fu でブラシを変更するだけで、個々の登録済みブラシの基本属性(太さとか)が直ちに適応されてた気がする…が、最新版では『カレントの設定』が優先されるらしい。そのカレント設定が GUI 画面上に表示されている、という解釈でいいのかな。。。

 それと、自分は gimp-obsolete-files フォルダに入っているブラシをずっと使っていたが、obsolete とは『廃止された』という意味だと、つい先日知った…。


 そんな訳で、自作 Script-Fu を修正する必要が生じた。いきなり該当ファイルの修正を行うのは危険なので、今回も検証用のスクリプトを別に作って動作テストをしてみる。

 自動化処理がしたくて Script-Fu を使っているのに、スクリプト実行前に GUI の設定項目をチマチマいじっていたら面倒だ。そこで、ブラシのカレント設定項目を Script-Fu で変更する方法を、この機会に覚えようと思う。

 gimp-obsolete-files に入っているブラシをいつまでも使い続けても、GIMP のバージョンアップの度に苦労することになるのは目に見えているので、それら古いブラシはなるべく使わず、別の方法でうまく代用したい。でも、当分は gimp-obsolete-files のブラシも使うと思うけど…。


gimp-obsolete-files のブラシを列記:

    5x5square  , 5x5squareBlur,
    10x10square, 10x10squareBlur,
    20x20square, 20x20squareBlur,
    Diagonal-Star-11, Diagonal-Star-17, Diagonal-Star-25
    feltpen, galaxy_small, Grass1, pepper, pixel,
    SketchBrush-16, SketchBrush-32, SketchBrush-64
    ... 自分はこれらを使ったことがないので完全無視。

    "Circle (01)"   "Circle (03)"   "Circle (05)"   "Circle (07)"
    "Circle (09)"   "Circle (11)"   "Circle (13)"   "Circle (15)"
    "Circle (17)"   "Circle (19)"
    ... これはもう使わない(ダミーブラシを使って代用)

    "Circle Fuzzy (03)"   "Circle Fuzzy (05)"   "Circle Fuzzy (07)"
    "Circle Fuzzy (09)"   "Circle Fuzzy (11)"   "Circle Fuzzy (13)"
    "Circle Fuzzy (15)"   "Circle Fuzzy (17)"   "Circle Fuzzy (19)"
    ... これも使わない(同じくダミーブラシを使って代用)

    Calligraphic-Brush-0, Calligraphic-Brush-1,
    Calligraphic-Brush-2, Calligraphic-Brush-3
    ... 登録済みかどうかを調べて、使えるなら使う。
        (使えない場合はダミーブラシを使ってエラー回避…かな)

    "2. Star (55x55)"
    ... うちの Gimp では Basic フォルダに入ってたけど、obsolete ぽい
        気がする(これも登録済みか調べて、使えるなら使う…にしておく)

…と、こんな感じで対応しようと思う。Circle と Circle Fuzzy は、9〜10 個のブラシが定義されていたが、今後は (gimp-context-set-brush-size size) でサイズ指定をするので、実際に作成するダミーブラシは 1個だけで対応できると思う。

 Script-Fu 実行時に使うブラシは gimp-context-set-brush で指定し、それをカレントのブラシとする。で、カレントブラシをサイズ変更するオプションをスクリプトに新たに追加する(具体的には前回のソースと同様の方法とする)。


ブラシ関連の Gimpプロシージャ【おさらい】:

まずは、新規作成、削除、複製、リネーム関連プロシージャについて。

●新規作成ブラシ関連:

ブラシ作成  (gimp-brush-new "new-name")         ⇒ actual new brush name
            備考:gimp-brush-new で作ったブラシはユーザーフォルダに
                  作成されるらしい(その場所のブラシは編集可能)
            (副作用として実際にブラシが作られ、戻り値は文字列らしい)

ブラシ削除  (gimp-brush-delete "name")          ⇒ ?(未規定?)
            使い方:gimp-brush-new で作ったブラシを削除
            (編集可能フォルダにあるブラシのみ削除できるらしい?)

ブラシ複製  (gimp-brush-duplicate "name")       ⇒ copy name
            使い方:編集不可フォルダのブラシを編集したい時に利用
            (複製ブラシはユーザーフォルダ(編集可)に作成されるらしい)
            (副作用として実際にブラシが作られ、戻り値は文字列らしい)

リネーム    (gimp-brush-rename "name" "new-name")
                                    ⇒ actual new name of the brush
            使い方:主に複製ブラシの名前変更に使うと思う
            (副作用としてブラシ名が変更され、戻り値は文字列らしい)
            (戻り値から察して、duplicate とワンセットで使うと思う)

存在確認?   (gimp-brush-is-generated "name")    ⇒ TRUE or FALSE
            使い方:ブラシが登録済なら gimp-brush-new をスキップ
            (これを怠ると同名ブラシ(自動リネーム)が増えてしまう)

編集可能?   (gimp-brush-is-editable "name")     ⇒ TRUE or FALSE

 上記で頻繁に使うのは gimp-brush-new と gimp-brush-is-generated の 2つだけだと思う。それ以外は『ブラシ作成職人』用のプロシージャかな…。


 次はブラシの形状やサイズ等の属性値の設定方法が知りたい訳だが、プロシージャ―ブラウザーで調べても FLOAT(実数), INT32(整数), STRING(文字列) …のようなザックリした引数指定についてしか書かれていない。例えば angle(角度)はラジアンなのか度数なのか…とか、さらに具体的な有効範囲(下限値〜上限値)とかも記載して欲しかった…。

 そこら辺を探るなら、実際に登録済ブラシの詳細情報を取り出して見てみるしかなさそう。で、探るためのプロシージャを調べたら良いものがあった。↓

●ブラシ名を正規表現パターンで検索し、マッチしたブラシ名リストを作成

(gimp-brushes-get-list "pattern") ⇒ (num-brushes (brush-names-list))

  引数:"pattern"         STRING      ブラシ名を正規表現文字列で指定
        (正規表現 → UNIX 系互換の普通の正規表現パターンで指定する)

  戻値:num-brushes       INT32       リスト内のブラシの数(0以上)
        brush-names-list  STRINGARRAY ブラシ名のリスト

  Script-Fuコンソールでの実行例(全ブラシを検索するなら .* を指定):

    > (gimp-brushes-get-list ".*")
    (54 ("クリップボード" "1. Pixel" "2. Block 01" ..中略.. "z Pepper"))
    > (gimp-brushes-get-list "Cell .*")
    (2 ("Cell 01" "Cell 02"))
    > (gimp-brushes-get-list "Pen.*")
    (3 ("Pencil 01" "Pencil 02" "Pencil Scratch"))
    > (cadr (gimp-brushes-get-list "Pen.*"))
    ("Pencil 01" "Pencil 02" "Pencil Scratch")

リストだけ取り出すなら cadr を使う(戻り値は 2重リストなので)。
ちなみに、自分の Gimp で ".*" (全スキャン)したら(適度に整形)。↓

(54
  ("クリップボード" "1. Pixel" "2. Block 01" "2. Block 02" "2. Block 03"
   "2. Hardness 025" "2. Hardness 050" "2. Hardness 075" "2. Hardness 100"
   "2. Star"
   "Acrylic 01" "Acrylic 02" "Acrylic 03" "Acrylic 04" "Acrylic 05"
   "Animated Confetti" "Bristles 01" "Bristles 02" "Bristles 03"
   "Cell 01" "Cell 02" "Chalk 01" "Chalk 02" "Chalk 03"
   "Charcoal 01" "Charcoal 02" "Confetti" "Galaxy (AP)" "Galaxy, Big"
   "Grass" "Oils 01" "Oils 02" "Oils 03" "Pencil 01" "Pencil 02"
   "Pencil Scratch" "Pixel (1x1 square)" "Sand Dunes (AP)" "Smoke"
   "Sparks" "Splats 01" "Splats 02" "Sponge 01" "Sponge 02" "Structure"
   "Texture 01" "Texture 02"
   "Texture Hose 01" "Texture Hose 02" "Texture Hose 03"
   "Vegetation 01" "Vegetation 02" "Vine" "z Pepper"))

…となった。gimp-obsolete-files のブラシは全く含まれていなかった。
これでは従来の Script-Fuコードの実行に支障が出るのも無理ない話だ。

 プロシージャ―ブラウザーでの説明だと filter が云々…と何言ってんのコイツ、みたいに分かりにくかったので、上記の説明に書き直してみた。要はそんなに難しいことではなかった。

 ブラシの名前リストが作れたので、これを使って各ブラシの属性値を探りたいところだが、記事が長くなってきたので本日はここまでとする。(続く)

2016-09-23 Fri

ブラシのサイズ(太さ)を変更する例

【573】


 自作 Script-Fu のコーディングを再開。
 とりあえず、簡単に手を付けられるところから着手。
 で、とりあえずのサンプル・コード。

;;; -*- encoding : utf-8 -*-
;;; (文字コード utf8:Script-Fu パスに置いて Gimp に読み込ませる)

(define (script-fu-try-using-brush radius hardness size)
  ; ブラシを新規作成 (スクリプト実行中のみ有効:実行終了時に delete)
  (let ((str "atdrw-brush-for-fill"))
    (gimp-brush-new str)        ;新規作成(実際にファイルが作られる)
    (gimp-brush-set-radius str radius)                  ;半径
    (gimp-brush-set-hardness str hardness)              ;硬さ
    (gimp-brush-set-shape str BRUSH-GENERATED-CIRCLE)   ;形状

    ; --- 座標データ:前景レイヤ作成 ---
    (let* (
        (vec '#(120 20 20 220 220 220 120 20))  ;座標データ(三角形)
        (ImageWidth 240)                        ;イメージサイズ
        (ImageHeight 240)
        (Image                                  ;新規イメージ作成
          (car (gimp-image-new ImageWidth ImageHeight RGB)))
        ; 描画イメージと同サイズの前景レイヤを作成
        (Layer (car (gimp-layer-new
              Image
              ImageWidth
              ImageHeight
              RGBA-IMAGE     ;RGBA : アルファチャンネルも追加
              "layer foreground"
              100
              NORMAL)))
        ) ;end bind

      ; --- Gimp プロシージャ実行(副作用) ---
      ; gimp-context-云々… は実行時デフォルト設定を決めるプロシージャ
      ; (gimp-context-push) 〜 (gimp-context-pop) の中で記述すると便利
      (gimp-context-push)
      (gimp-context-set-brush str)            ;デフォルトブラシ変更
      (gimp-context-set-brush-size size)      ;size(ブラシの太さ)
      (gimp-context-set-antialias TRUE)       ;アンチエイリアス有効
      (gimp-context-set-background "white")   ;背景色定義
      (gimp-context-set-foreground "black")   ;描画色定義

      ; 前景レイヤを画像に配置(0 が最前景となる)
      (gimp-image-add-layer Image Layer 0)
      ; 前景レイヤを塗り潰す:画像のゴミを一掃(VRAM クリア)
      (gimp-drawable-fill Layer BACKGROUND-FILL)    ;white
      ;(gimp-drawable-fill Layer TRANSPARENT-FILL)  ;こうすると透明になる

      ; 本体(ペイントブラシで描画):
      (gimp-paintbrush-default Layer (vector-length vec) vec)

      (gimp-context-pop)
      (gimp-brush-delete "atdrw-brush-for-fill")
      (gimp-display-new Image)     ; 画像表示
      (gimp-image-clean-all Image) ; [Ctrl-W] で破棄(メッセージ表示しない)

      ; 画像、レイヤ、座標データ(ベクタ) を戻り値として返す
      (list Image Layer vec) )))

(script-fu-register
  "script-fu-try-using-brush"                         ;1 func name
  "<Image>/File/Create/ブラシサイズ・テスト"          ;2 menu label
  "スクリプト実行中のみ有効のブラシを使って太さ変更"  ;3 description
  "http://d.hatena.ne.jp/foussin/archive?word=*[script-fu]" ;4 author?
  "foussin(japan)"                                    ;5 copyright notice
  "2016.09.23 Fri 00:04"                              ;6 date created
  ""                                                  ;7 image type
  SF-VALUE  "新規ブラシ 半径(1-30)"         "2"       ;radius
  SF-VALUE  "新規ブラシ 硬さ(1-30)"         "2"       ;hardness
  SF-VALUE  "新規ブラシ 太さ(size)(1-30)"   "2"       ;size(context)
  )

 線の太さを変える方法を確認するためのサンプルとして、なるべく短いコードを目指したが、それでも 70行弱ぐらいになってしまった。実行風景は次のような感じ。↓

f:id:foussin:20160923044832j:image
01-実行風景.jpg

f:id:foussin:20160923044833j:image
02-サイズ-1.jpg

f:id:foussin:20160923044834j:image
03-サイズ-30.jpg

 半径、硬さ、サイズ(太さ)を指定できる形にしてみたが、一番効果が大きかったのは『太さ(size)』のパラメータ指定だった。それを実現するのは
gimp-context-set-brush-size』というプロシージャだと分かった。これは『鉛筆』『ペイントブラシ(筆)』『エアブラシ』ツールで線を引く時に使えるプロシージャだった。

 やり方としては、ダミーのブラシを新規作成しておいて、それをデフォルトのブラシとして指定し、実行終了時に実行前の環境に戻す…という使い方が妥当と思った。ソース中のコメントにヒントになりうることを書いておいたので、詳しい説明は省く。

2016-09-17 Sat

Perl でパーフェクト・シャッフル…

【572】

use strict;
use warnings;

my @small = "a".."z";
my @large = "A".."Z";
my ($len, $ct) = @ARGV;     # $len:デック枚数,  $ct:ループ回数
                            # デック枚数=山札総数÷2 (26以内)
$len or $len = 26;          # デフォルト値
$ct or $ct = 10;
my @d1 = @small[0..$len-1];
my @d2 = @large[0..$len-1];
my @shuffled;

for (my $i=0; $i<$ct; ++$i) {
    printf "%02d: @d1\n    @d2\n\n", $i;
    @shuffled = riffle_shuffle(\@d1, \@d2);
    @d1 = @shuffled[0..$len-1];             # (set! d1 (take lis len))
    @d2 = @shuffled[$len..$len*2-1];        # (set! d2 (drop lis len))
}

# リフル・シャッフル(正確にはパーフェクト・シャッフル)
sub riffle_shuffle {
    my ($ref1, $ref2) = @_;
    my $len = @$ref1;
    my @shuffled;
    for (my $i=0; $i<$len; ++$i) {
        push @shuffled, $$ref1[$i], $$ref2[$i];
    }
    return @shuffled;
}
__END__
neta.pl

 2016-09-16-Fri> neta.pl
 00: a b c d e f g h i j k l m n o p q r s t u v w x y z
     A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

 01: a A b B c C d D e E f F g G h H i I j J k K l L m M
     n N o O p P q Q r R s S t T u U v V w W x X y Y z Z

 02: a n A N b o B O c p C P d q D Q e r E R f s F S g t
     G T h u H U i v I V j w J W k x K X l y L Y m z M Z

 …中略…

 06: a e i m q u y C G K O S W b f j n r v z D H L P T X
     c g k o s w A E I M Q U Y d h l p t x B F J N R V Z

 07: a c e g i k m o q s u w y A C E G I K M O Q S U W Y
     b d f h j l n p r t v x z B D F H J L N P R T V X Z

 08: a b c d e f g h i j k l m n o p q r s t u v w x y z    ←←←←
     A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

 09: a A b B c C d D e E f F g G h H i I j J k K l L m M
     n N o O p P q Q r R s S t T u U v V w W x X y Y z Z


 2016-09-16-Fri> neta.pl 13 22
 00: a b c d e f g h i j k l m
     A B C D E F G H I J K L M

 01: a A b B c C d D e E f F g
     G h H i I j J k K l L m M

 …中略…

 18: a e i m D H L d h l C G K
     c g k B F J b f j A E I M

 19: a c e g i k m B D F H J L
     b d f h j l A C E G I K M

 20: a b c d e f g h i j k l m   ←←←←
     A B C D E F G H I J K L M

 21: a A b B c C d D e E f F g
     G h H i I j J k K l L m M

 Perl の forループ(単純ループ)で記述すれば、「なんだ、こんなもんかパーフェクト・シャッフル」…と思って、ちょっと安心したりする。

 自分にとっての Perl は慣れ親しんだ言語だし、面倒なことはコンパイラが勝手にやってくれるので、デック枚数やループ回数などをオプション指定するとかの小芝居を入れる余裕もできて…。要するに、心にゆとりができるので、大らかな気持ちでコーディングできるのかな(見栄えはごちゃってるけど、Perl ソースに美は求めないので)。。。