gimppalette-import.c 16.9 KB
Newer Older
1
/* GIMP - The GNU Image Manipulation Program
2 3
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
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 8 9 10 11 12 13 14
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * 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
 */

#include "config.h"

20
#include <cairo.h>
21
#include <gegl.h>
22
#include <gdk-pixbuf/gdk-pixbuf.h>
23

24
#include "libgimpbase/gimpbase.h"
25 26
#include "libgimpcolor/gimpcolor.h"

Michael Natterer's avatar
Michael Natterer committed
27
#include "core-types.h"
28

29
#include "gimpchannel.h"
30
#include "gimpcontainer.h"
31
#include "gimpcontext.h"
32 33
#include "gimpgradient.h"
#include "gimpimage.h"
34
#include "gimpimage-colormap.h"
35
#include "gimppalette.h"
36
#include "gimppalette-import.h"
37
#include "gimppalette-load.h"
38
#include "gimppickable.h"
Michael Natterer's avatar
Michael Natterer committed
39

40
#include "gimp-intl.h"
41 42 43 44 45 46 47 48


#define MAX_IMAGE_COLORS (10000 * 2)


/*  create a palette from a gradient  ****************************************/

GimpPalette *
49 50 51 52 53 54
gimp_palette_import_from_gradient (GimpGradient                *gradient,
                                   GimpContext                 *context,
                                   gboolean                     reverse,
                                   GimpGradientBlendColorSpace  blend_color_space,
                                   const gchar                 *palette_name,
                                   gint                         n_colors)
55
{
56 57 58 59 60
  GimpPalette         *palette;
  GimpGradientSegment *seg = NULL;
  gdouble              dx, cur_x;
  GimpRGB              color;
  gint                 i;
61 62

  g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), NULL);
63
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
64
  g_return_val_if_fail (palette_name != NULL, NULL);
65
  g_return_val_if_fail (n_colors > 1, NULL);
66

67
  palette = GIMP_PALETTE (gimp_palette_new (context, palette_name));
68

69
  dx = 1.0 / (n_colors - 1);
70

71
  for (i = 0, cur_x = 0; i < n_colors; i++, cur_x += dx)
72
    {
73
      seg = gimp_gradient_get_color_at (gradient, context,
74 75
                                        seg, cur_x, reverse, blend_color_space,
                                        &color);
76
      gimp_palette_add_entry (palette, -1, NULL, &color);
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
    }

  return palette;
}


/*  create a palette from a non-indexed image  *******************************/

typedef struct _ImgColors ImgColors;

struct _ImgColors
{
  guint  count;
  guint  r_adj;
  guint  g_adj;
  guint  b_adj;
  guchar r;
  guchar g;
  guchar b;
};

static gint count_color_entries = 0;

static GHashTable *
101
gimp_palette_import_store_colors (GHashTable *table,
102 103 104
                                  guchar     *colors,
                                  guchar     *colors_real,
                                  gint        n_colors)
105 106 107 108 109
{
  gpointer   found_color = NULL;
  ImgColors *new_color;
  guint      key_colors = colors[0] * 256 * 256 + colors[1] * 256 + colors[2];

110
  if (table == NULL)
111
    {
112
      table = g_hash_table_new (g_direct_hash, g_direct_equal);
113 114 115 116
      count_color_entries = 0;
    }
  else
    {
117
      found_color = g_hash_table_lookup (table, GUINT_TO_POINTER (key_colors));
118 119 120 121 122
    }

  if (found_color == NULL)
    {
      if (count_color_entries > MAX_IMAGE_COLORS)
123 124 125 126
        {
          /* Don't add any more new ones */
          return table;
        }
127 128 129

      count_color_entries++;

130
      new_color = g_slice_new (ImgColors);
131 132 133 134 135 136 137 138 139

      new_color->count = 1;
      new_color->r_adj = 0;
      new_color->g_adj = 0;
      new_color->b_adj = 0;
      new_color->r     = colors[0];
      new_color->g     = colors[1];
      new_color->b     = colors[2];

140
      g_hash_table_insert (table, GUINT_TO_POINTER (key_colors), new_color);
141 142 143
    }
  else
    {
144
      new_color = found_color;
145 146

      if (new_color->count < (G_MAXINT - 1))
147
        new_color->count++;
148 149 150 151 152 153 154 155

      /* Now do the adjustments ...*/
      new_color->r_adj += (colors_real[0] - colors[0]);
      new_color->g_adj += (colors_real[1] - colors[1]);
      new_color->b_adj += (colors_real[2] - colors[2]);

      /* Boundary conditions */
      if(new_color->r_adj > (G_MAXINT - 255))
156
        new_color->r_adj /= new_color->count;
157 158

      if(new_color->g_adj > (G_MAXINT - 255))
159
        new_color->g_adj /= new_color->count;
160 161

      if(new_color->b_adj > (G_MAXINT - 255))
162
        new_color->b_adj /= new_color->count;
163 164
    }

165
  return table;
166 167 168
}

