GIMP Script-fu:Schemeでの簡単なスクリプトの簡単な学習と作成(+バッチ処理は無料)

エントリー


この記事では、できるだけ早くScheme言語のGIMPでのスクリプトの基本を理解し、簡単で実用的な問題を直接解決する方法を説明します。 この資料は、微妙なことをあまりせずに、貴重な時間を犠牲にすることなく、ここで、そして今、定期的な処理を自動化する人のみを対象としています。 また、この記事をScript-fuとは別にSchemeのガイドとして使用することはお勧めしません 。 これは、この資料のプログラミングスタイルが単純化されていることと、開発の速度よりもはるかに低い懸念を抱いている他の重要な事実を網羅していないためです。

内容:
  1. 何が必要ですか?
  2. 構文概要
  3. 変数
  4. 機能
  5. リスト
  6. GIMPでスクリプトを登録する
  7. コード記述
  8. おわりに

何が必要ですか?


英語のインターフェース :このためには、値「en」で環境変数「LANG」を作成するだけで十分です。 なぜこれが必要なのですか? まず、インターフェイスオブジェクトに一致するプロシージャを探しやすくなります。 第二に、2つの言語でチームを指定する必要はありません。 第三に、インターネット上の英語で最も多くの情報。
Script-fu Console :フィルター→Script-fu→コンソール。 ここでは、言語の習得に必要なコードの小さな断片をテストできます。
手順ブラウザ:ヘルプ→手順ブラウザ。 ここで、必要なアクションを実行する関数を簡単に見つけて、その完全な説明を読むことができます(すべてが十分に文書化されています)。
強調表示および/またはペアリングブラケットカウントを備えたコードエディタ 。 あなたの好みに任せます。 メモ帳++で十分でした。 しかし、多くの括弧があることに注意してください!

次のいくつかのセクションには、 Script-fuドキュメントの最初の4ページからの抜粋と小さなギャグが含まれています。 コンソールで次の例を実行することを強くお勧めします。

構文概要

例を挙げましょう。
(* (+ 1 2) (sqrt (- 13 4)) 10) 

最後は乗算の結果になります。 ご覧のように、3つの引数が乗算関数に渡されます。加算の結果、差からルートを抽出した結果、および数です。 ブラケットの数に注意してください:それらはどこでも必要です。 これは干渉する可能性がありますが、計算対象が常に明確です。例:「 (+ 1 2) 」は正しいコードですが、「 (+ 1 2) 」は正しいコードではありません。

変数


Schemeの変数は、 let*コンストラクトを使用して定義されます。 一般的なビュー:
 (let* ( ( ) ... ( ) ) () ... () ) 

命令型言語と比較すると、これはローカル変数を宣言するようなものです。 つまり、 let*コンストラクトを閉じる括弧の後に、変数は存在しなくなります。
例:
 (let* ( (a 1) (b (+ a 2)) ) (+ ab) ) 

別の例:
 (let* ( (x 9) ) (sqrt x) ) 

変数を1つだけ定義する場合でも、変数のリストの外側の括弧は省略されないことに注意してください!

set!を使用して、変数に新しい値を割り当てることができますset!
 (set!  ) 

例:
 (let* ( (a 42) (b 21) (x 0) ) (set! x (/ ab)) ) 

機能


defineコンストラクトを使用して関数を定義できます。
 (define (_ ) _) 

関数の値は、関数コードの最後のコマンドの結果になります。
モジュールの差を計算する機能を実装します( ) これはabsで実行できますが、もう少し複雑にします。
 (define (difference xy) (if (< x 0) (set! x (- x))) (if (< y 0) (set! y (- y))) (if (> xy) (- xy) (- yx)) ) 

ここでは、最初の引数の真偽をチェックし、それに応じて2番目または3番目の引数を実行するif構文を使用しました(後者は、ご覧のとおりオプションです)。
関数は引数を変数として扱うことができますが、コピーを変更するだけであることに注意してください。 これは次のように確認できます。
 (let* ((a 3) (b -4)) (list (difference ab) ab)) 

list関数は、関数の値、変数b 、変数bいくつかの結果を出力するためにここで使用されます。リストについては以下で詳しく説明します)。 コンソールで実行し、変数の値が変更されていないことを確認します。

リスト


リストを定義するには、次のように記述します(カンマなし):
 '(0 1 1 2 3 5 8 13) 

