独自の機能を GIMP に追加する

GNU Image Manipulation Program のコード・ベースを詳しく探る

GIMP (GNU Image Manipulation Program) はデジタル画像を編集および操作するための堅牢なアプリケーションです。オープンソースのソフトウェアであるため、どの開発者でもこのソフトウェアを変更して、さらに機能を追加することができます。この記事を読んで、GIMP コードを使用する方法、Git リポジトリーからプロジェクトをビルドする方法、そしてコード・ツリーで検索対象を見つけ出す方法を学んでください。記事ではサンプル・アプリケーションとして、このプログラムのための全く新しいペインティング・ツールを作成します。

Joao Bueno, Associate Professor, FATEC Americana

Joao BuenoJoão Bueno は 2004年以来、GIMP のコントリビューターとしてブラジル・ポルトガル語の翻訳主任などを務めています。ブラジルに住む彼は、Python プログラミング言語やグラフィック・ソフトウェアが関係する有料プロジェクトに取り組んでいます。Brazilian Python Association の理事長兼取締役であり、FATEC Americana では准教授として非常勤で教鞭をとっています。



2010年 7月 20日

GIMP を使う理由とは

無料の、またはオープンソースのソフトウェアを使用する大きな理由の 1 つは、製品のユーザーが自分の好みで、あるいは必要に応じて機能を追加する機会が与えられるためです。けれども機能を追加できるかどうかは、プロジェクトの規模と複雑さ、そして入手可能なドキュメントの性質によって左右されます。GIMP の場合、これは知名度の高い成功したオープンソースのソフトウェア・プロジェクトの 1 つとして数えられていますが、機能を追加するとなると、その膨大なコード・ベースに怖気づいてしまうかもしれません。

この記事の内容を理解するには、C プログラミング言語についての十分な知識が必要です。また、Git バージョン管理ツールについて知っているか、あるいは学習する心構えができている必要もあります。この記事のサンプル・アプリケーションは、Linux® 環境で GIMP V2.7 を使用して作成しました (V2.7 は開発ブランチであって、安定版リリースではないことに注意してください)。記事では Mandriva Linux の 2009年春のバージョンを使用しましたが、Linux のどのバージョンを使っても問題ないはずです (「参考文献」を参照)。

これから、既存のペインティング・ツールを基に新しいツールを作成しますが、この記事で作成するツールは純粋に説明を目的としたものです。このツールを実際のプロジェクトにして GIMP ディストリビューションの一部として使用できるようにするには、GIMP の中心的開発者および UI アーキテクトによる入念な検査を受ける必要があります。


準備手順

GIMP での作業に向けた最初のステップは、GIMP をビルドすることです。ソースの tarball を解凍すれば、簡単にコードを調べることができます。また、コード・リポジトリーへの Git Web インターフェースを使えばさらに簡単にコードを調べることができますが、実際に GIMP をビルドする段階では注意が必要です。

ソース・コードのサイズの割には、GIMP は保守しやすく、ビルドするにも一貫性があります。けれども、必要とされる依存関係の問題に対処する必要が出てきます。GIMP のようなソフトウェアを実行すると、気付かないうちに多数のライブラリーがシステムにインストールされます。ソフトウェアをビルドするには、ライブラリーのバイナリーだけでは情報が足りません。ほとんどの Linux ディストリビューションでは、これらの依存関係をメインのパッケージとは別にパッケージ化しています。ライブラリーの他に、コンパイラーそのもの、そして関連するツール・チェーンも必要です。よく使われている Linux ディストリビューションのほとんどでは、いくつかのコマンドを入力するだけで必要なすべてのものを準備することができます。

Windows で GIMP をビルドする場合

GIMP を Microsoft® Windows® システムでビルドする場合はさらに注意が必要になります。この場合のビルドは、デフォルトで Linux システムにインストールされる多数のプログラムとライブラリーがあることを前提として行われるためです。Windows でビルドするとしたら、仮想マシンに Linux をインストールしてビルド環境をセットアップすることをお勧めします。Linux 仮想マシンからは、Mingw32 ツール (「参考文献」を参照) を使って Windows 対応の GIMP をコンパイルすることができます。

GIMP ソース・コード自体としては、Git から開発バージョンのうちのいずれかを取得してください。安定バージョンのコードで作業するとしても、Git ツリーを取得することをお勧めします。そうすれば、コードで行った独自の変更を追跡し易くなります。Git は分散型バージョン管理ソフトウェアなので、GIMP コードをメイン・リポジトリーで管理するために使用することができます。グラフィック・インターフェースもありますが、Git はコマンドラインから使用するように設計されています。

GIMP ソース・コードを取得する

最新の開発バージョンを取得するには、コマンドラインから git clone git://git.gnome.org/gimp と入力します。すると数分もすれば、完全な GIMP コードを入手することができます。ダウンロードはよく整理されているため、3,000 以上のファイルの中から比較的簡単に検索することができます。

Git の使用に関する注意

