Criando plug-in em c para gimp
Tags: gimp, c, automatizacão, plugin
Published: 2023-05-01 19:20:07

Bem, hoje vamos criar um plug-in em c para automatizar algumas tarefas repetitivas e chatas.

Antes de começar fazer o código, é necessário instalar o `gimptool`.

Então, vamos instalar ele.

## Instalando o gimptool

Antes de continuarmos, tenho que esclarecer que eu vou fazer isso em Linux, pois eu não uso o Window, então se você não sabe onde achar o `gimptool` para Window.

Mas não se preocupe, eu vou te ajudar onde pode estar esse `gimptool` no Window, de acordo com [strontic](strontic.github.io), Ele diz que o arquivo pode está localizado no `C:\program files\GIMP 2\bin\gimptool-2.0.exe`.

Então, se você conseguiu localizar o arquivo, com isso, você já pode partir para a criação de plug-in.

Agora vamos instalar o Gimptool no Linux, no caso Ubuntu/Debian.

Basta ir ao terminal executar o comando: `sudo apt install libgimp2.0-dev`.

Pronto, é só isso, agora vamos criar um plug-in.

## Criando um plug-in

Beleza, antes de criar o plug-in, eu vou explicar o eu vou fazer.

Para não dificultar o processo de aprendizado, eu vou fazer um plug-in bem simples, mas bem simples mesmo.

É basicamente colocar uma guide(guia).

Se você não sabe o que é guide. Abra o gimp e vá ao menu "Image" Ou "Imagem", se estiver português, e verá ele aí.

Passando o mouse em cima, você verá 4 opções.

Aqui está uma captura de tela.

![Localização do guide](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b2zda2svgbugrhh7hgem.png)

Clicando na primeira opção, vai aparecer uma tela para escolher a direção e inserir um valor da posição da guia.

Então, colocando na direção vertical e posição 50%, vai aparecer uma linha azul no meio da imagem, por exemplo, nessa captura de tela.

![A linha azul de guia](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/18oghu9jxwdqcaob10v4.png)

Eu quero automatizar isso, pois é chato fica abrindo a telinha e inserindo os valores.

Então, primeiro, vamos criar um arquivo chamado `add_guias.c`.

Eu vou colocar o código inteiro logo de vez para fazer um teste, e então, depois vou explicando ao pouco.

```c
#include <libgimp/gimp.h>

static void query (void);
static void run (
	const gchar *name,
	gint nparams,
	const GimpParam *param,
	gint *nreturn_vals,
	GimpParam **return_vals);

GimpPlugInInfo PLUG_IN_INFO = {
	NULL, // init
	NULL, // quit
	query,
	run
};

static void query (void) {

  static GimpParamDef args[] = {
    {
      GIMP_PDB_INT32, // Tipo de variável
      "run-mode", // Nome da variável
      "Run mode" // Descrição da variável
    },
    {
      GIMP_PDB_IMAGE, // Tipo de variável
      "image", // Nome da variável
      "Input image" // Descrição da variável
    },
    {
      GIMP_PDB_DRAWABLE, // Tipo de variável
      "drawable", // Nome da variável
      "Input drawable" // Descrição da variável
    }
  };

  gimp_install_procedure (
    "plug-in-add_guias", // Nome do procedure
    "Adiciona guia", // Uma pequena descrição do que o procedure faz
    "Ele adiciona uma guia no meio da imagem", // Uma descrição completa
    "Alexandre dos Santos Alves", // Seu nome
    "Copyright Alexandre", // Licença
    "2023", // Ano que foi criado
    "_Adicona Guia", // Nome que vai aparece no menu
    "RGB*, GRAY*", // Tipo de imagem que o procedure vai trabalhar
    GIMP_PLUGIN, // Tipo de procedure
    G_N_ELEMENTS (args), // Tamanho do parâmetro
    0, // Tamanho do retorno
    args, // o parâmetro do procedure
    NULL); // o retorno do procedure.

  gimp_plugin_menu_register ("plug-in-add_guias",
                               "<Image>/Tools/");
}

static void run (
	const gchar      *name,
	gint              nparams,
	const GimpParam  *param,
	gint             *nreturn_vals,
	GimpParam       **return_vals)
	{

	// A variável que vai ser retornado
	static GimpParam  values[1];
	GimpPDBStatusType status = GIMP_PDB_SUCCESS; 
	GimpRunMode       run_mode;
	GimpDrawable     *drawable;

	/* Definindo valores de saída obrigatórios	*/
	*nreturn_vals = 1;
	*return_vals  = values;

	/* É obrigatório isso */
	values[0].type = GIMP_PDB_STATUS;
	values[0].data.d_status = status;

	run_mode = param[0].data.d_int32;
	gint image = param[1].data.d_image;
	drawable = gimp_drawable_get(param[2].data.d_drawable);

	gdouble metade_do_tamanho_da_image = (gimp_image_width(image) * 0.5);

	gimp_image_add_vguide(image, metade_do_tamanho_da_image);

	gimp_displays_flush ();
}

MAIN()
```

