~ubuntu-branches/ubuntu/breezy/gimp/breezy

« back to all changes in this revision

Viewing changes to app/core/gimpimage-preview.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2005-10-04 19:04:46 UTC
  • Revision ID: james.westby@ubuntu.com-20051004190446-ukh32kwk56s4sjhu
Tags: upstream-2.2.8
ImportĀ upstreamĀ versionĀ 2.2.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* The GIMP -- an 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 2 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, write to the Free Software
 
16
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
17
 */
 
18
 
 
19
#include "config.h"
 
20
 
 
21
#include <glib-object.h>
 
22
 
 
23
#include "core-types.h"
 
24
 
 
25
#include "base/pixel-region.h"
 
26
#include "base/temp-buf.h"
 
27
 
 
28
#include "paint-funcs/paint-funcs.h"
 
29
 
 
30
#include "config/gimpcoreconfig.h"
 
31
 
 
32
#include "gimp.h"
 
33
#include "gimp-utils.h"
 
34
#include "gimpdrawable-preview.h"
 
35
#include "gimpimage.h"
 
36
#include "gimpimage-preview.h"
 
37
#include "gimplayer.h"
 
38
#include "gimplayermask.h"
 
39
#include "gimplist.h"
 
40
 
 
41
 
 
42
void
 
43
gimp_image_get_preview_size (GimpViewable *viewable,
 
44
                             gint          size,
 
45
                             gboolean      is_popup,
 
46
                             gboolean      dot_for_dot,
 
47
                             gint         *width,
 
48
                             gint         *height)
 
49
{
 
50
  GimpImage *gimage = GIMP_IMAGE (viewable);
 
51
 
 
52
  if (! gimage->gimp->config->layer_previews && ! is_popup)
 
53
    {
 
54
      *width  = size;
 
55
      *height = size;
 
56
      return;
 
57
    }
 
58
 
 
59
  gimp_viewable_calc_preview_size (gimage->width,
 
60
                                   gimage->height,
 
61
                                   size,
 
62
                                   size,
 
63
                                   dot_for_dot,
 
64
                                   gimage->xresolution,
 
65
                                   gimage->yresolution,
 
66
                                   width,
 
67
                                   height,
 
68
                                   NULL);
 
69
}
 
70
 
 
71
gboolean
 
72
gimp_image_get_popup_size (GimpViewable *viewable,
 
73
                           gint          width,
 
74
                           gint          height,
 
75
                           gboolean      dot_for_dot,
 
76
                           gint         *popup_width,
 
77
                           gint         *popup_height)
 
78
{
 
79
  GimpImage *gimage = GIMP_IMAGE (viewable);
 
80
 
 
81
  if (! gimage->gimp->config->layer_previews)
 
82
    return FALSE;
 
83
 
 
84
  if (gimage->width > width || gimage->height > height)
 
85
    {
 
86
      gboolean scaling_up;
 
87
 
 
88
      gimp_viewable_calc_preview_size (gimage->width,
 
89
                                       gimage->height,
 
90
                                       width  * 2,
 
91
                                       height * 2,
 
92
                                       dot_for_dot, 1.0, 1.0,
 
93
                                       popup_width,
 
94
                                       popup_height,
 
95
                                       &scaling_up);
 
96
 
 
97
      if (scaling_up)
 
98
        {
 
99
          *popup_width  = gimage->width;
 
100
          *popup_height = gimage->height;
 
101
        }
 
102
 
 
103
      return TRUE;
 
104
    }
 
105
 
 
106
  return FALSE;
 
107
}
 
108
 
 
109
TempBuf *
 
110
gimp_image_get_preview (GimpViewable *viewable,
 
111
                        gint          width,
 
112
                        gint          height)
 