変更を行う際、オリジナルのファイルを失う心配はありません。また、カスタマイズ用に変更内容を保持することにした場合でも、オリジナルのファイルが失われることはありません。これは Git システムのおかげです。例えば、任意のファイルを GIMP リポジトリーに含まれているときの状態に戻すには、git checkout <filename> と入力するだけのことです。

コードを貢献する予定ではないとしても、Git については十分理解しておいてください。Git によって作業が遥かに楽になるからです。それは、コード・ベースに対して行った変更を追跡するためだけに Git を使用しているとしても同じことで、例えば git diff と入力するだけで、その時点までにコード・ベースに加えたすべての変更を確認することができます。

Git を適切に使用することで、ローカル・ブランチを作成してそこから別の機能を開発し、任意の時点でローカル・ブランチを更新して GIMP に変更を反映することができます。


GIMP のビルド

GIMP 開発ブランチ (Git マスター) をビルドするには、リスト 1 に示す最新バージョンのライブラリーと、それぞれに対応するヘッダーをインストールする必要があります。通常、これらのヘッダーは *-dev または *-devel という名前の Linux パッケージで提供されています。

ビルドを開始する前に、GIMP ソース・ファイルに含まれている HACKING ファイルを調べてください。このファイルは、プロジェクトの開発ルールを指定するファイルです。

リスト 1. 現行の Git マスターをビルドするために必要なライブラリー
glib 2.24.0
gtk 2.20.0
babl, 0.1.2
gegl, 0.1.2
libpng 1.2.34
cairo 1.6.0
pango 1.20.1
fontconfig 2.2.0
gtkdoc 1.0

これらの必須ライブラリーの他、リスト 2 に記載するライブラリーも必要になります。これらのライブラリーが検出されなければ、そのライブラリーの機能が欠落することになります。したがって、ビルド・システムにはライブラリーを無視するよう指示するオプションを渡さなければなりません。例えば、libpng の開発パッケージがインストールされていない場合には、autogen.sh を autogen.sh --prefix=<prefix> --without-libpng と指定して呼び出すことになります。

リスト 2. その他の重要なライブラリー
pygtk 2.10.4
poppler0.4.1
libcurl 7.15.1
dbus_glib 0.70
libhal 0.5.7
exif  0.6.15
lcms 1.16
libpng 1.2.37

システム上にあるライブラリーが最新のバージョンであることを確認する

システム上にあるライブラリーが最新のものになっていれば、Linux ディストリビューションのパッケージ管理システムは必要なライブラリーとその devel パッケージを自動的に取得することができます。

Ubuntu および Debian の場合、単純に sudo apt-get build-dep gimp と入力します。

Mandriva Linux では、URPMI の --buildrequires オプションを使用して、urpmi --buildrequires gimp のように実行することができます。この場合、最初にソース rpm リポジトリーを構成しておいてください。

OpenSuSE の場合は、zypper コマンドに関する資料を調べる必要があるかもしれません。

Fedora、Redhat、CentOS、SuSe をはじめ、その他のディストリビューションのほとんどでは、-devel パッケージを手動でインストールしなければなりませんが、インストールし忘れたとしても心配は要りません。その場合には、ビルド・システムが停止してインストールするように促します。このときに出力されるメッセージは、「ライブラリー x が欠落しています」というような、誤解を招くようなメッセージですが、簡単なチェックによって、システムにライブラリー x がインストールされていることがわかります。ライブラリーをチェックするためのディストリビューション共通のコマンドは、pkg-config です。例えば pkg-config --modversion gtk+-2.0 と入力すると、インストールされている GTK+ V2.x のバージョンが表示されます。

ビルド・システムから、バージョンが古いことに関するエラーが出力された場合は、新しい GIMP プレフィックスに新しいバージョンが必要になります。ライブラリーが欠落しているというエラーを受け取った場合、欠落している可能性として高いのは、ソフトウェアがライブラリーをコンパイルするのに必要な C ヘッダー・ファイルです。大抵、これらのヘッダー・ファイルは別のパッケージに含まれています。パッケージ名の最後には、使用しているディレクトリービューションに応じて -dev または -devel が付いています。つまり、システムに GTK V2.20 がインストールされているとしても、gtk2-devel パッケージをインストールする必要があるということです。


ディストリビューション・リポジトリーのライブラリーが古かったり欠落したりしている場合

上記で概説したライブラリーのすべてが、Linux ディストリビューションで GIMP をビルドできるように最新バージョンになっているとは限りません。これが特に当てはまるのは、GIMP マスター、つまり開発バージョンをビルドする場合です。その一方、安定版 GIMP をビルドする場合でも、古いシステムではこうした事態が起こる可能性があります。通常、開発版 GIMP をビルドするには、少なくとも GEGL (GEneric Graphics Library) ライブラリーについては Git からビルドする必要があります。

ライブラリーが古かったり欠落したりしている場合には、各ライブラリーの最新の安定版 tarball から取得してください。一般に各ライブラリーのダウンロード・ページには、Web で検索して最初にヒットしたライブラリー x のダウンロードからアクセスすることができます。tarball の代わりに Git バージョンを取得するのも慣例として認められていますが、安定版ではないバージョンは使用せずに、従来通り、各ライブラリーの Git 安定版ブランチを取得するに越したことはありません。

