1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimpviewrendererpalette.c
5  * Copyright (C) 2005 Michael Natterer <mitch@gimp.org>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  */
20 
21 #include "config.h"
22 
23 #include <string.h>
24 
25 #include <gegl.h>
26 #include <gtk/gtk.h>
27 
28 #include "libgimpcolor/gimpcolor.h"
29 #include "libgimpmath/gimpmath.h"
30 #include "libgimpwidgets/gimpwidgets.h"
31 
32 #include "widgets-types.h"
33 
34 #include "core/gimppalette.h"
35 
36 #include "gimpviewrendererpalette.h"
37 
38 
39 #define COLUMNS 16
40 
41 
42 static void   gimp_view_renderer_palette_finalize (GObject          *object);
43 
44 static void   gimp_view_renderer_palette_render   (GimpViewRenderer *renderer,
45                                                    GtkWidget        *widget);
46 
47 
G_DEFINE_TYPE(GimpViewRendererPalette,gimp_view_renderer_palette,GIMP_TYPE_VIEW_RENDERER)48 G_DEFINE_TYPE (GimpViewRendererPalette, gimp_view_renderer_palette,
49                GIMP_TYPE_VIEW_RENDERER)
50 
51 #define parent_class gimp_view_renderer_palette_parent_class
52 
53 
54 static void
55 gimp_view_renderer_palette_class_init (GimpViewRendererPaletteClass *klass)
56 {
57   GObjectClass          *object_class   = G_OBJECT_CLASS (klass);
58   GimpViewRendererClass *renderer_class = GIMP_VIEW_RENDERER_CLASS (klass);
59 
60   object_class->finalize = gimp_view_renderer_palette_finalize;
61 
62   renderer_class->render = gimp_view_renderer_palette_render;
63 }
64 
65 static void
gimp_view_renderer_palette_init(GimpViewRendererPalette * renderer)66 gimp_view_renderer_palette_init (GimpViewRendererPalette *renderer)
67 {
68   renderer->cell_size = 4;
69   renderer->draw_grid = FALSE;
70   renderer->columns   = COLUMNS;
71 }
72 
73 static void
gimp_view_renderer_palette_finalize(GObject * object)74 gimp_view_renderer_palette_finalize (GObject *object)
75 {
76   G_OBJECT_CLASS (parent_class)->finalize (object);
77 }
78 
79 static void
gimp_view_renderer_palette_render(GimpViewRenderer * renderer,GtkWidget * widget)80 gimp_view_renderer_palette_render (GimpViewRenderer *renderer,
81                                    GtkWidget        *widget)
82 {
83   GimpViewRendererPalette *renderpal = GIMP_VIEW_RENDERER_PALETTE (renderer);
84   GimpPalette             *palette;
85   GimpColorTransform      *transform;
86   guchar                  *row;
87   guchar                  *dest;
88   GList                   *list;
89   gdouble                  cell_width;
90   gint                     grid_width;
91   gint                     dest_stride;
92   gint                     y;
93 
94   palette = GIMP_PALETTE (renderer->viewable);
95 
96   if (gimp_palette_get_n_colors (palette) == 0)
97     return;
98 
99   grid_width = renderpal->draw_grid ? 1 : 0;
100 
101   if (renderpal->cell_size > 0)
102     {
103       gint n_columns = gimp_palette_get_columns (palette);
104 
105       if (n_columns > 0)
106         cell_width = MAX ((gdouble) renderpal->cell_size,
107                           (gdouble) (renderer->width - grid_width) /
108                           (gdouble) n_columns);
109       else
110         cell_width = renderpal->cell_size;
111     }
112   else
113     {
114       gint n_columns = gimp_palette_get_columns (palette);
115 
116       if (n_columns > 0)
117         cell_width = ((gdouble) (renderer->width - grid_width) /
118                       (gdouble) n_columns);
119       else
120         cell_width = (gdouble) (renderer->width - grid_width) / 16.0;
121     }
122 
123   cell_width = MAX (4.0, cell_width);
124 
125   renderpal->cell_width = cell_width;
126 
127   renderpal->columns = (gdouble) (renderer->width - grid_width) / cell_width;
128 
129   renderpal->rows = gimp_palette_get_n_colors (palette) / renderpal->columns;
130   if (gimp_palette_get_n_colors (palette) % renderpal->columns)
131     renderpal->rows += 1;
132 
133   renderpal->cell_height = MAX (4, ((renderer->height - grid_width) /
134                                     renderpal->rows));
135 
136   if (! renderpal->draw_grid)
137     renderpal->cell_height = MIN (renderpal->cell_height,
138                                   renderpal->cell_width);
139 
140   list = gimp_palette_get_colors (palette);
141 
142   if (! renderer->surface)
143     renderer->surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
144                                                     renderer->width,
145                                                     renderer->height);
146 
147   cairo_surface_flush (renderer->surface);
148 
149   row = g_new (guchar, renderer->width * 4);
150 
151   dest        = cairo_image_surface_get_data (renderer->surface);
152   dest_stride = cairo_image_surface_get_stride (renderer->surface);
153 
154   transform = gimp_view_renderer_get_color_transform (renderer, widget,
155                                                       babl_format ("cairo-RGB24"),
156                                                       babl_format ("cairo-RGB24"));
157 
158   for (y = 0; y < renderer->height; y++)
159     {
160       if ((y % renderpal->cell_height) == 0)
161         {
162           guchar  r, g, b;
163           gint    x;
164           gint    n = 0;
165           guchar *d = row;
166 
167           memset (row, renderpal->draw_grid ? 0 : 255, renderer->width * 4);
168 
169           r = g = b = (renderpal->draw_grid ? 0 : 255);
170 
171           for (x = 0; x < renderer->width; x++, d += 4)
172             {
173               if ((x % renderpal->cell_width) == 0)
174                 {
175                   if (list && n < renderpal->columns &&
176                       renderer->width - x >= renderpal->cell_width)
177                     {
178                       GimpPaletteEntry *entry = list->data;
179 
180                       list = g_list_next (list);
181                       n++;
182 
183                       gimp_rgb_get_uchar (&entry->color, &r, &g, &b);
184                     }
185                   else
186                     {
187                       r = g = b = (renderpal->draw_grid ? 0 : 255);
188                     }
189                 }
190 
191               if (renderpal->draw_grid && (x % renderpal->cell_width) == 0)
192                 {
193                   GIMP_CAIRO_RGB24_SET_PIXEL (d, 0, 0, 0);
194                 }
195               else
196                 {
197                   GIMP_CAIRO_RGB24_SET_PIXEL (d, r, g, b);
198                 }
199             }
200         }
201 
202       if (renderpal->draw_grid && (y % renderpal->cell_height) == 0)
203         {
204           memset (dest, 0, renderer->width * 4);
205         }
206       else
207         {
208           if (transform)
209             {
210               gimp_color_transform_process_pixels (transform,
211                                                    babl_format ("cairo-RGB24"),
212                                                    row,
213                                                    babl_format ("cairo-RGB24"),
214                                                    dest,
215                                                    renderer->width);
216             }
217           else
218             {
219               memcpy (dest, row, renderer->width * 4);
220             }
221         }
222 
223       dest += dest_stride;
224     }
225 
226   g_free (row);
227 
228   cairo_surface_mark_dirty (renderer->surface);
229 }
230 
231 
232 /*  public functions  */
233 
234 void
gimp_view_renderer_palette_set_cell_size(GimpViewRendererPalette * renderer,gint cell_size)235 gimp_view_renderer_palette_set_cell_size (GimpViewRendererPalette *renderer,
236                                           gint                     cell_size)
237 {
238   g_return_if_fail (GIMP_IS_VIEW_RENDERER_PALETTE (renderer));
239 
240   if (cell_size != renderer->cell_size)
241     {
242       renderer->cell_size = cell_size;
243 
244       gimp_view_renderer_invalidate (GIMP_VIEW_RENDERER (renderer));
245     }
246 }
247 
248 void
gimp_view_renderer_palette_set_draw_grid(GimpViewRendererPalette * renderer,gboolean draw_grid)249 gimp_view_renderer_palette_set_draw_grid (GimpViewRendererPalette *renderer,
250                                           gboolean                 draw_grid)
251 {
252   g_return_if_fail (GIMP_IS_VIEW_RENDERER_PALETTE (renderer));
253 
254   if (draw_grid != renderer->draw_grid)
255     {
256       renderer->draw_grid = draw_grid ? TRUE : FALSE;
257 
258       gimp_view_renderer_invalidate (GIMP_VIEW_RENDERER (renderer));
259     }
260 }
261