113
{
 
114
  GimpImage *gimage = GIMP_IMAGE (viewable);
 
115
 
 
116
  if (! gimage->gimp->config->layer_previews)
 
117
    return NULL;
 
118
 
 
119
  if (gimage->comp_preview_valid            &&
 
120
      gimage->comp_preview->width  == width &&
 
121
      gimage->comp_preview->height == height)
 
122
    {
 
123
      /*  The easy way  */
 
124
      return gimage->comp_preview;
 
125
    }
 
126
  else
 
127
    {
 
128
      /*  The hard way  */
 
129
      if (gimage->comp_preview)
 
130
        temp_buf_free (gimage->comp_preview);
 
131
 
 
132
      /*  Actually construct the composite preview from the layer previews!
 
133
       *  This might seem ridiculous, but it's actually the best way, given
 
134
       *  a number of unsavory alternatives.
 
135
       */
 
136
      gimage->comp_preview = gimp_image_get_new_preview (viewable,
 
137
                                                         width, height);
 
138
 
 
139
      gimage->comp_preview_valid = TRUE;
 
140
 
 
141
      return gimage->comp_preview;
 
142
    }
 
143
}
 
144
 
 
145
TempBuf *
 
146
gimp_image_get_new_preview (GimpViewable *viewable,
 
147
                            gint          width,
 
148
                            gint          height)
 