ただし、GEGL ライブラリーについては例外です。このライブラリーの場合は、最新の安定版ブランチではなく、GIMP マスターをビルドするための Git マスター (非安定版) ブランチを取得する必要があります。GEGL は現在、GIMP に含まれる中核的な合成操作を始めとする各種画像操作を置き換えつつあります。GEGL のコードを取得するには、git clone git://git.gnome.org/gegl を実行します。

このようにしてインストールするライブラリーのそれぞれについて (および GIMP 自体についても)、ディストリビューションにインストールされているライブラリーを上書きしないように注意しなければなりません。上書きを防ぐには、別のディレクトリー・プレフィックスでビルドしてください。私が通常使用しているのは、/opt プレフィックスです。--prefix オプションを構成スクリプト (または autogen.sh スクリプト) に渡すという方法の他、以下の変数を作成するという方法もあります (リスト 3 を参照)。

リスト 3. ビルド用の変数
PREFIX=/opt
export PATH=$PREFIX/bin:$PATH
export LD_LIBRARY_PATH=$PREFIX/lib:$LD_LIBRARY_PATH
export ACLOCAL_FLAGS="-I $PREFIX/share/aclocal"

上記の変数を使って最初のライブラリーをインストールする前に、/opt/share/aclocal ディレクトリーがあることを確認します。このディレクトリーがなければ、作成しておいてください。

必要となるコンポーネントの大部分は make システムを使用するため、コンパイルしてシステムにインストールするには、解凍したソース・コードのディレクトリーに切り替えて make を実行します (リスト 4 を参照)。

リスト 4. make を使用することによるコンポーネントのコンパイルとインストール
./configure --prefix=<xxx>
make
sudo make install

Git で取得したライブラリーについては、リスト 4 の最初のコマンド /configure./autogen.sh --prefix=<xxx> に置き換えます。また、GTK+ をビルドする場合には、autogen または configure コマンドラインにオプション --with-xinput=yes を指定します。これにより、タブレットや他の感圧装置が GIMP と連動できるようになります。


GIMP のコンパイル

前提条件が揃えば、後は簡単な作業で GIMP をコンパイルすることができます。前に選択した別のプレフィックスで GIMP が新しいライブラリーを取得し、そのプレフィックスで GIMP をビルドできるように、リスト 4 に記載した環境変数を設定します。こうすることで、これからコンパイルする GIMP と、システムによってインストールされた安定版 GIMP との競合を回避することができます (リスト 5 を参照)。

リスト 5. 環境変数の設定
PREFIX=/opt
export PATH=$PREFIX/bin:$PATH
export LD_LIBRARY_PATH=$PREFIX/lib:$LD_LIBRARY_PATH
export ACLOCAL_FLAGS="-I $PREFIX/share/aclocal"

上記のように環境変数を設定したスクリプトを、ソース・シェル・コマンドで実行します。これらの環境変数は、GIMP をビルドする度に設定する必要があります。スクリプトを実行した後、GIMP ソースの基本ディレクトリーに切り替え、リスト 6 のコマンドを入力します。

リスト 6. make を使用することによる GIMP ソース・コードのビルド
./autogen.sh --prefix=<xxx>
make
sudo make install

欠落したライブラリーに関するエラー・メッセージが表示されたら、「ディストリビューション・リポジトリーのライブラリーが失効または欠落している場合」セクションの説明に従ってください。

ソースの概要

GIMP は正常にビルドされたので、この段階で、GIMP ソース・コードの何が新しいのかを調べてみましょう。

プログラムの機能のなかでも調べてみるとよいのは、ブラシ、パレット、グラデーション、レイヤー・グループなどのリソースにタグを付ける機能、オンキャンバス・テキスト編集、そして新しいペイント・ダイナミクスなどがあり、それぞれを話題にしただけで、GIMP に関する本の一章分もの内容になります。これらの機能の開発は活発に進められているため、こうした箇所を変更することにした場合には、その変更が後になって無益であったということにならないよう、GIMP 開発者と緊密に連携を取るのが賢明です。

ソース・ツリー

GIMP のソースには、最初は 29 のディレクトリーがあります。そのうちの 7 つは、単に他のコンポーネントの変換ファイルを保管するためのディレクトリーです (po.* ディレクトリー)。モジュール・ライブラリー用のディレクトリーは 9 つあり、これらのディレクトリーには、GIMP 自体、または C で作成されたプラグインから使用できる特定の関数と定数が保管されています。注目に値するディレクトリーとしては、plug-ins ディレクトリーもあります。プラグインおよびスクリプトを作成するための scheme (script-fu) と Python 拡張を含め、GIMP に付属のプラグインのコードはすべて、このディレクトリー内に置かれます。

アプリケーション・コード自体は、すべて app ディレクトリー内に保管されています。ここには C ファイルの他、アプリケーションの構成要素が分散して格納された 20 のディレクトリーがあります。これらのディレクトリーには、そこに含まれるコードの処理内容を説明する名前 (dialogs や xcf など) が付いているものもあれば、それよりも一般的な名前 (core、base、actions など) となっているものもあります。