Com esse código, copie e cole no arquivo e execute o comando no qual o arquivo está localizado.

Se for Window, `C:\program files\GIMP 2\bin\gimptool-2.0.exe --install add_guias.c`.
Se for Linux, `gimptool-2.0 --install add_guias.c`.

Se por acaso, aparecer isso aqui embaixo, pode ignorar.

```bash
add_guias.c:92:2: warning: ‘gimp_drawable_get’ is deprecated: Use 'gimp_drawable_get_buffer' instead [-Wdeprecated-declarations]
   92 |  drawable = gimp_drawable_get(param[2].data.d_drawable);
      |  ^~~~~~~~
In file included from /usr/include/gimp-2.0/libgimp/gimp.h:41,
                 from add_guias.c:1:
/usr/include/gimp-2.0/libgimp/gimpdrawable.h:52:16: note: declared here
   52 | GimpDrawable * gimp_drawable_get                    (gint32         drawable_ID);
      |                ^~~~~~~~~~~~~~~~~
```


Se não houver erro, além desse aviso, agora, ele vai aparece no Gimp, então feche o Gimp e abra novamente e você verá no menu Tools(Ferramentas) um item com nome Adiciona Guia.

Crie uma nova imagem e clique nele para ver o que acontece.

Bem, Se apareceu a linha azul, então ele funcionou, se não, aí é com você para resolver.

Mentira, comente no comentário, o problema.

Mas, agora, vamos entender o código.

Na primeira linha, estamos incluindo uma biblioteca essencial para construção do plug-in, então não tem muito o que explicar sobre isso.

Em baixo disso, podemos ver duas funções, `query` e `run`.

```c
...

static void query (void);
static void run (
	const gchar *name,
	gint nparams,
	const GimpParam *param,
	gint *nreturn_vals,
	GimpParam **return_vals);

GimpPlugInInfo PLUG_IN_INFO = {
	NULL, // init
	NULL, // quit
	query,
	run
};

...
```

Mas antes de explicar essas funções, vamos pular essa parte e ver a variável `PLUG_IN_INFO`.

Essa variável pode guardar 4 valores.

Mas o que são esses valores?

São funções que o Gimp vai chamar.

Ou seja, o primeiro valor é uma função que vai ser chamado durante a inicialização do Gimp, no meu caso, eu coloquei `NULL`, pois não quero fazer nada durante a inicialização.

O segundo é `quit`, que vai ser chamado durante  o fechamento do Gimp, que no meu caso, está `NULL`.

Esses dois valores que citei, são opcionais, ou seja, não é necessário ter uma função, basta colocar `NULL`.

Agora os dois próximos que vou citar são obrigatórios.

O terceiro é `query`, não sei muito o que explicar sobre isso, pois a documentação não diz muito sobre isso, mas no meu entendimento, suponho que é usado para instalar o plug-in, mas vamos tenta entender mais, quando estivemos na dentro função `query()`.

O quarto e último é `run`, é peça central do código, pois ele vai ser rodado, quando for chamado, seja pelo menu, ou pelo script fu, ou Python fu.

Agora, sabendo disso, vamos partir para aquelas duas funções criada para entender os parâmetros.