static void
169 170 171
gimp_palette_import_create_list (gpointer key,
                                 gpointer value,
                                 gpointer user_data)
172
{
173 174
  GSList    **list      = user_data;
  ImgColors  *color_tab = value;
175

176
  *list = g_slist_prepend (*list, color_tab);
177 178 179 180
}

static gint
gimp_palette_import_sort_colors (gconstpointer a,
181
                                 gconstpointer b)
182
{
183 184
  const ImgColors *s1 = a;
  const ImgColors *s2 = b;
185 186 187 188 189 190 191 192 193 194 195

  if(s1->count > s2->count)
    return -1;
  if(s1->count < s2->count)
    return 1;

  return 0;
}

static void
gimp_palette_import_create_image_palette (gpointer data,
196
                                          gpointer user_data)
197
{
198
  GimpPalette *palette   = user_data;
Manish Singh's avatar
Manish Singh committed
199
  ImgColors   *color_tab = data;
200 201 202 203
  gint         n_colors;
  gchar       *lab;
  GimpRGB      color;

204
  n_colors = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (palette),
205
                                                 "import-n-colors"));
206

207
  if (gimp_palette_get_n_colors (palette) >= n_colors)
208 209
    return;

210 211 212 213 214
  /* TRANSLATORS: the "%s" is an item title and "%u" is the number of
     occurrences for this item. */
  lab = g_strdup_printf (_("%s (occurs %u)"),
                         _("Untitled"),
                         color_tab->count);
215 216 217 218

  /* Adjust the colors to the mean of the the sample */
  gimp_rgba_set_uchar
    (&color,
219 220
     (guchar) color_tab->r + (color_tab->r_adj / color_tab->count),
     (guchar) color_tab->g + (color_tab->g_adj / color_tab->count),
221 222 223
     (guchar) color_tab->b + (color_tab->b_adj / color_tab->count),
     255);

224
  gimp_palette_add_entry (palette, -1, lab, &color);
225 226 227 228 229

  g_free (lab);
}

static GimpPalette *
230 231
gimp_palette_import_make_palette (GHashTable  *table,
                                  const gchar *palette_name,
232
                                  GimpContext *context,
233
                                  gint         n_colors)
234
{
235 236
  GimpPalette *palette;
  GSList      *list = NULL;
237
  GSList      *iter;
238

239
  palette = GIMP_PALETTE (gimp_palette_new (context, palette_name));
240

241 242
  if (! table)
    return palette;
243

244 245
  g_hash_table_foreach (table, gimp_palette_import_create_list, &list);
  list = g_slist_sort (list, gimp_palette_import_sort_colors);
246

247
  g_object_set_data (G_OBJECT (palette), "import-n-colors",
248
                     GINT_TO_POINTER (n_colors));
249

250
  g_slist_foreach (list, gimp_palette_import_create_image_palette, palette);
251

252
  g_object_set_data (G_OBJECT (palette), "import-n-colors", NULL);
253 254 255 256 257

  /*  Free up used memory
   *  Note the same structure is on both the hash list and the sorted
   *  list. So only delete it once.
   */
258
  g_hash_table_destroy (table);
259

260 261
  for (iter = list; iter; iter = iter->next)
    g_slice_free (ImgColors, iter->data);
262

263
  g_slist_free (list);
264 265 266 267

  return palette;
}

268 269
static GHashTable *
gimp_palette_import_extract (GimpImage     *image,
270 271 272 273
                             GimpPickable  *pickable,
                             gint           pickable_off_x,
                             gint           pickable_off_y,
                             gboolean       selection_only,
274 275 276 277 278 279
                             gint           x,
                             gint           y,
                             gint           width,
                             gint           height,
                             gint           n_colors,
                             gint           threshold)