ソース内で対象を検索する

大規模なプロジェクトである GIMP では、すべての機能は整然と分類され、同じ機能のセットを扱うコードがグループにまとめられています。ほとんどの C ファイルは /app ディレクトリーに格納されていて、プロジェクトをビルドすると、1 つの GIMP 実行可能バイナリー内で互いにリンクされます。このディレクトリー内には 900 を超える C ファイルと、これとほとんど同じ数のヘッダー・ファイル (.h) があります。したがって、特定の機能がコード化されている場所を探す場合に備え、検索の方法を知っておく必要があります。

プログラムで目にした機能のコードがどこにあるのかを見つけるのに最適な手段の 1 つは、grep コマンドです。grep は、UNIX® に標準装備されたコマンドライン・ユーティリティーで、1 つ以上のファイルでテキスト・パターンを検索するために使用することができます。機能を見つける確実な方法は、UI 自体に表示されているテキストを検索することです。そのためにはもちろん、英語版の GIMP を実行しているか、画面に表示されるすべてのテキストが po/ ディレクトリー (app ツリーの外部) にあるストリング変換ファイルの中に含まれていなければなりません。

例えば、GIMP ウィンドウを全画面表示に切り替えるためのコードを見つけたいとします。その場合にはまず、この機能のツールチップが「Toggle fullscreen view (全画面表示に切り替える)」(GIMP の「View (表示)」メニュー) であることを確認します。このテキストを確認したら、カレント・ディレクトリーを app ディレクトリーに変更して、grep -i "toggle fullscreen view" ‛find -name "*c" ‛ と入力します。

-i スイッチは grep に大文字と小文字の区別を無視するように指示します。‛find -name "*c" サブコマンドが返すのは、検索対象のディレクトリー・ツリー内にあるすべての C ファイルのリストです (サブコマンドが逆引用符で囲まれていることに注意してください。このコマンドは逆引用符以外の引用符では機能しないため、逆引用符の使用が必須です)。grep はすべての C ファイルを調べて、指定されたテキスト・パターンを検索します。その結果、以下の応答が返ってきます。

./actions/view-actions.c:    NC_("view-action", "Toggle fullscreen view"),

このファイルの内容を調べるには、less コマンドを使用することをお勧めします。ファイルの内容を詳細に調べるには、お好みのテキスト・エディターを使用してください (リスト 7 を参照)。

リスト 7. view-actions.c ファイルの内容
  { "view-fullscreen", GTK_STOCK_FULLSCREEN,
    NC_("view-action", "Fullscr_een"), "F11",
    NC_("view-action", "Toggle fullscreen view"),
    G_CALLBACK (view_fullscreen_cmd_callback),
    FALSE,
    GIMP_HELP_VIEW_FULLSCREEN },

このファイルが果たす役割を完全に理解しなくても、次のステップは予想できるはずです。action エントリーは単に、アクションを view_fullscreen_cmd_callback という名前の関数に関連付けるにすぎません。そこで次のステップとなるのが、grep をもう一度実行することです。これまでにわかっている限りでは、この関数はツリーのどこにでも存在する可能性があります。

grep -i  "view_fullscreen_cmd_callback" ‛find -name "*c" ‛

上記を実行すると、2 つの検索結果が返されます。1 つは actions.c ファイルで見つかったエントリー、もう 1 つは ./actions/view-commands.c ファイル内のエントリーです。このファイルの中身を見ると、ようやくコードが見つかります。このファイルには C 関数があります。この関数は、ウィンドウの有無のチェック、アクティブな画像の取得、そして gimp_image_window_set_fullscreen 関数の呼び出しを行います。C 関数によって呼び出されるこの関数が、ご想像のとおり、次の grep のターゲットとなります。

grep -i  gimp_image_window_set_fullscreen   ‛find -name "*c" ‛

上記を検索すると、app/display/gimpimagewindow.c というファイル (リスト 8 を参照) がすぐに見つかります。このファイルの内容を調べると、関数の実行内容がわかります。それはむしろ単純な内容で、ウィンドウを最大化する GTK+ 関数を呼び出すにすぎません。

リスト 8. app/display/gimpimagewindow.c
gimp_image_window_set_fullscreen (GimpImageWindow *window,
                                  gboolean         fullscreen)
{
  g_return_if_fail (GIMP_IS_IMAGE_WINDOW (window));

  if (fullscreen != gimp_image_window_get_fullscreen (window))
    {
      if (fullscreen)
        gtk_window_fullscreen (GTK_WINDOW (window));
      else
        gtk_window_unfullscreen (GTK_WINDOW (window));
    }
}

ウィンドウを最大化するための関数自体はごく単純なものですが、上記のファイルの内容を検討することによって、GIMPの内部処理をよく理解できるようになります。このファイルには、トップ・ウィンドウを表示して、その属性を維持するためのコードが含まれています。GIMP V2.7 ツリーを使用しているとしたら、新しい単一ウィンドウ・モードのGIMP でドッキング可能なダイアログを管理するために新規に作成されたコードが大量に追加されているはずです。

