[翻訳]GIMPプラグインの作成方法(二)

26156 ワード

私の翻訳は専门ではありませんて、甚だしきに至っては英语はよくなくて、翻訳の内容はただ参考に供します.ブロガーは勉強しながら翻訳するので、翻訳の正確性と正確性を保証することはできません.できれば、原版学習を見てください.本文は学習記録のためだけです.
《How to write a GIMP plug-in, part II》
原文:http://developer.gimp.org/writing-a-plug-in/2/index.html
作者:Dave Neary
第1部ではgimpを用いてプラグインを構築するために必要な基本要素を示し,プラグインに簡単で有用なアルゴリズムを提供する.
紹介する
GIMPのフィルタ-ブラー-ブラーにデフォルトでインストールされる単純なブラーを実装します.このアルゴリズムは非常に簡単で、各画素値をその周囲の画素の平均値に置き換えることができます.例えば、最も簡単な例を挙げて、3×3の行列、値は1から9で、それでは中心の値は5で、9の要素はその隣です
この方法を用いると,エッジ差は(2 r+1)x(2 r+1)行列を用いて異なる半径で曖昧な結果をもたらす.
イメージこうぞう
前の例でrun()関数を書いたことがありますが、あまり機能していません.run()の関数の原形を見てみましょう.
static void run (const gchar     *name,
                 gint             nparams,
                 const GimpParam *param,
                 gint            *nreturn_vals,
                 GimpParam      **return_vals);

最初の3つの入力パラメータのうちの1つは動作モードであり、もう1つは画像の識別子であり、もう1つはアクティブでドラッグ可能な(レイヤまたはマスク)、GIMPの画像は構造体であり、ガイド、レイヤ、マスク、および画像に関連するデータを含む.「ドラッグ可能」はGIMPの内部構造でよく使われ、修正可能なオブジェクトなので、レイヤー、レイヤーが隠され、選択範囲がすべて「ドラッグ可能」です.
  [翻译]如何编写GIMP插件(二)_第1张图片
データの取得
GimpDrawable構造体を識別子から取得するにはgimp_を使用する必要があります.drawable_get()関数:
GimpDrawable *gimp_drawable_get (gint32 drawable_id);

この構造体を使用すると、GimpPixelRgn構造でドラッグ可能なデータにアクセスでき、ドラッグ可能なタイプ(RGB、グレースケール)を表示できます.GimpDrawable関数に関する完全なリストは公式APIで検索できます.
2つのプラグインにとって非常に重要な関数はgimp_です.drawable_mask_bounds()とgimp_pixel_rgn_init().1つ目はドラッグ可能なオブジェクトのアクティブな選択範囲を制限するために使用され、2つ目はGimPixelRgnを初期化するために使用されます.
GimpPixelRgnを初期化した後、ピクセル、矩形、円、柱などの異なる方法でデータにアクセスできます.最善の方法は、使用するアルゴリズムに依存します.また、GIMPはtile-based構造を使用しており、データのロード/ロードにかかるコストが大きいため、必要でない場合は頻繁に使用しないでください.
[翻译]如何编写GIMP插件(二)_第2张图片
主関数の取得と設定の関数は次のとおりです.
void gimp_pixel_rgn_get_pixel (GimpPixelRgn *pr,
                               guchar       *buf,
                               gint          x,
                               gint          y);
void gimp_pixel_rgn_get_row   (GimpPixelRgn *pr,
                               guchar       *buf,
                               gint          x,
                               gint          y,
                               gint          width);
void gimp_pixel_rgn_get_col   (GimpPixelRgn *pr,
                               guchar       *buf,
                               gint          x,
                               gint          y,
                               gint          height);
void gimp_pixel_rgn_get_rect  (GimpPixelRgn *pr,
                               guchar       *buf,
                               gint          x,
                               gint          y,
                               gint          width,
                               gint          height);
void gimp_pixel_rgn_set_pixel (GimpPixelRgn *pr,
                               const guchar *buf,
                               gint          x,
                               gint          y);
void gimp_pixel_rgn_set_row   (GimpPixelRgn *pr,
                               const guchar *buf,
                               gint          x,
                               gint          y,
                               gint          width);
void gimp_pixel_rgn_set_col   (GimpPixelRgn *pr,
                               const guchar *buf,
                               gint          x,
                               gint          y,
                               gint          height);
void gimp_pixel_rgn_set_rect  (GimpPixelRgn *pr,
                               const guchar *buf,
                               gint          x,
                               gint          y,
                               gint          width,
                               gint          height);

ここでは、tileレベルでデータを管理できる画像データにアクセスする方法もあります.後で詳細に説明します.
データの更新
プラグインは、画像データを更新した後、カーネルにデータをコミットし、表示を更新すべきだと伝えなければなりません.これは、次の2つの関数によって実現されます.
gimp_displays_flush ();
gimp_drawable_detach (drawable);