280
{
281 282 283 284 285 286 287 288 289 290
  GeglBuffer         *buffer;
  GeglBufferIterator *iter;
  GeglRectangle      *mask_roi = NULL;
  GeglRectangle       rect     = { x, y, width, height };
  GHashTable         *colors   = NULL;
  const Babl         *format;
  gint                bpp;
  gint                mask_bpp = 0;

  buffer = gimp_pickable_get_buffer (pickable);
291
  format = babl_format ("R'G'B'A u8");
292

293
  iter = gegl_buffer_iterator_new (buffer, &rect, 0, format,
294
                                   GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 2);
295
  bpp = babl_format_get_bytes_per_pixel (format);
296

297 298 299
  if (selection_only &&
      ! gimp_channel_is_empty (gimp_image_get_mask (image)))
    {
300 301
      GimpDrawable *mask = GIMP_DRAWABLE (gimp_image_get_mask (image));

302 303 304
      rect.x = x + pickable_off_x;
      rect.y = y + pickable_off_y;

305 306
      buffer = gimp_drawable_get_buffer (mask);
      format = babl_format ("Y u8");
307

308
      gegl_buffer_iterator_add (iter, buffer, &rect, 0, format,
309
                                GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
310
      mask_roi = &iter->items[1].roi;
311
      mask_bpp = babl_format_get_bytes_per_pixel (format);
312 313
    }

314
  while (gegl_buffer_iterator_next (iter))
315
    {
316
      const guchar *data      = iter->items[0].data;
317
      const guchar *mask_data = NULL;
318
      gint          length    = iter->length;
319

320
      if (mask_roi)
321
        mask_data = iter->items[1].data;
322

323
      while (length--)
324
        {
325 326
          /*  ignore unselected, and completely transparent pixels  */
          if ((! mask_data || *mask_data) && data[ALPHA])
327
            {
328 329
              guchar rgba[MAX_CHANNELS]     = { 0, };
              guchar rgb_real[MAX_CHANNELS] = { 0, };
330

331 332
              memcpy (rgba, data, 4);
              memcpy (rgb_real, rgba, 4);
333

334 335 336
              rgba[0] = (rgba[0] / threshold) * threshold;
              rgba[1] = (rgba[1] / threshold) * threshold;
              rgba[2] = (rgba[2] / threshold) * threshold;
337

338 339 340
              colors = gimp_palette_import_store_colors (colors,
                                                         rgba, rgb_real,
                                                         n_colors);
341
            }
342

343
          data += bpp;
344 345

          if (mask_data)
346
            mask_data += mask_bpp;
347
        }
348 349
    }

350 351 352 353
  return colors;
}

GimpPalette *
354
gimp_palette_import_from_image (GimpImage   *image,
355
                                GimpContext *context,
356 357
                                const gchar *palette_name,
                                gint         n_colors,
358 359
                                gint         threshold,
                                gboolean     selection_only)
360
{
361 362 363
  GHashTable *colors;
  gint        x, y;
  gint        width, height;
364

365
  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
366
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
367 368 369 370
  g_return_val_if_fail (palette_name != NULL, NULL);
  g_return_val_if_fail (n_colors > 1, NULL);
  g_return_val_if_fail (threshold > 0, NULL);

371
  gimp_pickable_flush (GIMP_PICKABLE (image));
372

373 374
  if (selection_only)
    {
375 376
      gimp_item_bounds (GIMP_ITEM (gimp_image_get_mask (image)),
                        &x, &y, &width, &height);
377 378 379 380 381
    }
  else
    {
      x      = 0;
      y      = 0;
382 383
      width  = gimp_image_get_width  (image);
      height = gimp_image_get_height (image);
384
    }
385

386
  colors = gimp_palette_import_extract (image,
387
                                        GIMP_PICKABLE (image),
388 389 390
                                        0, 0,
                                        selection_only,
                                        x, y, width, height,
391 392
                                        n_colors, threshold);

393 394
  return gimp_palette_import_make_palette (colors, palette_name, context,
                                           n_colors);
395 396
}

397

398 399 400
/*  create a palette from an indexed image  **********************************/

GimpPalette *
401
gimp_palette_import_from_indexed_image (GimpImage   *image,
402
                                        GimpContext *context,
403
                                        const gchar *palette_name)
404
{
405 406 407 408 409
  GimpPalette  *palette;
  const guchar *colormap;
  guint         n_colors;
  gint          count;
  GimpRGB       color;
410

411
  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
412
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
413
  g_return_val_if_fail (gimp_image_get_base_type (image) == GIMP_INDEXED, NULL);
414 415
  g_return_val_if_fail (palette_name != NULL, NULL);

416
  palette = GIMP_PALETTE (gimp_palette_new (context, palette_name));
417

418 419 420 421
  colormap = gimp_image_get_colormap (image);
  n_colors = gimp_image_get_colormap_size (image);

  for (count = 0; count < n_colors; ++count)
422
    {
423 424 425 426
      gchar name[256];

      g_snprintf (name, sizeof (name), _("Index %d"), count);

427
      gimp_rgba_set_uchar (&color,
428 429 430
                           colormap[count * 3 + 0],
                           colormap[count * 3 + 1],
                           colormap[count * 3 + 2],
431
                           255);
432

433
      gimp_palette_add_entry (palette, -1, name, &color);
434 435 436 437
    }

  return palette;
}
438

439

440 441 442 443
/*  create a palette from a drawable  ****************************************/

GimpPalette *
gimp_palette_import_from_drawable (GimpDrawable *drawable,
444
                                   GimpContext  *context,
445 446
                                   const gchar  *palette_name,
                                   gint          n_colors,
447 448
                                   gint          threshold,
                                   gboolean      selection_only)
449 450 451 452
{
  GHashTable *colors = NULL;
  gint        x, y;
  gint        width, height;
453
  gint        off_x, off_y;
454 455

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
456
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
457 458 459 460 461
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
  g_return_val_if_fail (palette_name != NULL, NULL);
  g_return_val_if_fail (n_colors > 1, NULL);
  g_return_val_if_fail (threshold > 0, NULL);

462
  if (selection_only)
463
    {
464 465
      if (! gimp_item_mask_intersect (GIMP_ITEM (drawable),
                                      &x, &y, &width, &height))
466
        return NULL;
467
    }
468 469 470 471
  else
    {
      x      = 0;
      y      = 0;
472 473
      width  = gimp_item_get_width  (GIMP_ITEM (drawable));
      height = gimp_item_get_height (GIMP_ITEM (drawable));
474 475
    }

476
  gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
477 478 479 480 481 482 483 484

  colors =
    gimp_palette_import_extract (gimp_item_get_image (GIMP_ITEM (drawable)),
                                 GIMP_PICKABLE (drawable),
                                 off_x, off_y,
                                 selection_only,
                                 x, y, width, height,
                                 n_colors, threshold);
485

486 487
  return gimp_palette_import_make_palette (colors, palette_name, context,
                                           n_colors);
488
}
489

490

491 492
/*  create a palette from a file  **********************************/

493
GimpPalette *
494
gimp_palette_import_from_file (GimpContext  *context,
Michael Natterer's avatar
Michael Natterer committed
495
                               GFile        *file,
496 497 498
                               const gchar  *palette_name,
                               GError      **error)
{
499 500 501
  GList        *palette_list = NULL;
  GInputStream *input;
  GError       *my_error = NULL;
Warren Turkal's avatar
Warren Turkal committed
502

503
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
Michael Natterer's avatar
Michael Natterer committed
504
  g_return_val_if_fail (G_IS_FILE (file), NULL);
505 506 507
  g_return_val_if_fail (palette_name != NULL, NULL);
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);

508 509 510 511 512 513 514 515 516 517
  input = G_INPUT_STREAM (g_file_read (file, NULL, &my_error));
  if (! input)
    {
      g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_OPEN,
                   _("Could not open '%s' for reading: %s"),
                   gimp_file_get_utf8_name (file), my_error->message);
      g_clear_error (&my_error);
      return NULL;
    }