```c
static void query (void);
static void run (
	const gchar *name, // Nome do plug-in
	gint nparams, // Quantidade de parâmetro
	const GimpParam *param, // O parâmetro do plug-in
	gint *nreturn_vals, // Quantidade de retorno
	GimpParam **return_vals); // O retorno do plug-in
```

Não tem muito que o explicar sobre o parâmetro do `query`, então vamos para `run`.

O primeiro parâmetro é o nome do plug-in.
O segundo é a quantidade de parâmetro.
O terceiro é o parâmetro do plug-in.
O quarto é a quantidade de retorno.
O quinto é o retorno do plug-in.

Beleza, sabendo quais são os parâmetros.

Agora, vamos entender ver o que dentro da função `query(void)`.

```c
static void query (void) {

  static GimpParamDef args[] = {
    {
      GIMP_PDB_INT32, // Tipo de variável
      "run-mode", // Nome da variável
      "Run mode" // Descrição da variável
    },
    {
      GIMP_PDB_IMAGE, // Tipo de variável
      "image", // Nome da variável
      "Input image" // Descrição da variável
    },
    {
      GIMP_PDB_DRAWABLE, // Tipo de variável
      "drawable", // Nome da variável
      "Input drawable" // Descrição da variável
    }
  };

  gimp_install_procedure (
    "plug-in-add_guias", // Nome do procedure
    "Adiciona guia", // Uma pequena descrição do que o procedure faz
    "Ele adiciona uma guia no meio da imagem", // Uma descrição completa
    "Alexandre dos Santos Alves", // Seu nome
    "Copyright Alexandre", // Licença
    "2023", // Ano que foi criado
    "_Adicona Guia", // Nome que vai aparece no menu
    "RGB*, GRAY*", // Tipo de imagem que o procedure vai trabalhar
    GIMP_PLUGIN, // Tipo de procedure
    G_N_ELEMENTS (args), // Tamanho do parâmetro
    0, // Tamanho do retorno
    args, // o parâmetro do procedure
    NULL); // o retorno do procedure.

  gimp_plugin_menu_register ("plug-in-add_guias", // nome do plug-in
                               "<Image>/Tools/"); // Localização dele no menu
}
```

Primeiro, declaramos uma variável `static GimpParamDef args[]`, ela possibilita saber quais são os valores do parâmetro que o plug-in recebe.

No nosso caso, vamos apenas manter o padrão, que são `run-mode`, `image` e `drawable`.

Mas se por acaso, seu plug-in precisa de mais valores, eu vou colocar uma lista de cada tipo de variável para facilitar para você.

| Tipo de variável | Descrição |
| ---              | --- |
| GIMP_PDB_INT32       | 32-bit integer |
| GIMP_PDB_INT16       | 16-bit integer |
| GIMP_PDB_INT8        | 8-bit integer  |
| GIMP_PDB_FLOAT       | Float          |
| GIMP_PDB_STRING      | String          |
| GIMP_PDB_INT32ARRAY  | Array of INT32  |
| GIMP_PDB_INT16ARRAY  | Array of INT16  |
| GIMP_PDB_INT8ARRAY   | Array of INT8   |
| GIMP_PDB_FLOATARRAY  | Array of floats |
| GIMP_PDB_STRINGARRAY | Array of strings |
| GIMP_PDB_COLOR       | Color |
| GIMP_PDB_ITEM        | Item ID |
| GIMP_PDB_DISPLAY     | Display ID |
| GIMP_PDB_IMAGE       | Image ID |
| GIMP_PDB_LAYER       | Layer ID |
| GIMP_PDB_CHANNEL     | Channel ID |
| GIMP_PDB_DRAWABLE    | Drawable ID |
| GIMP_PDB_SELECTION   | Selection ID |
| GIMP_PDB_COLORARRAY  | Array of colors |
| GIMP_PDB_VECTORS     | Vectors (psath) ID |
| GIMP_PDB_PARASITE    | Parasite |
| GIMP_PDB_STATUS      | Procedure return status |
| GIMP_PDB_END         | Marker for last enum value |