ここまでのところで、actions ディレクトリーに置かれた actions および commands ファイルの役割についても十分に理解できたはずです。これらのファイルを完全に理解しなくても、呼び出し可能コマンドがユーザーからのアクションとして作成されることは把握することができます。actions ファイルがツールチップ、表示テキスト、変換ヒントなどのメタ情報を集約することによって、この仕組みをさらに簡素化しています。アクションに名前が付けられた後は、そのアクションを XML ファイルから直接使用し、例えばアプリケーション・メニューに追加できるようになります。app/actions ディレクトリーに保管されたアクションからメニューを作成する XML ファイルはすべて、プロジェクトのルート・ディレクトリーの menu ディレクトリーに置かれます。そのため、GIMP のメニューを再編成するには、XML ファイルを編集するだけでよくなります。


GIMP ソース・コードの変更

ソース・ツリーの中で機能を見つける方法がわかったところで、次に、変更の作業に移ります。現段階では、マイナーな変更を加え、変更そのものが上手く行くかどうかを確認しなければなりません。そこで、上記の関数呼び出しをコメント・アウトして GIMP を再ビルドし、全画面機能を無効にしてみます。

上記の app/display/gimpimagewindow.c ファイルを編集できるように開き、 gimp_image_window_set_fullscreen 関数内の最初の行に return; 文を追加します。続いて make と入力して GIMP アプリケーションを再ビルドします。autogen.sh を再実行する必要はありません。また、app ディレクトリーに生成された gimp-2.7 バイナリー・ファイルを再インストールの代わりに実行するのでも構いません。変更後のバージョンの GIMP には、全画面機能がないはずです。

C でのオブジェクト指向プログラミング

一般に、C はオブジェクト指向 (OO) 言語とは見なされていませんが、OO は言語に本来備わっている性質というよりは、アプリケーションを構築する 1 つの方法です。クラス/インスタンスの構文を使用しなければならない言語で非 OO アプリケーションをコーディングできるのと同じく、高級言語が規定する構文に従わずに OO コードを作成することも可能です。

それは、GIMP での場合に当てはまります。GIMP は GObject フレームワークベースをベースとするため、C コードを OO 流に作成すると、C コードは実行時に OO のように振る舞います。その場合の難点は、ボイラープレート・コードを使って新しいクラスを作成し、オブジェクトを操作しなければならないことです。しかしその一方で、このやり方は上手く行きます。

OO ライブラリーを C で作成することの利点の 1 つは、Python、Ruby、Java プログラミング言語のような他の言語との言語バインディングを使用できるようになることです。GTK+ や GEGL をはじめ、GIMP と密接に結び付いた多くのライブラリーも、GObject システムを使用します。


新しいツールの作成

ここからは、プログラムを実際に変更する作業に取り掛かります。この記事の例では、ペインティング・ツールを作成し、そのツールをツール・ボックスから選択できるようにします。新しいツールを作成する前には必ず、プログラムの既存の機能を再確認しておく必要があることを忘れないでください。

ペイント・ダイナミクス、アニメーション・ブラシ、ペインティング・モード、および既存のツールに考えられる組み合わせのうち、さまざまな組み合わせを実現することができます。現在不可能なのは、例えば 1 つのペイント・ストロークの色を放射線状に変更し、ブラシの中心とブラシ・マスク外側の部分にそれぞれ別の色を使用することです。これは「グラデーションの色」ペインティング・オプションのための機能なので、アクティブなグラデーションに従って、ストロークの色が選択されます。

変更対象を検索する

最初のステップでは、上記で説明したように振る舞うペインティング・ツールをアプリケーションに追加するには、どのファイルをコピーし、変更し、ビルド・システムに追加しなければならないかを特定します。まず初めに探すのにふさわしい場所は、app/tools ディレクトリーです。このディレクトリーに置かれている gimppaintbrushtool.h ファイルと gimppaintbrushtool.c ファイルを調べてください。

残念なことに、この 2 つの小さなファイルは、ツールを GObject クラスとして作成するためのボイラープレート・コードでほとんど占められています。コマンドラインに戻り、今度は grep で app ディレクトリー内の paintbrush を検索し、関連するコードが含まれている別のファイルがないかどうかを調べられます。

今度は、複数のファイルとそれぞれのファイル内での該当箇所を含む多少長いリストが返されます。嬉しいことに結果を得られましたが、あまり嬉しくないことに、ここではペイントブラシ・ツールを複製しようとしていることから、リストに含まれるほとんどのファイルとそれに対応するヘッダー (.h) ファイルにアクセスし、ファイルをコピーするか、あるいは現行のペイントブラシ・ツールへの参照として、新しいツールに参照を追加しなければなりません。

grep を実行してリストアップされたファイルは、リスト 9 のとおりです。

