1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18 /*
19 * gbr plug-in version 1.00
20 * Loads/exports version 2 GIMP .gbr files, by Tim Newsome <drz@frody.bloke.com>
21 * Some bits stolen from the .99.7 source tree.
22 *
23 * Added in GBR version 1 support after learning that there wasn't a
24 * tool to read them.
25 * July 6, 1998 by Seth Burgess <sjburges@gimp.org>
26 *
27 * Dec 17, 2000
28 * Load and save GIMP brushes in GRAY or RGBA. jtl + neo
29 *
30 *
31 * TODO: Give some better error reporting on not opening files/bad headers
32 * etc.
33 */
34
35 #include "config.h"
36
37 #include <libgimp/gimp.h>
38 #include <libgimp/gimpui.h>
39
40 #include "libgimp/stdplugins-intl.h"
41
42
43 #define SAVE_PROC "file-gbr-save"
44 #define PLUG_IN_BINARY "file-gbr"
45 #define PLUG_IN_ROLE "gimp-file-gbr"
46
47
48 typedef struct
49 {
50 gchar description[256];
51 gint spacing;
52 } BrushInfo;
53
54
55 /* local function prototypes */
56
57 static void query (void);
58 static void run (const gchar *name,
59 gint nparams,
60 const GimpParam *param,
61 gint *nreturn_vals,
62 GimpParam **return_vals);
63
64 static gboolean save_dialog (void);
65 static void entry_callback (GtkWidget *widget,
66 gpointer data);
67
68
69 const GimpPlugInInfo PLUG_IN_INFO =
70 {
71 NULL, /* init_proc */
72 NULL, /* quit_proc */
73 query, /* query_proc */
74 run, /* run_proc */
75 };
76
77
78 /* private variables */
79
80 static BrushInfo info =
81 {
82 "GIMP Brush",
83 10
84 };
85
86
MAIN()87 MAIN ()
88
89 static void
90 query (void)
91 {
92 static const GimpParamDef save_args[] =
93 {
94 { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
95 { GIMP_PDB_IMAGE, "image", "Input image" },
96 { GIMP_PDB_DRAWABLE, "drawable", "Drawable to export" },
97 { GIMP_PDB_STRING, "uri", "The URI of the file to export the image in" },
98 { GIMP_PDB_STRING, "raw-uri", "The URI of the file to export the image in" },
99 { GIMP_PDB_INT32, "spacing", "Spacing of the brush" },
100 { GIMP_PDB_STRING, "description", "Short description of the brush" }
101 };
102
103 gimp_install_procedure (SAVE_PROC,
104 "Exports files in the GIMP brush file format",
105 "Exports files in the GIMP brush file format",
106 "Tim Newsome, Jens Lautenbacher, Sven Neumann",
107 "Tim Newsome, Jens Lautenbacher, Sven Neumann",
108 "1997-2000",
109 N_("GIMP brush"),
110 "RGB*, GRAY*, INDEXED*",
111 GIMP_PLUGIN,
112 G_N_ELEMENTS (save_args), 0,
113 save_args, NULL);
114
115 gimp_plugin_icon_register (SAVE_PROC, GIMP_ICON_TYPE_ICON_NAME,
116 (const guint8 *) GIMP_ICON_BRUSH);
117 gimp_register_file_handler_mime (SAVE_PROC, "image/x-gimp-gbr");
118 gimp_register_file_handler_uri (SAVE_PROC);
119 gimp_register_save_handler (SAVE_PROC, "gbr", "");
120 }
121
122 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)123 run (const gchar *name,
124 gint nparams,
125 const GimpParam *param,
126 gint *nreturn_vals,
127 GimpParam **return_vals)
128 {
129 static GimpParam values[2];
130 GimpRunMode run_mode;
131 GimpPDBStatusType status = GIMP_PDB_SUCCESS;
132 gint32 image_ID;
133 gint32 drawable_ID;
134 GimpExportReturn export = GIMP_EXPORT_CANCEL;
135 GError *error = NULL;
136
137 INIT_I18N ();
138
139 run_mode = param[0].data.d_int32;
140
141 *nreturn_vals = 1;
142 *return_vals = values;
143
144 values[0].type = GIMP_PDB_STATUS;
145 values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
146
147 if (strcmp (name, SAVE_PROC) == 0)
148 {
149 GFile *file;
150 GimpParasite *parasite;
151 gint32 orig_image_ID;
152
153 image_ID = param[1].data.d_int32;
154 drawable_ID = param[2].data.d_int32;
155 file = g_file_new_for_uri (param[3].data.d_string);
156
157 orig_image_ID = image_ID;
158
159 switch (run_mode)
160 {
161 case GIMP_RUN_INTERACTIVE:
162 case GIMP_RUN_WITH_LAST_VALS:
163 gimp_ui_init (PLUG_IN_BINARY, FALSE);
164
165 export = gimp_export_image (&image_ID, &drawable_ID, "GBR",
166 GIMP_EXPORT_CAN_HANDLE_GRAY |
167 GIMP_EXPORT_CAN_HANDLE_RGB |
168 GIMP_EXPORT_CAN_HANDLE_INDEXED |
169 GIMP_EXPORT_CAN_HANDLE_ALPHA);
170
171 if (export == GIMP_EXPORT_CANCEL)
172 {
173 values[0].data.d_status = GIMP_PDB_CANCEL;
174 return;
175 }
176
177 /* Possibly retrieve data */
178 gimp_get_data (SAVE_PROC, &info);
179
180 parasite = gimp_image_get_parasite (orig_image_ID,
181 "gimp-brush-name");
182 if (parasite)
183 {
184 strncpy (info.description,
185 gimp_parasite_data (parasite),
186 MIN (sizeof (info.description),
187 gimp_parasite_data_size (parasite)));
188 info.description[sizeof (info.description) - 1] = '\0';
189
190 gimp_parasite_free (parasite);
191 }
192 else
193 {
194 gchar *name = g_path_get_basename (gimp_file_get_utf8_name (file));
195
196 if (g_str_has_suffix (name, ".gbr"))
197 name[strlen (name) - 4] = '\0';
198
199 if (strlen (name))
200 {
201 strncpy (info.description, name, sizeof (info.description));
202 info.description[sizeof (info.description) - 1] = '\0';
203 }
204
205 g_free (name);
206 }
207 break;
208
209 default:
210 break;
211 }
212
213 switch (run_mode)
214 {
215 case GIMP_RUN_INTERACTIVE:
216 if (! save_dialog ())
217 status = GIMP_PDB_CANCEL;
218 break;
219
220 case GIMP_RUN_NONINTERACTIVE:
221 if (nparams != 7)
222 {
223 status = GIMP_PDB_CALLING_ERROR;
224 }
225 else
226 {
227 info.spacing = (param[5].data.d_int32);
228 strncpy (info.description, param[6].data.d_string,
229 sizeof (info.description));
230 info.description[sizeof (info.description) - 1] = '\0';
231 }
232 break;
233
234 default:
235 break;
236 }
237
238 if (status == GIMP_PDB_SUCCESS)
239 {
240 GimpParam *save_retvals;
241 gint n_save_retvals;
242
243 save_retvals =
244 gimp_run_procedure ("file-gbr-save-internal",
245 &n_save_retvals,
246 GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
247 GIMP_PDB_IMAGE, image_ID,
248 GIMP_PDB_DRAWABLE, drawable_ID,
249 GIMP_PDB_STRING, param[3].data.d_string,
250 GIMP_PDB_STRING, param[4].data.d_string,
251 GIMP_PDB_INT32, info.spacing,
252 GIMP_PDB_STRING, info.description,
253 GIMP_PDB_END);
254
255 if (save_retvals[0].data.d_status == GIMP_PDB_SUCCESS)
256 {
257 gimp_set_data (SAVE_PROC, &info, sizeof (info));
258 }
259 else
260 {
261 g_set_error (&error, 0, 0,
262 "Running procedure 'file-gbr-save-internal' "
263 "failed: %s",
264 gimp_get_pdb_error ());
265
266 status = GIMP_PDB_EXECUTION_ERROR;
267 }
268
269 gimp_destroy_params (save_retvals, n_save_retvals);
270 }
271
272 if (export == GIMP_EXPORT_EXPORT)
273 gimp_image_delete (image_ID);
274
275 if (strlen (info.description))
276 {
277 GimpParasite *parasite;
278
279 parasite = gimp_parasite_new ("gimp-brush-name",
280 GIMP_PARASITE_PERSISTENT,
281 strlen (info.description) + 1,
282 info.description);
283 gimp_image_attach_parasite (orig_image_ID, parasite);
284 gimp_parasite_free (parasite);
285 }
286 else
287 {
288 gimp_image_detach_parasite (orig_image_ID, "gimp-brush-name");
289 }
290 }
291 else
292 {
293 status = GIMP_PDB_CALLING_ERROR;
294 }
295
296 if (status != GIMP_PDB_SUCCESS && error)
297 {
298 *nreturn_vals = 2;
299 values[1].type = GIMP_PDB_STRING;
300 values[1].data.d_string = error->message;
301 }
302
303 values[0].data.d_status = status;
304 }
305
306 static gboolean
save_dialog(void)307 save_dialog (void)
308 {
309 GtkWidget *dialog;
310 GtkWidget *table;
311 GtkWidget *entry;
312 GtkWidget *spinbutton;
313 GtkAdjustment *adj;
314 gboolean run;
315
316 dialog = gimp_export_dialog_new (_("Brush"), PLUG_IN_BINARY, SAVE_PROC);
317
318 /* The main table */
319 table = gtk_table_new (2, 2, FALSE);
320 gtk_container_set_border_width (GTK_CONTAINER (table), 12);
321 gtk_table_set_row_spacings (GTK_TABLE (table), 6);
322 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
323 gtk_box_pack_start (GTK_BOX (gimp_export_dialog_get_content_area (dialog)),
324 table, TRUE, TRUE, 0);
325 gtk_widget_show (table);
326
327 entry = gtk_entry_new ();
328 gtk_entry_set_width_chars (GTK_ENTRY (entry), 20);
329 gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
330 gtk_entry_set_text (GTK_ENTRY (entry), info.description);
331 gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
332 _("_Description:"), 1.0, 0.5,
333 entry, 1, FALSE);
334
335 g_signal_connect (entry, "changed",
336 G_CALLBACK (entry_callback),
337 info.description);
338
339 adj = (GtkAdjustment *) gtk_adjustment_new (info.spacing, 1, 1000, 1, 10, 0);
340 spinbutton = gimp_spin_button_new (adj, 1.0, 0);
341 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
342 gtk_entry_set_activates_default (GTK_ENTRY (spinbutton), TRUE);
343 gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
344 _("_Spacing:"), 1.0, 0.5,
345 spinbutton, 1, TRUE);
346
347 g_signal_connect (adj, "value-changed",
348 G_CALLBACK (gimp_int_adjustment_update),
349 &info.spacing);
350
351 gtk_widget_show (dialog);
352
353 run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
354
355 gtk_widget_destroy (dialog);
356
357 return run;
358 }
359
360 static void
entry_callback(GtkWidget * widget,gpointer data)361 entry_callback (GtkWidget *widget,
362 gpointer data)
363 {
364 strncpy (info.description, gtk_entry_get_text (GTK_ENTRY (widget)),
365 sizeof (info.description));
366 info.description[sizeof (info.description) - 1] = '\0';
367 }
368