Beleza, Já entendemos sobre o `args[]`, agora vamos para função que estamos chamando `gimp_install_procedure`.

Não tem muito o que explicar, pois se você ler o comentário ao lado do parâmetro, já dá pra ter uma noção, mas o que ele basicamente faz é instalar o plug-in no gimp.

Então, vamos para outra função que é `gimp_plugin_menu_register`. Como o nome diz, ele vai registrar o plug-in no Menu, que no nosso caso, vai ser colocado no `Tools`.

Aqui nós terminamos a função `query()`.

Vamos para função `run()`, por ser um código um pouco grande, eu vou colocar a explicação dentro do código.

```c
...

static void run (
	const gchar      *name,
	gint              nparams,
	const GimpParam  *param,
	gint             *nreturn_vals,
	GimpParam       **return_vals)
	{

	// A variável que vai ser retornado
	static GimpParam  values[1];

	// Como o nome diz é o status
	GimpPDBStatusType status = GIMP_PDB_SUCCESS; 

	// O run_mode é usado para saber se estar no modo interativo ou não
	// Não irei explicar isso nesse blog
	GimpRunMode       run_mode;

	// Variável que, por padrão, é o layer(camada) atual.
	GimpDrawable     *drawable;

	/* Definindo valores de saída obrigatórios	*/
	*nreturn_vals = 1; // definindo o tamanho da variável values
	*return_vals  = values;

	/* É obrigatório isso */
	values[0].type = GIMP_PDB_STATUS;
	values[0].data.d_status = status;

	// Aqui temos uma forma de pegar os valores passados no parâmetro
	// Eu vou colocar lista de tipos de variáveis abaixo fora do código
	// Sobre o índices da variável 'param', ele está na mesma ordem
	// que você declarou na função 'query' da variável 'args'
	run_mode = param[0].data.d_int32;
	gint image = param[1].data.d_image;
	drawable = gimp_drawable_get(param[2].data.d_drawable);

	// Agora, a partir daqui, são os códigos que você pode fazer
	// Aqui estamos pegando a metade do tamanho da imagem
	// Para poder colocar a guia no meio
	gdouble metade_do_tamanho_da_image = (gimp_image_width(image) * 0.5);

	// essa função coloca a guia, primeiro parâmetro é a imagem
	// o segundo é a posição dessa guia
	gimp_image_add_vguide(image, metade_do_tamanho_da_image);

	// Essa função serve para atualizar o que você fez no código,
	// mas não é necessário para o nosso caso,
        // Não estamos alterando a imagem
	gimp_displays_flush ();
}

...
```

| Tipos de variáveis | membro |
----- | ------
| gint32            | d_int32 |
| gint16            | d_int16 |
| guint8            | d_int8 |
| gdouble           | d_float |
| gchar             | d_string |
| gint32            | d_int32array |
| gint16            | d_int16array |
| guint8            | d_int8array |
| gdouble           | d_floatarray |
| gchar             | d_stringarray |
| GimpRGB           | d_colorarray |
| GimpRGB           | d_color |
| gint32            | d_display |
| gint32            | d_image |
| gint32            | d_item |
| gint32            | d_layer |
| gint32            | d_layer_mask |
| gint32            | d_channel |
| gint32            | d_drawable |
| gint32            | d_selection |
| gint32            | d_boundary |
| gint32            | d_vectors |
| gint32            | d_unit |
| GimpParasite      | d_parasite |
| gint32            | d_tattoo |
| GimpPDBStatusType | d_status |

Se você não entendeu essa lista ou não sabe usá-la, basta fazer assim `param[i].data.membro`, troque o membro para um item da lista.

E por último, temos que colocar o `MAIN()`, é obrigatório que tenha isso, e que fique no final do arquivo.

Pronto, com isso, você tem a base para construir um plug-in por si próprio, só que não, pois você ainda não sabe quais são os métodos disponíveis no Gimp.

Aqui está a documentação do [Gimp](https://developer.gimp.org/api/3.0/libgimp/index.html).

Agora, sim, podemos terminar aqui.

Bem, então é isso e tchau!