518
  switch (gimp_palette_load_detect_format (file, input))
519
    {
520
    case GIMP_PALETTE_FILE_FORMAT_GPL:
521
      palette_list = gimp_palette_load (context, file, input, error);
522 523 524
      break;

    case GIMP_PALETTE_FILE_FORMAT_ACT:
525
      palette_list = gimp_palette_load_act (context, file, input, error);
526 527
      break;

528
    case GIMP_PALETTE_FILE_FORMAT_RIFF_PAL:
529
      palette_list = gimp_palette_load_riff (context, file, input, error);
530 531
      break;

532
    case GIMP_PALETTE_FILE_FORMAT_PSP_PAL:
533
      palette_list = gimp_palette_load_psp (context, file, input, error);
534 535
      break;

536
    case GIMP_PALETTE_FILE_FORMAT_ACO:
537
      palette_list = gimp_palette_load_aco (context, file, input, error);
538 539
      break;

540
    case GIMP_PALETTE_FILE_FORMAT_CSS:
541
      palette_list = gimp_palette_load_css (context, file, input, error);
542 543
      break;

544
    default:
545
      g_set_error (error,
546 547
                   GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                   _("Unknown type of palette file: %s"),
Michael Natterer's avatar
Michael Natterer committed
548
                   gimp_file_get_utf8_name (file));
549
      break;
550 551
    }

552
  g_object_unref (input);
Warren Turkal's avatar
Warren Turkal committed
553

554 555 556
  if (palette_list)
    {
      GimpPalette *palette = g_object_ref (palette_list->data);
557

558 559
      gimp_object_set_name (GIMP_OBJECT (palette), palette_name);

560
      g_list_free_full (palette_list, (GDestroyNotify) g_object_unref);
561

562 563 564 565 566
      return palette;
    }

  return NULL;
}