1 /* CSource - GIMP Plugin to dump image data in RGB(A) format for C source
2 * Copyright (C) 1999 Tim Janik
3 *
4 * This program is free software: you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 3
7 * of the License, or (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 * This plugin is heavily based on the header plugin by Spencer Kimball and
18 * Peter Mattis.
19 */
20
21 #include "config.h"
22
23 #include <string.h>
24 #include <errno.h>
25
26 #include <glib/gstdio.h>
27
28 #include <libgimp/gimp.h>
29 #include <libgimp/gimpui.h>
30
31 #include "libgimp/stdplugins-intl.h"
32
33
34 #define SAVE_PROC "file-csource-save"
35 #define PLUG_IN_BINARY "file-csource"
36 #define PLUG_IN_ROLE "gimp-file-csource"
37
38
39 typedef struct
40 {
41 gchar *prefixed_name;
42 gchar *comment;
43 gboolean use_comment;
44 gboolean glib_types;
45 gboolean alpha;
46 gboolean rgb565;
47 gboolean use_macros;
48 gboolean use_rle;
49 gdouble opacity;
50 } Config;
51
52
53 static void query (void);
54 static void run (const gchar *name,
55 gint nparams,
56 const GimpParam *param,
57 gint *nreturn_vals,
58 GimpParam **return_vals);
59
60 static gboolean save_image (GFile *file,
61 Config *config,
62 gint32 image_ID,
63 gint32 drawable_ID,
64 GError **error);
65 static gboolean run_save_dialog (Config *config);
66
67
68 const GimpPlugInInfo PLUG_IN_INFO =
69 {
70 NULL, /* init_proc */
71 NULL, /* quit_proc */
72 query, /* query_proc */
73 run, /* run_proc */
74 };
75
76 static Config config =
77 {
78 "gimp_image", /* prefixed_name */
79 NULL, /* comment */
80 FALSE, /* use_comment */
81 TRUE, /* glib_types */
82 FALSE, /* alpha */
83 FALSE, /* rgb565 */
84 FALSE, /* use_macros */
85 FALSE, /* use_rle */
86 100.0, /* opacity */
87 };
88
89
MAIN()90 MAIN ()
91
92
93 static void
94 query (void)
95 {
96 static const GimpParamDef save_args[] =
97 {
98 { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0) }" },
99 { GIMP_PDB_IMAGE, "image", "Input image" },
100 { GIMP_PDB_DRAWABLE, "drawable", "Drawable to save" },
101 { GIMP_PDB_STRING, "filename", "The name of the file to save the image in" },
102 { GIMP_PDB_STRING, "raw-filename", "The name of the file to save the image in" }
103 };
104
105 gimp_install_procedure (SAVE_PROC,
106 "Dump image data in RGB(A) format for C source",
107 "CSource cannot be run non-interactively.",
108 "Tim Janik",
109 "Tim Janik",
110 "1999",
111 N_("C source code"),
112 "*",
113 GIMP_PLUGIN,
114 G_N_ELEMENTS (save_args), 0,
115 save_args, NULL);
116
117 gimp_register_file_handler_mime (SAVE_PROC, "text/x-csrc");
118 gimp_register_file_handler_uri (SAVE_PROC);
119 gimp_register_save_handler (SAVE_PROC, "c", "");
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 GimpExportReturn export = GIMP_EXPORT_CANCEL;
133 GError *error = NULL;
134
135 INIT_I18N ();
136 gegl_init (NULL, NULL);
137
138 run_mode = param[0].data.d_int32;
139
140 *nreturn_vals = 1;
141 *return_vals = values;
142
143 values[0].type = GIMP_PDB_STATUS;
144 values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
145
146 if (run_mode == GIMP_RUN_INTERACTIVE &&
147 strcmp (name, SAVE_PROC) == 0)
148 {
149 gint32 image_ID = param[1].data.d_int32;
150 gint32 drawable_ID = param[2].data.d_int32;
151 GimpParasite *parasite;
152 gchar *x;
153
154 gimp_get_data (SAVE_PROC, &config);
155
156 config.prefixed_name = "gimp_image";
157 config.comment = NULL;
158 config.alpha = gimp_drawable_has_alpha (drawable_ID);
159
160 parasite = gimp_image_get_parasite (image_ID, "gimp-comment");
161 if (parasite)
162 {
163 config.comment = g_strndup (gimp_parasite_data (parasite),
164 gimp_parasite_data_size (parasite));
165 gimp_parasite_free (parasite);
166 }
167 x = config.comment;
168
169 gimp_ui_init (PLUG_IN_BINARY, FALSE);
170
171 export = gimp_export_image (&image_ID, &drawable_ID, "C Source",
172 GIMP_EXPORT_CAN_HANDLE_RGB |
173 GIMP_EXPORT_CAN_HANDLE_ALPHA);
174
175 if (export == GIMP_EXPORT_CANCEL)
176 {
177 values[0].data.d_status = GIMP_PDB_CANCEL;
178 return;
179 }
180
181 if (run_save_dialog (&config))
182 {
183 if (x != config.comment &&
184 !(x && config.comment && strcmp (x, config.comment) == 0))
185 {
186 if (!config.comment || !config.comment[0])
187 {
188 gimp_image_detach_parasite (image_ID, "gimp-comment");
189 }
190 else
191 {
192 parasite = gimp_parasite_new ("gimp-comment",
193 GIMP_PARASITE_PERSISTENT,
194 strlen (config.comment) + 1,
195 config.comment);
196 gimp_image_attach_parasite (image_ID, parasite);
197 gimp_parasite_free (parasite);
198 }
199 }
200
201 if (! save_image (g_file_new_for_uri (param[3].data.d_string),
202 &config, image_ID, drawable_ID, &error))
203 {
204 status = GIMP_PDB_EXECUTION_ERROR;
205
206 if (error)
207 {
208 *nreturn_vals = 2;
209 values[1].type = GIMP_PDB_STRING;
210 values[1].data.d_string = error->message;
211 }
212 }
213 else
214 {
215 gimp_set_data (SAVE_PROC, &config, sizeof (config));
216 }
217 }
218 else
219 {
220 status = GIMP_PDB_CANCEL;
221 }
222
223 if (export == GIMP_EXPORT_EXPORT)
224 gimp_image_delete (image_ID);
225 }
226 else
227 {
228 status = GIMP_PDB_CALLING_ERROR;
229 }
230
231 values[0].data.d_status = status;
232 }
233
234 static gboolean
diff2_rgb565(guint8 * ip)235 diff2_rgb565 (guint8 *ip)
236 {
237 return ip[0] != ip[2] || ip[1] != ip[3];
238 }
239
240 static gboolean
diff2_rgb(guint8 * ip)241 diff2_rgb (guint8 *ip)
242 {
243 return ip[0] != ip[3] || ip[1] != ip[4] || ip[2] != ip[5];
244 }
245
246 static gboolean
diff2_rgba(guint8 * ip)247 diff2_rgba (guint8 *ip)
248 {
249 return ip[0] != ip[4] || ip[1] != ip[5] || ip[2] != ip[6] || ip[3] != ip[7];
250 }
251
252 static guint8 *
rl_encode_rgbx(guint8 * bp,guint8 * ip,guint8 * limit,guint bpp)253 rl_encode_rgbx (guint8 *bp,
254 guint8 *ip,
255 guint8 *limit,
256 guint bpp)
257 {
258 gboolean (*diff2_pix) (guint8 *);
259 guint8 *ilimit = limit - bpp;
260
261 switch (bpp)
262 {
263 case 2: diff2_pix = diff2_rgb565; break;
264 case 3: diff2_pix = diff2_rgb; break;
265 case 4: diff2_pix = diff2_rgba; break;
266 default: g_assert_not_reached ();
267 }
268
269 while (ip < limit)
270 {
271 g_assert (ip < ilimit); /* paranoid */
272
273 if (diff2_pix (ip))
274 {
275 guint8 *s_ip = ip;
276 guint l = 1;
277
278 ip += bpp;
279 while (l < 127 && ip < ilimit && diff2_pix (ip))
280 { ip += bpp; l += 1; }
281 if (ip == ilimit && l < 127)
282 { ip += bpp; l += 1; }
283 *(bp++) = l;
284 memcpy (bp, s_ip, l * bpp);
285 bp += l * bpp;
286 }
287 else
288 {
289 guint l = 2;
290
291 ip += bpp;
292 while (l < 127 && ip < ilimit && !diff2_pix (ip))
293 { ip += bpp; l += 1; }
294 *(bp++) = l | 128;
295 memcpy (bp, ip, bpp);
296 ip += bpp;
297 bp += bpp;
298 }
299 if (ip == ilimit)
300 {
301 *(bp++) = 1;
302 memcpy (bp, ip, bpp);
303 ip += bpp;
304 bp += bpp;
305 }
306 }
307
308 return bp;
309 }
310
311 static gboolean print (GOutputStream *stream,
312 GError **error,
313 const gchar *format,
314 ...) G_GNUC_PRINTF (3, 4);
315
316 static gboolean
print(GOutputStream * stream,GError ** error,const gchar * format,...)317 print (GOutputStream *stream,
318 GError **error,
319 const gchar *format,
320 ...)
321 {
322 va_list args;
323 gboolean success;
324
325 va_start (args, format);
326 success = g_output_stream_vprintf (stream, NULL, NULL,
327 error, format, args);
328 va_end (args);
329
330 return success;
331 }
332
333 static inline gboolean
save_rle_decoder(GOutputStream * output,const gchar * macro_name,const gchar * s_uint,const gchar * s_uint_8,guint bpp,GError ** error)334 save_rle_decoder (GOutputStream *output,
335 const gchar *macro_name,
336 const gchar *s_uint,
337 const gchar *s_uint_8,
338 guint bpp,
339 GError **error)
340 {
341 return
342 print (output, error,
343 "#define %s_RUN_LENGTH_DECODE(image_buf, rle_data, size, bpp) do \\\n",
344 macro_name) &&
345 print (output, error,
346 "{ %s __bpp; %s *__ip; const %s *__il, *__rd; \\\n",
347 s_uint, s_uint_8, s_uint_8) &&
348 print (output, error,
349 " __bpp = (bpp); __ip = (image_buf); __il = __ip + (size) * __bpp; \\\n"
350 " __rd = (rle_data); if (__bpp > 3) { /* RGBA */ \\\n"
351 " while (__ip < __il) { %s __l = *(__rd++); \\\n",
352 s_uint) &&
353 print (output, error,
354 " if (__l & 128) { __l = __l - 128; \\\n"
355 " do { memcpy (__ip, __rd, 4); __ip += 4; } while (--__l); __rd += 4; \\\n"
356 " } else { __l *= 4; memcpy (__ip, __rd, __l); \\\n"
357 " __ip += __l; __rd += __l; } } \\\n"
358 " } else if (__bpp == 3) { /* RGB */ \\\n"
359 " while (__ip < __il) { %s __l = *(__rd++); \\\n",
360 s_uint) &&
361 print (output, error,
362 " if (__l & 128) { __l = __l - 128; \\\n"
363 " do { memcpy (__ip, __rd, 3); __ip += 3; } while (--__l); __rd += 3; \\\n"
364 " } else { __l *= 3; memcpy (__ip, __rd, __l); \\\n"
365 " __ip += __l; __rd += __l; } } \\\n"
366 " } else { /* RGB16 */ \\\n"
367 " while (__ip < __il) { %s __l = *(__rd++); \\\n",
368 s_uint) &&
369 print (output, error,
370 " if (__l & 128) { __l = __l - 128; \\\n"
371 " do { memcpy (__ip, __rd, 2); __ip += 2; } while (--__l); __rd += 2; \\\n"
372 " } else { __l *= 2; memcpy (__ip, __rd, __l); \\\n"
373 " __ip += __l; __rd += __l; } } \\\n"
374 " } } while (0)\n");
375 }
376
377 static inline gboolean
save_uchar(GOutputStream * output,guint * c,guint8 d,Config * config,GError ** error)378 save_uchar (GOutputStream *output,
379 guint *c,
380 guint8 d,
381 Config *config,
382 GError **error)
383 {
384 static guint8 pad = 0;
385
386 if (*c > 74)
387 {
388 if (! config->use_macros)
389 {
390 if (! print (output, error, "\"\n \""))
391 return FALSE;
392
393 *c = 3;
394 }
395 else
396 {
397 if (! print (output, error, "\"\n \""))
398 return FALSE;
399
400 *c = 2;
401 }
402 }
403
404 if (d < 33 || (d >= 48 && d <= 57) || d > 126)
405 {
406 if (! print (output, error, "\\%03o", d))
407 return FALSE;
408
409 *c += 1 + 1 + (d > 7) + (d > 63);
410 pad = d < 64;
411
412 return TRUE;
413 }
414
415 if (d == '\\')
416 {
417 if (! print (output, error, "\\\\"))
418 return FALSE;
419
420 *c += 2;
421 }
422 else if (d == '"')
423 {
424 if (! print (output, error, "\\\""))
425 return FALSE;
426
427 *c += 2;
428 }
429 else if (pad && d >= '0' && d <= '9')
430 {
431 if (! print (output, error, "\"\"%c", d))
432 return FALSE;
433
434 *c += 3;
435 }
436 else
437 {
438 if (! print (output, error, "%c", d))
439 return FALSE;
440
441 *c += 1;
442 }
443
444 pad = 0;
445
446 return TRUE;
447 }
448
449 static gboolean
save_image(GFile * file,Config * config,gint32 image_ID,gint32 drawable_ID,GError ** error)450 save_image (GFile *file,
451 Config *config,
452 gint32 image_ID,
453 gint32 drawable_ID,
454 GError **error)
455 {
456 GOutputStream *output;
457 GeglBuffer *buffer;
458 GCancellable *cancellable;
459 GimpImageType drawable_type = gimp_drawable_type (drawable_ID);
460 gchar *s_uint_8, *s_uint, *s_char, *s_null;
461 guint c;
462 gchar *macro_name;
463 guint8 *img_buffer, *img_buffer_end;
464 gchar *basename;
465 guint8 *data, *p;
466 gint width;
467 gint height;
468 gint x, y, pad, n_bytes, bpp;
469 const Babl *drawable_format;
470 gint drawable_bpp;
471
472 output = G_OUTPUT_STREAM (g_file_replace (file,
473 NULL, FALSE, G_FILE_CREATE_NONE,
474 NULL, error));
475 if (output)
476 {
477 GOutputStream *buffered;
478
479 buffered = g_buffered_output_stream_new (output);
480 g_object_unref (output);
481
482 output = buffered;
483 }
484 else
485 {
486 return FALSE;
487 }
488
489 buffer = gimp_drawable_get_buffer (drawable_ID);
490
491 width = gegl_buffer_get_width (buffer);
492 height = gegl_buffer_get_height (buffer);
493
494 if (gimp_drawable_has_alpha (drawable_ID))
495 drawable_format = babl_format ("R'G'B'A u8");
496 else
497 drawable_format = babl_format ("R'G'B' u8");
498
499 drawable_bpp = babl_format_get_bytes_per_pixel (drawable_format);
500
501 bpp = config->rgb565 ? 2 : (config->alpha ? 4 : 3);
502 n_bytes = width * height * bpp;
503 pad = width * drawable_bpp;
504 if (config->use_rle)
505 pad = MAX (pad, 130 + n_bytes / 127);
506
507 data = g_new (guint8, pad + n_bytes);
508 p = data + pad;
509
510 for (y = 0; y < height; y++)
511 {
512 gegl_buffer_get (buffer, GEGL_RECTANGLE (0, y, width, 1), 1.0,
513 drawable_format, data,
514 GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
515
516 if (bpp == 2)
517 {
518 for (x = 0; x < width; x++)
519 {
520 guint8 *d = data + x * drawable_bpp;
521 guint8 r, g, b;
522 gushort rgb16;
523 gdouble alpha = drawable_type == GIMP_RGBA_IMAGE ? d[3] : 0xff;
524
525 alpha *= config->opacity / 25500.0;
526 r = (0.5 + alpha * (gdouble) d[0]);
527 g = (0.5 + alpha * (gdouble) d[1]);
528 b = (0.5 + alpha * (gdouble) d[2]);
529 r >>= 3;
530 g >>= 2;
531 b >>= 3;
532 rgb16 = (r << 11) + (g << 5) + b;
533 *(p++) = (guchar) rgb16;
534 *(p++) = (guchar) (rgb16 >> 8);
535 }
536 }
537 else if (config->alpha)
538 {
539 for (x = 0; x < width; x++)
540 {
541 guint8 *d = data + x * drawable_bpp;
542 gdouble alpha = drawable_type == GIMP_RGBA_IMAGE ? d[3] : 0xff;
543
544 alpha *= config->opacity / 100.0;
545 *(p++) = d[0];
546 *(p++) = d[1];
547 *(p++) = d[2];
548 *(p++) = alpha + 0.5;
549 }
550 }
551 else
552 {
553 for (x = 0; x < width; x++)
554 {
555 guint8 *d = data + x * drawable_bpp;
556 gdouble alpha = drawable_type == GIMP_RGBA_IMAGE ? d[3] : 0xff;
557
558 alpha *= config->opacity / 25500.0;
559 *(p++) = 0.5 + alpha * (gdouble) d[0];
560 *(p++) = 0.5 + alpha * (gdouble) d[1];
561 *(p++) = 0.5 + alpha * (gdouble) d[2];
562 }
563 }
564 }
565
566 img_buffer = data + pad;
567 if (config->use_rle)
568 {
569 img_buffer_end = rl_encode_rgbx (data, img_buffer,
570 img_buffer + n_bytes, bpp);
571 img_buffer = data;
572 }
573 else
574 {
575 img_buffer_end = img_buffer + n_bytes;
576 }
577
578 if (!config->use_macros && config->glib_types)
579 {
580 s_uint_8 = "guint8 ";
581 s_uint = "guint ";
582 s_char = "gchar ";
583 s_null = "NULL";
584 }
585 else if (!config->use_macros)
586 {
587 s_uint_8 = "unsigned char";
588 s_uint = "unsigned int ";
589 s_char = "char ";
590 s_null = "(char*) 0";
591 }
592 else if (config->use_macros && config->glib_types)
593 {
594 s_uint_8 = "guint8";
595 s_uint = "guint";
596 s_char = "gchar";
597 s_null = "NULL";
598 }
599 else /* config->use_macros && !config->glib_types */
600 {
601 s_uint_8 = "unsigned char";
602 s_uint = "unsigned int";
603 s_char = "char";
604 s_null = "(char*) 0";
605 }
606
607 macro_name = g_ascii_strup (config->prefixed_name, -1);
608
609 basename = g_file_get_basename (file);
610
611 if (! print (output, error,
612 "/* GIMP %s C-Source image dump %s(%s) */\n\n",
613 config->alpha ? "RGBA" : "RGB",
614 config->use_rle ? "1-byte-run-length-encoded " : "",
615 basename))
616 goto fail;
617
618 g_free (basename);
619
620 if (config->use_rle && !config->use_macros)
621 {
622 if (! save_rle_decoder (output,
623 macro_name,
624 config->glib_types ? "guint" : "unsigned int",
625 config->glib_types ? "guint8" : "unsigned char",
626 bpp,
627 error))
628 goto fail;
629 }
630
631 if (!config->use_macros)
632 {
633 if (! print (output, error,
634 "static const struct {\n"
635 " %s\t width;\n"
636 " %s\t height;\n"
637 " %s\t bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */ \n",
638 s_uint, s_uint, s_uint))
639 goto fail;
640
641 if (config->use_comment)
642 {
643 if (! print (output, error, " %s\t*comment;\n", s_char))
644 goto fail;
645 }
646
647 if (! print (output, error,
648 " %s\t %spixel_data[",
649 s_uint_8,
650 config->use_rle ? "rle_" : ""))
651 goto fail;
652
653 if (config->use_rle)
654 {
655 if (! print (output, error,
656 "%u + 1];\n",
657 (guint) (img_buffer_end - img_buffer)))
658 goto fail;
659 }
660 else
661 {
662 if (! print (output, error,
663 "%u * %u * %u + 1];\n",
664 width,
665 height,
666 bpp))
667 goto fail;
668 }
669
670 if (! print (output, error, "} %s = {\n", config->prefixed_name))
671 goto fail;
672
673 if (! print (output, error,
674 " %u, %u, %u,\n",
675 width,
676 height,
677 bpp))
678 goto fail;
679 }
680 else /* use macros */
681 {
682 if (! print (output, error,
683 "#define %s_WIDTH (%u)\n"
684 "#define %s_HEIGHT (%u)\n"
685 "#define %s_BYTES_PER_PIXEL (%u) /* 2:RGB16, 3:RGB, 4:RGBA */\n",
686 macro_name, width,
687 macro_name, height,
688 macro_name, bpp))
689 {
690 goto fail;
691 }
692 }
693
694 if (config->use_comment && !config->comment)
695 {
696 if (! config->use_macros)
697 {
698 if (! print (output, error, " %s,\n", s_null))
699 goto fail;
700 }
701 else
702 {
703 if (! print (output, error,
704 "#define %s_COMMENT (%s)\n",
705 macro_name, s_null))
706 goto fail;
707 }
708 }
709 else if (config->use_comment)
710 {
711 gchar *p = config->comment - 1;
712
713 if (config->use_macros)
714 {
715 if (! print (output, error, "#define %s_COMMENT \\\n", macro_name))
716 goto fail;
717 }
718
719 if (! print (output, error, " \""))
720 goto fail;
721
722 while (*(++p))
723 {
724 gboolean success = FALSE;
725
726 if (*p == '\\')
727 success = print (output, error, "\\\\");
728 else if (*p == '"')
729 success = print (output, error, "\\\"");
730 else if (*p == '\n' && p[1])
731 success = print (output, error,
732 "\\n\"%s\n \"",
733 config->use_macros ? " \\" : "");
734 else if (*p == '\n')
735 success = print (output, error, "\\n");
736 else if (*p == '\r')
737 success = print (output, error, "\\r");
738 else if (*p == '\b')
739 success = print (output, error, "\\b");
740 else if (*p == '\f')
741 success = print (output, error, "\\f");
742 else if (( *p >= 32 && *p <= 47 ) || (*p >= 58 && *p <= 126))
743 success = print (output, error, "%c", *p);
744 else
745 success = print (output, error, "\\%03o", *p);
746
747 if (! success)
748 goto fail;
749 }
750
751 if (! config->use_macros)
752 {
753 if (! print (output, error, "\",\n"))
754 goto fail;
755 }
756 else
757 {
758 if (! print (output, error, "\"\n"))
759 goto fail;
760 }
761 }
762
763 if (config->use_macros)
764 {
765 if (! print (output, error,
766 "#define %s_%sPIXEL_DATA ((%s*) %s_%spixel_data)\n",
767 macro_name,
768 config->use_rle ? "RLE_" : "",
769 s_uint_8,
770 macro_name,
771 config->use_rle ? "rle_" : ""))
772 goto fail;
773
774 if (config->use_rle)
775 {
776 if (! save_rle_decoder (output,
777 macro_name,
778 s_uint,
779 s_uint_8,
780 bpp,
781 error))
782 goto fail;
783 }
784
785 if (! print (output, error,
786 "static const %s %s_%spixel_data[",
787 s_uint_8,
788 macro_name,
789 config->use_rle ? "rle_" : ""))
790 goto fail;
791
792 if (config->use_rle)
793 {
794 if (! print (output, error,
795 "%u + 1] =\n",
796 (guint) (img_buffer_end - img_buffer)))
797 goto fail;
798 }
799 else
800 {
801 if (! print (output, error,
802 "%u * %u * %u + 1] =\n",
803 width,
804 height,
805 bpp))
806 goto fail;
807 }
808
809 if (! print (output, error, "(\""))
810 goto fail;
811
812 c = 2;
813 }
814 else
815 {
816 if (! print (output, error, " \""))
817 goto fail;
818
819 c = 3;
820 }
821
822 switch (drawable_type)
823 {
824 case GIMP_RGB_IMAGE:
825 case GIMP_RGBA_IMAGE:
826 do
827 {
828 if (! save_uchar (output, &c, *(img_buffer++), config, error))
829 goto fail;
830 }
831 while (img_buffer < img_buffer_end);
832 break;
833
834 default:
835 g_warning ("unhandled drawable type (%d)", drawable_type);
836 goto fail;
837 }
838
839 if (! config->use_macros)
840 {
841 if (! print (output, error, "\",\n};\n\n"))
842 goto fail;
843 }
844 else
845 {
846 if (! print (output, error, "\");\n\n"))
847 goto fail;
848 }
849
850 if (! g_output_stream_close (output, NULL, error))
851 goto fail;
852
853 g_object_unref (output);
854 g_object_unref (buffer);
855
856 return TRUE;
857
858 fail:
859
860 cancellable = g_cancellable_new ();
861 g_cancellable_cancel (cancellable);
862 g_output_stream_close (output, cancellable, NULL);
863 g_object_unref (cancellable);
864
865 g_object_unref (output);
866 g_object_unref (buffer);
867
868 return FALSE;
869 }
870
871 static void
rgb565_toggle_button_update(GtkWidget * toggle,gpointer data)872 rgb565_toggle_button_update (GtkWidget *toggle,
873 gpointer data)
874 {
875 GtkWidget *widget;
876 gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (toggle));
877
878 gimp_toggle_button_update (toggle, data);
879
880 widget = g_object_get_data (G_OBJECT (toggle), "set-insensitive-1");
881 if (widget)
882 gtk_widget_set_sensitive (widget, ! active);
883 }
884
885 static gboolean
run_save_dialog(Config * config)886 run_save_dialog (Config *config)
887 {
888 GtkWidget *dialog;
889 GtkWidget *vbox;
890 GtkWidget *table;
891 GtkWidget *prefixed_name;
892 GtkWidget *centry;
893 GtkWidget *toggle;
894 GtkWidget *alpha_toggle;
895 GtkObject *adj;
896 gboolean run;
897
898 dialog = gimp_export_dialog_new (_("C-Source"), PLUG_IN_BINARY, SAVE_PROC);
899
900 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
901 gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
902 gtk_box_pack_start (GTK_BOX (gimp_export_dialog_get_content_area (dialog)),
903 vbox, TRUE, TRUE, 0);
904 gtk_widget_show (vbox);
905
906 table = gtk_table_new (2, 2, FALSE);
907 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
908 gtk_table_set_row_spacings (GTK_TABLE (table), 6);
909 gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
910 gtk_widget_show (table);
911
912 /* Prefixed Name
913 */
914 prefixed_name = gtk_entry_new ();
915 gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
916 _("_Prefixed name:"), 0.0, 0.5,
917 prefixed_name, 1, FALSE);
918 gtk_entry_set_text (GTK_ENTRY (prefixed_name),
919 config->prefixed_name ? config->prefixed_name : "");
920
921 /* Comment Entry
922 */
923 centry = gtk_entry_new ();
924 gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
925 _("Co_mment:"), 0.0, 0.5,
926 centry, 1, FALSE);
927 gtk_entry_set_text (GTK_ENTRY (centry),
928 config->comment ? config->comment : "");
929
930 /* Use Comment
931 */
932 toggle = gtk_check_button_new_with_mnemonic (_("_Save comment to file"));
933 gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
934 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
935 config->use_comment);
936 gtk_widget_show (toggle);
937
938 g_signal_connect (toggle, "toggled",
939 G_CALLBACK (gimp_toggle_button_update),
940 &config->use_comment);
941
942 /* GLib types
943 */
944 toggle = gtk_check_button_new_with_mnemonic (_("_Use GLib types (guint8*)"));
945 gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
946 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
947 config->glib_types);
948 gtk_widget_show (toggle);
949
950 g_signal_connect (toggle, "toggled",
951 G_CALLBACK (gimp_toggle_button_update),
952 &config->glib_types);
953
954 /* Use Macros
955 */
956 toggle =
957 gtk_check_button_new_with_mnemonic (_("Us_e macros instead of struct"));
958 gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
959 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
960 config->use_macros);
961 gtk_widget_show (toggle);
962
963 g_signal_connect (toggle, "toggled",
964 G_CALLBACK (gimp_toggle_button_update),
965 &config->use_macros);
966
967 /* Use RLE
968 */
969 toggle =
970 gtk_check_button_new_with_mnemonic (_("Use _1 byte Run-Length-Encoding"));
971 gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
972 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
973 config->use_rle);
974 gtk_widget_show (toggle);
975
976 g_signal_connect (toggle, "toggled",
977 G_CALLBACK (gimp_toggle_button_update),
978 &config->use_rle);
979
980 /* Alpha
981 */
982 alpha_toggle = toggle =
983 gtk_check_button_new_with_mnemonic (_("Sa_ve alpha channel (RGBA/RGB)"));
984 gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
985 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
986 config->alpha);
987 gtk_widget_show (toggle);
988
989 g_signal_connect (toggle, "toggled",
990 G_CALLBACK (gimp_toggle_button_update),
991 &config->alpha);
992
993 /* RGB-565
994 */
995 toggle = gtk_check_button_new_with_mnemonic (_("Save as _RGB565 (16-bit)"));
996 gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
997
998 /* Alpha setting is not used with RGB-565 */
999 g_object_set_data (G_OBJECT (toggle), "set-insensitive-1", alpha_toggle);
1000
1001 g_signal_connect (toggle, "toggled",
1002 G_CALLBACK (rgb565_toggle_button_update),
1003 &config->rgb565);
1004 gtk_widget_show (toggle);
1005
1006 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
1007 config->rgb565);
1008
1009 /* Max Alpha Value
1010 */
1011 table = gtk_table_new (1, 3, FALSE);
1012 gtk_table_set_col_spacings (GTK_TABLE (table), 4);
1013 gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
1014 gtk_widget_show (table);
1015
1016 adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
1017 _("Op_acity:"), 100, 0,
1018 config->opacity, 0, 100, 1, 10, 1,
1019 TRUE, 0, 0,
1020 NULL, NULL);
1021 g_signal_connect (adj, "value-changed",
1022 G_CALLBACK (gimp_double_adjustment_update),
1023 &config->opacity);
1024
1025 gtk_widget_show (dialog);
1026
1027 run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
1028
1029 if (run)
1030 {
1031 config->prefixed_name =
1032 g_strdup (gtk_entry_get_text (GTK_ENTRY (prefixed_name)));
1033 config->comment = g_strdup (gtk_entry_get_text (GTK_ENTRY (centry)));
1034 }
1035
1036 gtk_widget_destroy (dialog);
1037
1038 if (!config->prefixed_name || !config->prefixed_name[0])
1039 config->prefixed_name = "tmp";
1040
1041 if (config->comment && !config->comment[0])
1042 config->comment = NULL;
1043
1044 return run;
1045 }
1046