実装blur()関数
異なる方法を試みるためにblur関数を用い,run関数実装を以下に示す.
static void
run (const gchar      *name,
     gint              nparams,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
{
  static GimpParam  values[1];
  GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  GimpRunMode       run_mode;
  GimpDrawable     *drawable;
 
  /* Setting mandatory output values */
  *nreturn_vals = 1;
  *return_vals  = values;
 
  values[0].type = GIMP_PDB_STATUS;
  values[0].data.d_status = status;
 
  /* Getting run_mode - we won't display a dialog if
   * we are in NONINTERACTIVE mode */
  run_mode = param[0].data.d_int32;
 
  /*  Get the specified drawable  */
  drawable = gimp_drawable_get (param[2].data.d_drawable);
 
  gimp_progress_init ("My Blur...");
 
  /* Let's time blur
   *
   *   GTimer timer = g_timer_new time ();
   */
 
  blur (drawable);
 
  /*   g_print ("blur() took %g seconds.
", g_timer_elapsed (timer)); * g_timer_destroy (timer);
*/ gimp_displays_flush (); gimp_drawable_detach (drawable); }

ここではいくつかの行を説明する必要がありますgimp_progress_Init()関数の役割は、プラグインの進捗バー(パラメータは進捗バーに表示される文字列)を初期化することです.後でblurでgimp_が呼び出されますprogress_update()関数で、パラメータのパーセントに基づいて進捗バーを印刷します.実行モード(run_mode)は、プラグインがグラフィックインタフェースで開始されるかどうかを決定します.GIMP_RUN_INTERACTIVE, GIMP_RUN_NONINTERACTIVEまたはGIMP_RUN_WITH_LAST_VALSの値の1つです.これらは、インタラクティブ実行、スクリプト実行、最後のフィルタの繰り返しです.
ファジイアルゴリズム自体については、次のバージョンでgimp_を使用しています.pixel_rgn_(get|set)_pixel()関数は、まだ説明されていません.
gimp_drawable_mask_bounds()は、フィルタの影響を計算するための範囲であり、非アクティブ領域を含まないため、このように処理を制限することで性能を向上させることができる.
gimp_pixel_rgn_Init()は、指定されたパラメータに従って画素領域を初期化し、2つのbool変数にはGimpPixelRgnの動作が格納され、dirty変数とshadow変数がFALSEであれば、このGimpPixelRgnは読み取り用であり、いずれもTRUEであれば、このGimpPixelRgnは書き込み用であり、他の組合せはあまり使用されない.
static void
blur (GimpDrawable *drawable)
{
  gint         i, j, k, channels;
  gint         x1, y1, x2, y2;
  GimpPixelRgn rgn_in, rgn_out;
  guchar       output[4];
 
  /* Gets upper left and lower right coordinates,
   * and layers number in the image */
  gimp_drawable_mask_bounds (drawable->drawable_id,
                             &x1, &y1,
                             &x2, &y2);
  channels = gimp_drawable_bpp (drawable->drawable_id);
 
  /* Initialises two PixelRgns, one to read original data,
   * and the other to write output data. That second one will
   * be merged at the end by the call to
   * gimp_drawable_merge_shadow() */
  gimp_pixel_rgn_init (&rgn_in,
                       drawable,
                       x1, y1,
                       x2 - x1, y2 - y1,
                       FALSE, FALSE);
  gimp_pixel_rgn_init (&rgn_out,
                       drawable,
                       x1, y1,
                       x2 - x1, y2 - y1,
                       TRUE, TRUE);
 
  for (i = x1; i < x2; i++)
    {
      for (j = y1; j < y2; j++)
        {
          guchar pixel[9][4];
 
          /* Get nine pixels */
          gimp_pixel_rgn_get_pixel (&rgn_in,
                                    pixel[0],
                                    MAX (i - 1, x1),
                                    MAX (j - 1, y1));
          gimp_pixel_rgn_get_pixel (&rgn_in,
                                    pixel[1],
                                    MAX (i - 1, x1),
                                    j);
          gimp_pixel_rgn_get_pixel (&rgn_in,
                                    pixel[2],
                                    MAX (i - 1, x1),
                                    MIN (j + 1, y2 - 1));
 
          gimp_pixel_rgn_get_pixel (&rgn_in,
                                    pixel[3],
                                    i,
                                    MAX (j - 1, y1));
          gimp_pixel_rgn_get_pixel (&rgn_in,
                                    pixel[4],
                                    i,
                                    j);
          gimp_pixel_rgn_get_pixel (&rgn_in,
                                    pixel[5],
                                    i,
                                    MIN (j + 1, y2 - 1));
 
          gimp_pixel_rgn_get_pixel (&rgn_in,
                                    pixel[6],
                                    MIN (i + 1, x2 - 1),
                                    MAX (j - 1, y1));
          gimp_pixel_rgn_get_pixel (&rgn_in,
                                    pixel[7],
                                    MIN (i + 1, x2 - 1),
                                    j);
          gimp_pixel_rgn_get_pixel (&rgn_in,
                                    pixel[8],
                                    MIN (i + 1, x2 - 1),
                                    MIN (j + 1, y2 - 1));
 
          /* For each layer, compute the average of the
           * nine */
          for (k = 0; k < channels; k++)
            {
              int tmp, sum = 0;
              for (tmp = 0; tmp < 9; tmp++)
                sum += pixel[tmp][k];
              output[k] = sum / 9;
            }
 
          gimp_pixel_rgn_set_pixel (&rgn_out,
                                    output,
                                    i, j);
        }
 
      if (i % 10 == 0)
        gimp_progress_update ((gdouble) (i - x1) / (gdouble) (x2 - x1));
    }
 
  /*  Update the modified region */
  gimp_drawable_flush (drawable);
  gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
  gimp_drawable_update (drawable->drawable_id,
                        x1, y1,
                        x2 - x1, y2 - y1);
}

明細による処理
我々の関数には致命的な欠点があります:性能、300×300の選挙区は、私のK 6-2 350 MHzで処理するのに12分かかり、同じ選挙区では、ガウスブラーを使うのに3秒しかかかりません.
gimp_を使用するとpixel_rgn_(get|set)_row()関数処理では、速度がずっと速くなり、blur()v 2バージョンを使用して、処理300×300の選択範囲の所要時間は760秒から6秒に減少します.
static void
blur (GimpDrawable *drawable)
{
  gint         i, j, k, channels;
  gint         x1, y1, x2, y2;
  GimpPixelRgn rgn_in, rgn_out;
  guchar      *row1, *row2, *row3;
  guchar      *outrow;
 
  gimp_drawable_mask_bounds (drawable->drawable_id,
                             &x1, &y1,
                             &x2, &y2);
  channels = gimp_drawable_bpp (drawable->drawable_id);
 
  gimp_pixel_rgn_init (&rgn_in,
                       drawable,
                       x1, y1,
                       x2 - x1, y2 - y1,
                       FALSE, FALSE);
  gimp_pixel_rgn_init (&rgn_out,
                       drawable,
                       x1, y1,
                       x2 - x1, y2 - y1,
                       TRUE, TRUE);
 
  /* Initialise enough memory for row1, row2, row3, outrow */
  row1 = g_new (guchar, channels * (x2 - x1));
  row2 = g_new (guchar, channels * (x2 - x1));
  row3 = g_new (guchar, channels * (x2 - x1));
  outrow = g_new (guchar, channels * (x2 - x1));
 
  for (i = y1; i < y2; i++)
    {
      /* Get row i-1, i, i+1 */
      gimp_pixel_rgn_get_row (&rgn_in,
                              row1,
                              x1, MAX (y1, i - 1),
                              x2 - x1);
      gimp_pixel_rgn_get_row (&rgn_in,
                              row2,
                              x1, i,
                              x2 - x1);
      gimp_pixel_rgn_get_row (&rgn_in,
                              row3,
                              x1, MIN (y2 - 1, i + 1),
                              x2 - x1);
 
      for (j = x1; j < x2; j++)
        {
          /* For each layer, compute the average of the nine
           * pixels */
          for (k = 0; k < channels; k++)
            {
              int sum = 0;
              sum = row1[channels * MAX ((j - 1 - x1), 0) + k]           +
                    row1[channels * (j - x1) + k]                        +
                    row1[channels * MIN ((j + 1 - x1), x2 - x1 - 1) + k] +
                    row2[channels * MAX ((j - 1 - x1), 0) + k]           +
                    row2[channels * (j - x1) + k]                        +
                    row2[channels * MIN ((j + 1 - x1), x2 - x1 - 1) + k] +
                    row3[channels * MAX ((j - 1 - x1), 0) + k]           +
                    row3[channels * (j - x1) + k]                        +
                    row3[channels * MIN ((j + 1 - x1), x2 - x1 - 1) + k];
              outrow[channels * (j - x1) + k] = sum / 9;
            }
 
       }
 
       gimp_pixel_rgn_set_row (&rgn_out,
                               outrow,
                               x1, i,
                               x2 - x1);
 
       if (i % 10 == 0)
            gimp_progress_update ((gdouble) (i - y1) / (gdouble) (y2 - y1));
  }
 
  g_free (row1);
  g_free (row2);
  g_free (row3);
  g_free (outrow);
 
  gimp_drawable_flush (drawable);
  gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
  gimp_drawable_update (drawable->drawable_id,
                        x1, y1,
                        x2 - x1, y2 - y1);
}

完全なblur1.cblur2.cを見てみましょう
第3部
私たちが提供したパラメータに基づいて処理できるように、プラグインを改造します.