空のリストは、「 '() 」と'() 」の両方で指定できます。 リストには、アトミック値と他のリストの両方を含めることができます。
 (let* ( (x '("GIMP" (1 2 3) ("is" ("great" () ) ) ) ) ) x ) 

すでに1つのアポストロフィを書いているので、内部リストの前にアポストロフィを付ける必要はありません。
リストの一番上に別の要素を追加するには、連結関数cons使用します。
 (cons 1 '(2 3 4) ) 

空のリストでも同様に機能します( " (cons 1 () ) "は1つのアイテムのリストを提供します)。
以前に宣言された変数の値を含むリストを作成するには、 list関数が必要です。
 (let* ( (a 1) (b 2) (c 3) ) (list abc 4 5) ) 

アポストロフィを使用してリストを定義することの違いを理解するには、「 (list abc 4 5) 」を「 '(abc 4 5) 」に置き換えて、出力を比較します。
これはすべて良いですが、リストの内容をどのように取得しますか? これには2つの機能があります。 最初のcarは、リストの先頭、つまり最初の要素を返します。 2番目のcdrは、リストの末尾、つまり最初の要素を除くすべての要素を含むリストを返します。 両方の関数は、リストが空でないことを前提としています。 例:
 (car '(1 2 3 4) ) 
 (cdr '(1 2 3 4) ) 
 (car '(1) ) 
 (cdr '(1) ) 

cdrcdr順番に呼び出す代わりに、 caadrcddrなどの関数を使用すると便利です。 たとえば、リストの2番目の要素を取得するには、次のように記述します。
 (cadr '("first" "second") ) 
同等です
 (car (cdr '("first" "second") ) ) 

次の例では、このような関数の呼び出しを2回だけ使用して要素3に到達しようとします。
 (let* ( ( x '( (1 2 (3 4 5) 6) 7 8 (9 10) ) ) ) ;    ) 

成功すれば、最初のスクリプトを作成する準備がほぼ整いました。

GIMPでスクリプトを登録する


コードを記述する前に、このための便利な条件を提供します。

ユーザースクリプトの場合、GIMPはホームディレクトリに.gimp-2.6/scriptsフォルダーを.gimp-2.6/scriptsます。 スクリプトを取得するには、scmファイルをその中に置き、GIMPメニューで[フィルター]→[Script-fu]→[スクリプトの更新]を選択します(GIMPが既に実行されている場合、そうでない場合は起動時にすべてがロードされます)。

明らかに、作成した関数はファイルに配置する必要があります。 好きなだけ関数を含めることができますが、論理的に異なる関数を異なるファイルにソートし、内容に敬意を表してファイルに名前を付けると便利です。 別の推奨事項、慣習でさえ:作成した関数は、 script-fu-functionnameちなんで命名する必要がありscript-fu-functionname

概して、これはすでにコンソールから関数を呼び出すのに十分です。
しかし、スクリプトに独自のメニューを持たせたい場合、それを開くとウィンドウが設定とともに開き、登録を担当する2つの関数を追加する必要があります。 複雑なことは何もありません。例を見てください。

不均一な照明の画像のテキストの品質を改善する関数を書きたいとしましょう(実際、私はすでにそれを書きましたが、これは私たちがこれを再びすることを妨げません)。 彼女の定義は次のとおりです。
 (define (script-fu-readability inImage inLayer inRadius inHigh-input)) 

私は知っている、私は知っている、関数宣言のみがあり、それは何もしません。 便利なコードはもう少し後になるでしょう。 これで十分です。 登録は次のように行われます。
 (script-fu-register "script-fu-readability" "Readability" "Improves text readability on the photos. It's needed only when there is a non-uniform illumination" "Dragonizer" "Copyleft, use it at your own sweet will" "January 7, 2011" "RGB* GRAY* INDEXED*" SF-IMAGE "The image" 0 SF-DRAWABLE "The layer" 0 SF-ADJUSTMENT "Median blur: radius" '(15 1 20 1 5 0 SF-SLIDER) SF-ADJUSTMENT "Levels: intensity of highest input" '(235 0 255 1 10 0 SF-SPINNER) ) (script-fu-menu-register "script-fu-readability" "<Image>/Filters/User's scripts") 

最初の関数には次が渡されます。 最初の引数は関数の名前、2番目は表示名、3番目は説明、4番目は作成者、5番目は著作権情報、6番目は作成日です。 7番目-サポートされている画像の種類(RGB、RGBA、GRAY、GRAYA、INDEXED、INDEXEDA)。

後続の引数はオプションです。 SF-IMAGEおよびSF-DRAWABLE )を使用すると、スクリプトウィンドウに、線、ジャックドー、スライダー、スピナー、色、フォントなどのウィジェットを作成して、ユーザーの選択を関数に渡すことができます。 前述のSF-IMAGEは、現在開いている画像へのリンクと、選択したレイヤーへのSF-DRAWABLEます。 これらのSF-*すべてについては説明しませんが、これらのパラメーターはここの表見ることができます (この記事で要約されているので、残りは読む必要はありません)。 そして、私はあなたがこれから必要なものを理解するためにこの写真を見ることを勧めます( ここから取りました )。

ウィンドウの準備ができたので、GIMPメニューに呼び出しを追加し、上記のコードの2番目の機能を作成します。 2つの引数:ここでも、関数の名前とメニューへのパス。 パスは<Image>で始まり、以前にブランチが存在しなかった場合、GIMPはそれらを追加します。

別の例:指定されたプロパティで画像を作成するスクリプトを作成する場合、最初の関数からSF-IMAGEおよびSF-DRAWABLESF-DRAWABLE "RGB* GRAY* INDEXED*"ではなく、空の文字列""を使用します(開いている画像が必要な場合は作成します)、2番目の関数ではパスを"<Image>/File/Create/Something"ように変更します。

結果を楽しむには、「 script-fu-readability.scm 」に創造性を保存し、スクリプトを更新してください。 画像を開いて作成し、メニューからスクリプトを選択します。

コード記述


ここに、憧れの瞬間があります! しかし、私は急いで怒ります。ここには複雑なことは何もありません。 絶対に。 関数の作成方法はすでに知っています。 また、エディターで必要なものはすべて、プロシージャブラウザーで簡単に見つけることができます。 レイヤーで何らかの操作が必要ですか? 「 layer 」を検索します。 画像を反転しますか? 「 invert 」を含むものが必要です。 などなど。

コメントは2つだけにします。そして今、作業コードの例。 ここからアルゴリズムを借りました( Killyに感謝します )。
 (define (script-fu-readability inImage inLayer inRadius inHigh-input) (let* ( (layer2 0) ) (gimp-image-undo-group-start inImage) (if (not (= (car (gimp-image-base-type inImage)) GRAY)) (gimp-image-convert-grayscale inImage)) (set! layer2 (car (gimp-layer-copy inLayer FALSE))) (gimp-image-add-layer inImage layer2 -1) (plug-in-despeckle RUN-NONINTERACTIVE inImage layer2 inRadius 0 -1 256) (gimp-layer-set-mode layer2 DIFFERENCE-MODE) (set! inLayer (car (gimp-image-flatten inImage))) (gimp-invert inLayer) (gimp-levels inLayer HISTOGRAM-VALUE 0 inHigh-input 0.1 0 255) (gimp-image-undo-group-end inImage) ) ) 

手元にプロシージャブラウザがあれば、興味があるかどうかを簡単に把握できます。

バッチ処理


どこへどこへ? それだけではありません。 1枚の写真を処理する不幸なスクリプトを書くために、私たちがそんなにやったと思いますか? はい、手は速くなります! それでは、GIMPに特定のフォルダーのすべてのファイルを開いて処理し、別のフォルダーに保存してみましょう。

最良の部分は、以下のコードを他の何かに合わせて調整し、呼び出す関数を必要なものに置き換えるだけです。他のすべては変更されません(ファイルを別の拡張子に保存したい場合を除きます)。

コードはこのトピックから部分的に借用されていますがApostolに感謝)、ファイルを保存し、元のファイルを上書きします。 morph-filename関数はここから取得されます
 (define (morph-filename orig-name new-extension) (let* ((buffer (vector "" "" ""))) (if (re-match "^(.*)[.]([^.]+)$" orig-name buffer) (string-append (substring orig-name 0 (car (vector-ref buffer 2))) new-extension) ) ) ) (define (script-fu-batch-readability inInFolder inOutFolder inRadius inHigh-input) (let* ((filelist (cadr (file-glob (string-append inInFolder DIR-SEPARATOR "*") 1)))) (while (not (null? filelist)) (let* ((filename (car filelist)) (image (car (gimp-file-load RUN-NONINTERACTIVE filename filename))) (layer (car (gimp-image-get-active-layer image))) ) (script-fu-readability image layer inRadius inHigh-input) (set! layer (car (gimp-image-get-active-layer image))) (set! filename (string-append inOutFolder DIR-SEPARATOR (morph-filename (car (gimp-image-get-name image)) "png"))) (file-png-save2 RUN-NONINTERACTIVE image layer filename filename 0 9 0 0 0 1 0 0 0) (gimp-image-delete image) ) (set! filelist (cdr filelist)) ) ) ) 


おわりに


Readabilityスクリプトとバッチバージョンは、 ここからダウンロードできますミラー )。 コードはコメントアウトされており、多少冗長です。

この記事は広義の包括的であるふりをするものではなく、読者が座って思慮深く読み、同時に練習し、自分のタスクを解決するスクリプトの作成を開始することのみを目的としています。 そのため、多少質の高い言語学習に必要な時間はかかりません。

記事を最後まで読んだら、Script-fuを私より悪くすることはできません。

Source: https://habr.com/ru/post/J111387/


All Articles