リスト 9. grep による paintbrush の検索結果
./core/gimpbrush.c
./core/gimpcontext.c
./paint/gimp-paint.c
./paint/gimpairbrush.c
./paint/gimppaintbrush.c
./pdb/paint-tools-cmds.c
./tools/gimp-tools.c
./tools/gimppaintbrushtool.c
./widgets/gimpcursor.c

上記には、ツール・サフィックスを持たない gimppaintbrush.c という別のファイルがリストアップされています。このファイルを編集できるように開いてください。このファイルは期待できそうです。ファイルに含まれている最後の _gimp_paintbrush_motion という関数は、実際には一連の関数呼び出しを行い、ペイント対象のバッファー領域、使用される現行のブラシ、ペインティング・オプションとペインティング・ダイナミクス・システムから適用する色を取得して、ペイント対象のバッファーのピクセルを塗りつぶします。そして最後に gimp_brush_core_paste_canvas を呼び出してストロークをコミットします。

ちょっとした変更を試してみる

GIMP の最大の利点は、基本的な C コードの知識があれば、コードの処理内容を理解できることです。今や、ほとんどの関数名とオブジェクト・システムはそれぞれの存在価値を示しているので、このコードは簡単に理解できるはずです。grep を使って関数を検索し、その関数のコードを調べることで、関数呼び出しの実行内容を確認することもできます。

特定のペインティング・モードや不透明度しか使用しないとしても、ここでいろいろと変更してみて、変更が適用されることを確認してください。例えば、関数が opacity 変数を呼び出す前に、この変数の値を固定の数値に置き換えてみるのも一考です。

目的とする変更を行う

作業を進めるには、paintbrush ファイルでの適切な変更が目的とする効果を得られるとわかった時点で、このファイルをコピーし、そのファイル名を変更してください。ファイルには、新しいツールに付けることにした名前を付けるのが得策です。この例では、gradientbrush という名前にします。

app/paint/paintbrush.c ファイルと app/paint/paintbrush.h ファイルを同じディレクトリーにコピーして、gradientbrush.c と gradientbrush.h という名前に変更します。この 2 つのファイルを編集し、paintbrush、Paintbrush、PAINTBRUSH 等々のようになっているテキストを、それぞれに応じて新しい名前 gradientbrush に置換します。ここで重要となるのは、すべてのインスタンスで大文字と小文字の区別に従うことです。この作業によって、新しいツールの新規 GObject クラスが作成されます。

make を実行して新規ファイルをコンパイルするには、新規ファイルが置かれているディレクトリーに Makefile.am ファイルを追加する必要があります。このファイルさえ追加すれば、新規ファイルがビルドの実行時にコンパイルおよびリンクされ、GIMP 実行可能ファイルが生成されます。

ビルドによって作成されるのは新しい GIMP コアだけです。このコアは、新規ツールに統合して登録しない限り、何の役目も果たしません。

もちろん、すべてが準備できた時点で、ペインティング関数自体に対して目的とする変更を行い、この関数が目的とするタスクを行うようにする必要があります。そのタスクとは、ブラシに沿って放射線状の色のグラデーションでペイントすることです (リスト 10 に、この関数のコードを記載しています)。

ここからは、必要な変更のほとんどのすべてには、paintbrush という用語が含まれるファイルのほとんどを編集するという作業が関わってきます。そのファイルが他のすべてのペイント・ツールをリストアップしたファイルであれば、paintbrush を参照している行をコピーして、gradientbrush に作用するように書き換えるだけでよいのです。

注意する点として、この例では新しいアイコンやツール・カーソルは作成していないため、ペイントブラシのオカレンスはそのまま、GIMP_STOCK_TOOL_PAINTBRUSH、GIMP_TOOL_CURSOR_PAINTBRUSH として保持されています。

paint ディレクトリーに置かれたコードは、各種のツールで実際に画像を更新する役割を果たし、tools ディレクトリーに置かれたコードは、ペイントブラシや塗りつぶしなどのツール機能をユーザー・インターフェースに結び付ける役割を果たします。この 2 つのディレクトリーの両方に、新しいツールを作成するめに更新しなければならないファイルがあります。

ペイントブラシ・ツールのコピーを paint ディレクトリーに追加するには、以下の手順に従います。

  1. gimppaintbrush.c および gimppaintbrush.h ファイルを gimpgradientbrush.* にコピーし、コピーした 2 つのファイルの中に含まれるすべての paintbrush を gradientbrush に名前変更します (大文字、小文字の区別に従うこと)。
  2. Makefile.am ファイルに、gimpgradientbrush.h と gimpgradientbrush.c への参照を追加します。
  3. gimp-paint.c ファイルに gimpgradientbrush.h ヘッダー・ファイルのインクルード文を追加し、gimp_paint_init 関数内のリストに gimp_gradientbrush_register 関数を追加します。
  4. paint-types.h ファイルに、GimpPaintbrush に使用されているような typedef 行を追加します。