149
{
 
150
  GimpImage   *gimage;
 
151
  GimpLayer   *layer;
 
152
  GimpLayer   *floating_sel;
 
153
  PixelRegion  src1PR, src2PR, maskPR;
 
154
  PixelRegion *mask;
 
155
  TempBuf     *comp;
 
156
  TempBuf     *layer_buf;
 
157
  TempBuf     *mask_buf;
 
158
  GList       *list;
 
159
  GSList      *reverse_list = NULL;
 
160
  gdouble      ratio;
 
161
  gint         x, y, w, h;
 
162
  gint         x1, y1, x2, y2;
 
163
  gint         bytes;
 
164
  gboolean     construct_flag;
 
165
  gboolean     visible_components[MAX_CHANNELS] = { TRUE, TRUE, TRUE, TRUE };
 
166
  gint         off_x, off_y;
 
167
 
 
168
  gimage = GIMP_IMAGE (viewable);
 
169
 
 
170
  if (! gimage->gimp->config->layer_previews)
 
171
    return NULL;
 
172
 
 
173
  ratio = (gdouble) width / (gdouble) gimage->width;
 
174
 
 
175
  switch (gimp_image_base_type (gimage))
 
176
    {
 
177
    case GIMP_RGB:
 
178
    case GIMP_INDEXED:
 
179
      bytes = 4;
 
180
      break;
 
181
    case GIMP_GRAY:
 
182
      bytes = 2;
 
183
      break;
 
184
    default:
 
185
      bytes = 0;
 
186
      g_assert_not_reached ();
 
187
      break;
 
188
    }
 
189
 
 
190
  /*  The construction buffer  */
 
191
  comp = temp_buf_new (width, height, bytes, 0, 0, NULL);
 
192
  temp_buf_data_clear (comp);
 
193
 
 
194
  floating_sel = NULL;
 
195
 
 
196
  for (list = GIMP_LIST (gimage->layers)->list;
 
197
       list;
 
198
       list = g_list_next (list))
 
199
    {
 
200
      layer = (GimpLayer *) list->data;
 
201
 
 
202
      /*  only add layers that are visible to the list  */
 
203
      if (gimp_item_get_visible (GIMP_ITEM (layer)))
 
204
        {
 
205
          /*  floating selections are added right above the layer
 
206
           *  they are attached to
 
207
           */
 
208
          if (gimp_layer_is_floating_sel (layer))
 
209
            {
 
210
              floating_sel = layer;
 
211
            }
 
212
          else
 
213
            {
 
214
              if (floating_sel &&
 
215
                  floating_sel->fs.drawable == GIMP_DRAWABLE (layer))
 
216
                {
 
217
                  reverse_list = g_slist_prepend (reverse_list, floating_sel);
 
218
                }
 
219
 
 
220
              reverse_list = g_slist_prepend (reverse_list, layer);
 
221
            }
 
222
        }
 
223
    }
 
224
 
 
225
  construct_flag = FALSE;
 
226
 
 
227
  for (; reverse_list; reverse_list = g_slist_next (reverse_list))
 
228
    {
 
229
      gint     src_x, src_y;
 
230
      gint     src_width, src_height;
 
231
      gboolean use_sub_preview = FALSE;
 
232
 
 
233
      layer = (GimpLayer *) reverse_list->data;
 
234
 
 
235
      gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y);
 
236
 
 
237
      if (! gimp_rectangle_intersect (0, 0,
 
238
                                      gimp_item_width  (GIMP_ITEM (layer)),
 
239
                                      gimp_item_height (GIMP_ITEM (layer)),
 
240
                                      -off_x, -off_y,
 
241
                                      gimage->width, gimage->height,
 
242
                                      &src_x, &src_y,
 
243
                                      &src_width, &src_height))
 
244
        {
 
245
          continue;
 
246
        }
 
247
 
 
248
      x = (gint) RINT (ratio * off_x);
 
249
      y = (gint) RINT (ratio * off_y);
 
250
      w = (gint) RINT (ratio * gimp_item_width  (GIMP_ITEM (layer)));
 
251
      h = (gint) RINT (ratio * gimp_item_height (GIMP_ITEM (layer)));
 
252
 
 
253
      if (w < 1 || h < 1)
 
254
        continue;
 
255
 
 
256
      if ((w * h) > (width * height * 4))
 
257
        use_sub_preview = TRUE;
 
258
 
 
259
      x1 = CLAMP (x, 0, width);
 
260
      y1 = CLAMP (y, 0, height);
 
261
      x2 = CLAMP (x + w, 0, width);
 
262
      y2 = CLAMP (y + h, 0, height);
 
263
 
 
264
      src1PR.bytes     = comp->bytes;
 
265
      src1PR.x         = x1;
 
266
      src1PR.y         = y1;
 
267
      src1PR.w         = (x2 - x1);
 
268
      src1PR.h         = (y2 - y1);
 
269
      src1PR.rowstride = comp->width * src1PR.bytes;
 
270
      src1PR.data      = (temp_buf_data (comp) +
 
271
                          y1 * src1PR.rowstride + x1 * src1PR.bytes);
 
272
 
 
273
      if (use_sub_preview)
 
274
        {
 
275
          layer_buf = gimp_drawable_get_sub_preview (GIMP_DRAWABLE (layer),
 
276
                                                     src_x, src_y,
 
277
                                                     src_width, src_height,
 
278
                                                     (x2 - x1),
 
279
                                                     (y2 - y1));
 
280
 
 
281
          g_assert (layer_buf);
 
282
          g_assert (layer_buf->bytes <= comp->bytes);
 
283
 
 
284
          src2PR.bytes     = layer_buf->bytes;
 
285
          src2PR.x         = 0;
 
286
          src2PR.y         = 0;
 
287
          src2PR.w         = src1PR.w;
 
288
          src2PR.h         = src1PR.h;
 
289
          src2PR.rowstride = layer_buf->width * src2PR.bytes;
 
290
          src2PR.data      = temp_buf_data (layer_buf);
 
291
        }
 
292
      else
 
293
        {
 
294
          layer_buf = gimp_viewable_get_preview (GIMP_VIEWABLE (layer), w, h);
 
295
 
 
296
          g_assert (layer_buf);
 
297
          g_assert (layer_buf->bytes <= comp->bytes);
 
298
 
 
299
          src2PR.bytes     = layer_buf->bytes;
 
300
          src2PR.x         = src1PR.x;
 
301
          src2PR.y         = src1PR.y;
 
302
          src2PR.w         = src1PR.w;
 
303
          src2PR.h         = src1PR.h;
 
304
          src2PR.rowstride = layer_buf->width * src2PR.bytes;
 
305
          src2PR.data      = (temp_buf_data (layer_buf) +
 
306
                              (y1 - y) * src2PR.rowstride +
 
307
                              (x1 - x) * src2PR.bytes);
 
308
        }
 
309
 
 
310
      if (layer->mask && layer->mask->apply_mask)
 
311
        {
 
312
          if (use_sub_preview)
 
313
            {
 
314
              mask_buf =
 
315
                gimp_drawable_get_sub_preview (GIMP_DRAWABLE (layer->mask),
 
316
                                               src_x, src_y,
 
317
                                               src_width, src_height,
 
318
                                               x2 - x1,
 
319
                                               y2 - y1);
 
320
 
 
321
              maskPR.bytes     = mask_buf->bytes;
 
322
              maskPR.x         = 0;
 
323
              maskPR.y         = 0;
 
324
              maskPR.w         = src1PR.w;
 
325
              maskPR.h         = src1PR.h;
 
326
              maskPR.rowstride = mask_buf->width * mask_buf->bytes;
 
327
              maskPR.data      = mask_buf_data (mask_buf);
 
328
            }
 
329
          else
 
330
            {
 
331
              mask_buf = gimp_viewable_get_preview (GIMP_VIEWABLE (layer->mask),
 
332
                                                    w, h);
 
333
 
 
334
              maskPR.bytes     = mask_buf->bytes;
 
335
              maskPR.x         = src1PR.x;
 
336
              maskPR.y         = src1PR.y;
 
337
              maskPR.w         = src1PR.w;
 
338
              maskPR.h         = src1PR.h;
 
339
              maskPR.rowstride = mask_buf->width * mask_buf->bytes;
 
340
              maskPR.data      = (mask_buf_data (mask_buf) +
 
341
                                  (y1 - y) * maskPR.rowstride +
 
342
                                  (x1 - x) * maskPR.bytes);
 
343
            }
 
344
 
 
345
          mask = &maskPR;
 
346
        }
 
347
      else
 
348
        {
 
349
          mask_buf = NULL;
 
350
          mask     = NULL;
 
351
        }
 
352
 
 
353
      /*  Based on the type of the layer, project the layer onto the
 
354
       *   composite preview...
 
355
       *  Indexed images are actually already converted to RGB and RGBA,
 
356
       *   so just project them as if they were type "intensity"
 
357
       *  Send in all TRUE for visible since that info doesn't matter
 
358
       *   for previews
 
359
       */
 
360
      if (gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))
 