ペイントブラシのコピーを tool ディレクトリーに追加する手順は以下のとおりです。

  1. gimppaintbrushtool (c および h) ファイルを gimpgradientbrushtool バージョンにコピーし、内部参照の名前を新しいツール名に変更します。
  2. Makefile.am ファイルに、2 つの新しい gimpgradientbrushtool ファイルへの参照を追加します。
  3. gimp-tools.c ファイルに gimpgradientbrushtool.h ヘッダー・ファイルのインクルード文を追加し、gimp_tools_init 関数内のリストに gimp_gradientbrush_register 関数を追加します。さらに、gimp_tools_register 関数内に、ペイントブラシに使用されているような else if ブロックを追加し、そこで paint_code_namegimp-gradientbrush に結び付けます。

以上の手順で、目的を達成できるはずです。ビルドの際には、追加のペイントブラシ・アイコンをツール・ボックスで選択できるようにする必要があります (図 1 を参照)。

図 1. 新たに作成したツールが表示された GIMP のツール・ボックス
GIMP のツール・ボックスのスクリーン・ショット。リストの最後に、2 つ目のペイントブラシ・アイコンが表示されています。

コード自体の変更は、やや広範なものになります。リスト 10 に、app/paint/gimpgradientbrush.c ファイルに含まれる _gimp_gradientbrush_motion のコードを記載します。ここが、新規ツールを作成するために新しいコードを作成しなければならない唯一の場所です。

リスト 10. _gimp_gradientbrush_motion のコード
void
_gimp_gradientbrush_motion (GimpPaintCore    *paint_core,
                            GimpDrawable     *drawable,
                            GimpPaintOptions *paint_options,
                            const GimpCoords *coords,
                            gdouble           opacity)
{
  GimpBrushCore            *brush_core = GIMP_BRUSH_CORE (paint_core);
  GimpContext              *context    = GIMP_CONTEXT (paint_options);
  GimpDynamics             *dynamics   = brush_core->dynamics;
  GimpImage                *image;
  GimpRGB                   gradient_color; 
  TempBuf                  *area;
  guchar                   *col;
  GimpPaintApplicationMode  paint_appl_mode;
  gdouble                   fade_point;
  gdouble                   force;
  guchar                   *colors;
  gint                      max_colors;
  gint                      x, y;
  gint                      u, v;
  guchar                   *area_data;
  GimpGradient             *gradient;
  gdouble                   cx, cy;

  image = gimp_item_get_image (GIMP_ITEM (drawable));
  fade_point = gimp_paint_options_get_fade (paint_options, image,
                                            paint_core->pixel_dist);

  opacity *= gimp_dynamics_output_get_linear_value (dynamics->opacity_output,
                                                    coords,
                                                    paint_options,
                                                    fade_point);
  if (opacity == 0.0)
    return;

  area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options,
                                         coords);
  if (! area)
    return;

  paint_appl_mode = GIMP_PAINT_INCREMENTAL;;

  gradient = gimp_context_get_gradient (GIMP_CONTEXT (paint_options));
  max_colors = (gint)(sqrt(area->width * area->width +
                      area->height * area->height) / 2) + 1;
  colors = g_malloc(max_colors * MAX_CHANNELS);

  for (x = 0; x < max_colors; x++)
    {
      gimp_gradient_get_color_at (gradient, GIMP_CONTEXT (paint_options),
                          NULL, (gdouble)x / max_colors,
                          paint_options->gradient_options->gradient_reverse,
                         &gradient_color);
       col = &colors[x * MAX_CHANNELS];
       gimp_rgba_get_uchar (&gradient_color,
                            &col[RED],  
                            &col[GREEN],
                            &col[BLUE],
                            &col[ALPHA]);
    }

  area_data = temp_buf_get_data(area);
  cx = area->width / 2;
  cy = area->height / 2;
  for (x = 0; x < area->width; x++)
     for (y = 0; y < area->height; y++)
        {
           u = (gint)sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy)) * MAX_CHANNELS;
           v = (x + y * area->width) * area->bytes;
           if (area->bytes >= 3)
             {
               area_data[v + RED] = colors[u + RED];
               area_data[v + GREEN] = colors[u + GREEN];
               area_data[v + BLUE] = colors[u + BLUE];
               if (area->bytes == 4)
                 area_data[v + ALPHA] = colors[u + ALPHA];
             }
          else
            {
              /* FIXME: get color value instead; */
              area_data[v] = colors[u + RED];
              if (area->bytes == 2)
                area_data[v] = colors[u + ALPHA];
            }
        }

  force = gimp_dynamics_output_get_linear_value (dynamics->force_output,
                                                    coords,
                                                    paint_options,
                                                    fade_point);

  /* finally, let the brush core paste the colored area on the canvas */
  gimp_brush_core_paste_canvas (brush_core, drawable,
                                coords,
                                MIN (opacity, GIMP_OPACITY_OPAQUE),
                                gimp_context_get_opacity (context),
                                gimp_context_get_paint_mode (context),
                                gimp_paint_options_get_brush_mode (paint_options),
                                force,
                                paint_appl_mode);
  g_free(colors);
}