361
        {
 
362
          if (! construct_flag)
 
363
            initial_region (&src2PR, &src1PR,
 
364
                            mask, NULL,
 
365
                            layer->opacity * 255.999,
 
366
                            layer->mode,
 
367
                            visible_components,
 
368
                            INITIAL_INTENSITY_ALPHA);
 
369
          else
 
370
            combine_regions (&src1PR, &src2PR, &src1PR,
 
371
                             mask, NULL,
 
372
                             layer->opacity * 255.999,
 
373
                             layer->mode,
 
374
                             visible_components,
 
375
                             COMBINE_INTEN_A_INTEN_A);
 
376
        }
 
377
      else
 
378
        {
 
379
          if (! construct_flag)
 
380
            initial_region (&src2PR, &src1PR,
 
381
                            mask, NULL,
 
382
                            layer->opacity * 255.999,
 
383
                            layer->mode,
 
384
                            visible_components,
 
385
                            INITIAL_INTENSITY);
 
386
          else
 
387
            combine_regions (&src1PR, &src2PR, &src1PR,
 
388
                             mask, NULL,
 
389
                             layer->opacity * 255.999,
 
390
                             layer->mode,
 
391
                             visible_components,
 
392
                             COMBINE_INTEN_A_INTEN);
 
393
        }
 
394
 
 
395
      if (use_sub_preview)
 
396
        {
 
397
          temp_buf_free (layer_buf);
 
398
 
 
399
          if (mask_buf)
 
400
            temp_buf_free (mask_buf);
 
401
        }
 
402
 
 
403
      construct_flag = TRUE;
 
404
    }
 
405
 
 
406
  g_slist_free (reverse_list);
 
407
 
 
408
  return comp;
 
409
}