_gimp_gradientbrush_motion 関数は、ペインティング・ツールのペイント・ストロークごとに呼び出されます。この関数は、GIMP でペイントするために使用されているブラシが含まれる四角形の対角線の半分のサイズを持つ内部バッファーを作成し、そこに、アクティブなグラデーションから抽出された色を取り込みます。続いてこの領域にマッピングを含めます。このマッピングは、各ストロークのペインティング領域に色を付けるための画像バッファーです。この新しい関数は、(gimppaintbrush.c の元の関数のように) 一色で塗りつぶすための関数を呼び出す代わりに、各ピクセルをウォークスルーし、ブラシの中心からの距離に応じて色を割り当てます。

_gimp_gradientbrush_motion のコードを、リスト 10 のコードに置き換えてください。これまでの変更内容で GIMP をビルドするには、make を実行し、このコマンドが完了した後に、root として make install を実行します。すると、完全に機能する新しいツールが GIMP に作成されます。

図 2 に、この新しいツールと、ペインティング方向を追跡するように設定されたペイント・ダイナミクス・システム、そして高アスペクト比ブラシを使用して作成した簡単な下絵を示します。

図 2. gradientbrush ツールの使用例
新規 gradientbrush ツールを使用している状態のスクリーン・ショット

これで、GIMP に独自のツールを作成することができました。

新しいツールを作成することを決める前には、GIMP 対応のプラグインを作成することも検討してください。GIMP 対応のプラグインを作成する方が、コアに変更を加えるよりも作業が簡単になります。ただし、プラグインの場合には、ユーザーが画像ウィンドウ自体で操作できないなど、その機能が制限されます。プレビューやユーザー操作はすべて、メインのアプリケーションとは区別されなければなりません。その一方、プラグインを作成すれば、プラグイン自体を配布できるため、GIMP のカスタム・バージョンを作成しなくても、他のユーザーが使用することができます。


まとめ

これで皆さんは、GIMP ソース・コードと依存関係を取得する方法、そして Linux システムで GIMP をビルドする方法について確実な理解を得られたはずです。この記事ではペイントブラシを作成する例を通して、ソース・ツリーをナビゲートし、grep を使って変更対象の機能を実装するコードを見つける方法を説明しました。また、GIMP の新規ツールを作成するためには何が必要なのかも説明しました。いつの日か、皆さんが作成した新しい機能が GIMP ソースに組み込まれ、世界中の何百万人ものユーザーが使用することになるかもしれません。


ダウンロード

内容ファイル名サイズ
Article source codeos-gimp-add.gradientbrush.tool.zip5KB

参考文献

学ぶために

  • Git の学習方法についての情報、そして GIMP やその他のソフトウェアをリポジトリーから取得するには、Getting the most out of Git in GNOME を調べてください。
  • GIMP Development サイトから、API マニュアル、コード・スタイルに関する情報などを入手できます。
  • GIMP.org には必ずアクセスしてください。
  • GObject Reference Manual で、オブジェクト指向の手法がどのように機能するかについて説明しています。
  • 重要なコードを作成する前に、GIMP メーリング・リストを利用して GIMP の開発者と直接連絡を取り、意見を交換してください。
  • GIMP Python Documentation を読んで、Python プラグインの作成方法に関する情報を入手してください。
  • GTK+ Project に、GTK+ とその他の関連するライブラリーの資料が用意されています。
  • developerWorks podcasts ではソフトウェア開発者のための興味深いインタビューや議論を聞くことができます。
  • developerWorks の Technical events and webcasts で最新情報を入手してください。
  • Twitter で developerWorks をフォローしてください。
  • 世界中で近日中に予定されている IBM オープンソース開発者を対象とした会議、見本市、ウェブキャストやその他のイベントをチェックしてください。
  • オープンソース技術を使用して開発し、IBM の製品と併用するときに役立つ広範囲のハウツー情報、ツール、およびプロジェクト・アップデートについては、developerWorks Open source ゾーンを参照してください。
  • My developerWorks コミュニティーは、多種多様なトピックを網羅した全般的コミュニティーの成功例です。
  • 無料の developerWorks On demand demos で、IBM およびオープンソースの技術と製品機能を調べて試してみてください。

製品や技術を入手するために

  • GIMP V2.7.0 は、GIMP V2.8 に向けた開発の現時点でのスナップショットです。必ず GIMP V2.7 のリリース・ノートを読んでください。
  • Git をダウンロードしてください。最新バージョンは 1.7.1 です。
  • Mandriva Linux について調べてください。
  • GEGL (Generic Graphics Library) にアクセスしてください。GIMP ですでに使用されている GEGL は、GIMP V3.0 でイメージ・データを操作する唯一の方法になる予定です。
  • Mingw32 パッケージを入手してください。
  • IBM ソフトウェアの試用版を使用して、次のオープンソース開発プロジェクトを革新してください。ダウンロード、あるいは DVD で入手できます。
  • IBM 製品の評価版をダウンロードするか、あるいは IBM SOA Sandbox のオンライン試用版で、DB2®、Lotus®、Rational®、Tivoli®、および WebSphere® などが提供するアプリケーション開発ツールやミドルウェア製品を試してみてください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source, Linux
ArticleID=512983
ArticleTitle=独自の機能を GIMP に追加する
publish-date=07202010