~ubuntu-branches/ubuntu/jaunty/gimp/jaunty-security

« back to all changes in this revision

Viewing changes to app/core/gimp-transform-region.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Holbach
  • Date: 2007-05-02 16:33:03 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070502163303-bvzhjzbpw8qglc4y
Tags: 2.3.16-1ubuntu1
* Resynchronized with Debian, remaining Ubuntu changes:
  - debian/rules: i18n magic.
* debian/control.in:
  - Maintainer: Ubuntu Core Developers <ubuntu-devel@lists.ubuntu.com>
* debian/patches/02_help-message.patch,
  debian/patches/03_gimp.desktop.in.in.patch,
  debian/patches/10_dont_show_wizard.patch: updated.
* debian/patches/04_composite-signedness.patch,
  debian/patches/05_add-letter-spacing.patch: dropped, used upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GIMP - The GNU Image Manipulation Program
 
2
 * Copyright (C) 1995-2003 Spencer Kimball, Peter Mattis, and others
 
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 <stdlib.h>
 
22
 
 
23
#include <glib-object.h>
 
24
 
 
25
#include "libgimpbase/gimpbase.h"
 
26
#include "libgimpmath/gimpmath.h"
 
27
 
 
28
#include "core-types.h"
 
29
 
 
30
#include "base/pixel-region.h"
 
31
#include "base/pixel-surround.h"
 
32
#include "base/tile-manager.h"
 
33
#include "base/tile.h"
 
34
 
 
35
#include "paint-funcs/scale-funcs.h"
 
36
 
 
37
#include "gimp-transform-region.h"
 
38
#include "gimpchannel.h"
 
39
#include "gimpcontext.h"
 
40
#include "gimpimage.h"
 
41
#include "gimppickable.h"
 
42
#include "gimpprogress.h"
 
43
 
 
44
 
 
45
/*  forward function prototypes  */
 
46
 
 
47
static void  gimp_transform_region_nearest (TileManager       *orig_tiles,
 
48
                                            PixelRegion       *destPR,
 
49
                                            gint               dest_x1,
 
50
                                            gint               dest_y1,
 
51
                                            gint               dest_x2,
 
52
                                            gint               dest_y2,
 
53
                                            gint               u1,
 
54
                                            gint               v1,
 
55
                                            gint               u2,
 
56
                                            gint               v2,
 
57
                                            const GimpMatrix3 *m,
 
58
                                            gint               alpha,
 
59
                                            const guchar      *bg_color,
 
60
                                            GimpProgress      *progress);
 
61
static void  gimp_transform_region_linear  (TileManager       *orig_tiles,
 
62
                                            PixelRegion       *destPR,
 
63
                                            gint               dest_x1,
 
64
                                            gint               dest_y1,
 
65
                                            gint               dest_x2,
 
66
                                            gint               dest_y2,
 
67
                                            gint               u1,
 
68
                                            gint               v1,
 
69
                                            gint               u2,
 
70
                                            gint               v2,
 
71
                                            const GimpMatrix3 *m,
 
72
                                            gint               alpha,
 
73
                                            gboolean           supersample,
 
74
                                            gint               recursion_level,
 
75
                                            const guchar      *bg_color,
 
76
                                            GimpProgress      *progress);
 
77
static void  gimp_transform_region_cubic   (TileManager       *orig_tiles,
 
78
                                            PixelRegion       *destPR,
 
79
                                            gint               dest_x1,
 
80
                                            gint               dest_y1,
 
81
                                            gint               dest_x2,
 
82
                                            gint               dest_y2,
 
83
                                            gint               u1,
 
84
                                            gint               v1,
 
85
                                            gint               u2,
 
86
                                            gint               v2,
 
87
                                            const GimpMatrix3 *m,
 
88
                                            gint               alpha,
 
89
                                            gboolean           supersample,
 
90
                                            gint               recursion_level,
 
91
                                            const guchar      *bg_color,
 
92
                                            GimpProgress      *progress);
 
93
static void  gimp_transform_region_lanczos (TileManager       *orig_tiles,
 
94
                                            PixelRegion       *destPR,
 
95
                                            gint               dest_x1,
 
96
                                            gint               dest_y1,
 
97
                                            gint               dest_x2,
 
98
                                            gint               dest_y2,
 
99
                                            gint               u1,
 
100
                                            gint               v1,
 
101
                                            gint               u2,
 
102
                                            gint               v2,
 
103
                                            const GimpMatrix3 *m,
 
104
                                            gint               alpha,
 
105
                                            gboolean           supersample,
 
106
                                            gint               recursion_level,
 
107
                                            const guchar      *bg_color,
 
108
                                            GimpProgress      *progress);
 
109
 
 
110
static inline void  untransform_coords     (const GimpMatrix3 *m,
 
111
                                            gint               x,
 
112
                                            gint               y,
 
113
                                            gdouble           *tu,
 
114
                                            gdouble           *tv,
 
115
                                            gdouble           *tw);
 
116
static inline void  normalize_coords       (const gint         coords,
 
117
                                            const gdouble     *tu,
 
118
                                            const gdouble     *tv,
 
119
                                            const gdouble     *tw,
 
120
                                            gdouble           *u,
 
121
                                            gdouble           *v);
 
122
 
 
123
static inline gboolean supersample_dtest   (gdouble u0,
 
124
                                            gdouble v0,
 
125
                                            gdouble u1,
 
126
                                            gdouble v1,
 
127
                                            gdouble u2,
 
128
                                            gdouble v2,
 
129
                                            gdouble u3,
 
130
                                            gdouble v3);
 
131
 
 
132
static void     sample_adapt      (TileManager   *tm,
 
133
                                   gdouble        uc,
 
134
                                   gdouble        vc,
 
135
                                   gdouble        u0,
 
136
                                   gdouble        v0,
 
137
                                   gdouble        u1,
 
138
                                   gdouble        v1,
 
139
                                   gdouble        u2,
 
140
                                   gdouble        v2,
 
141
                                   gdouble        u3,
 
142
                                   gdouble        v3,
 
143
                                   gint           level,
 
144
                                   guchar        *color,
 
145
                                   const guchar  *bg_color,
 
146
                                   gint           bpp,
 
147
                                   gint           alpha);
 
148
 
 
149
static void     sample_linear     (PixelSurround *surround,
 
150
                                   gdouble        u,
 
151
                                   gdouble        v,
 
152
                                   guchar        *color,
 
153
                                   gint           bytes,
 
154
                                   gint           alpha);
 
155
static void     sample_cubic      (PixelSurround *surround,
 
156
                                   gdouble        u,
 
157
                                   gdouble        v,
 
158
                                   guchar        *color,
 
159
                                   gint           bytes,
 
160
                                   gint           alpha);
 
161
static void     sample_lanczos    (PixelSurround *surround,
 
162
                                   const gfloat  *lanczos,
 
163
                                   gdouble        u,
 
164
                                   gdouble        v,
 
165
                                   guchar        *color,
 
166
                                   gint           bytes,
 
167
                                   gint           alpha);
 
168
 
 
169
 
 
170
/*  public functions  */
 
171
 
 
172
void
 
173
gimp_transform_region (GimpPickable          *pickable,
 
174
                       GimpContext           *context,
 
175
                       TileManager           *orig_tiles,
 
176
                       PixelRegion           *destPR,
 
177
                       gint                   dest_x1,
 
178
                       gint                   dest_y1,
 
179
                       gint                   dest_x2,
 
180
                       gint                   dest_y2,
 
181
                       const GimpMatrix3     *matrix,
 
182
                       GimpInterpolationType  interpolation_type,
 
183
                       gboolean               supersample,
 
184
                       gint                   recursion_level,
 
185
                       GimpProgress          *progress)
 
186
{
 
187
  GimpImageType  pickable_type;
 
188
  GimpMatrix3    m;
 
189
  gint           u1, v1, u2, v2;       /* source bounding box */
 
190
  gint           alpha;
 
191
  guchar         bg_color[MAX_CHANNELS];
 
192
 
 
193
  g_return_if_fail (GIMP_IS_PICKABLE (pickable));
 
194
 
 
195
  tile_manager_get_offsets (orig_tiles, &u1, &v1);
 
196
 
 
197
  u2 = u1 + tile_manager_width (orig_tiles);
 
198
  v2 = v1 + tile_manager_height (orig_tiles);
 
199
 
 
200
  m = *matrix;
 
201
  gimp_matrix3_invert (&m);
 
202
 
 
203
  alpha = 0;
 
204
 
 
205
  /*  turn interpolation off for simple transformations (e.g. rot90)  */
 
206
  if (gimp_matrix3_is_simple (matrix))
 
207
    interpolation_type = GIMP_INTERPOLATION_NONE;
 
208
 
 
209
  pickable_type = gimp_pickable_get_image_type (pickable);
 
210
 
 
211
  /*  Get the background color  */
 
212
  gimp_image_get_background (gimp_pickable_get_image (pickable), context,
 
213
                             pickable_type, bg_color);
 
214
 
 
215
  switch (GIMP_IMAGE_TYPE_BASE_TYPE (pickable_type))
 
216
    {
 
217
    case GIMP_RGB:
 
218
      bg_color[ALPHA_PIX] = TRANSPARENT_OPACITY;
 
219
      alpha = ALPHA_PIX;
 
220
      break;
 
221
 
 
222
    case GIMP_GRAY:
 
223
      bg_color[ALPHA_G_PIX] = TRANSPARENT_OPACITY;
 
224
      alpha = ALPHA_G_PIX;
 
225
      break;
 
226
 
 
227
    case GIMP_INDEXED:
 
228
      bg_color[ALPHA_I_PIX] = TRANSPARENT_OPACITY;
 
229
      alpha = ALPHA_I_PIX;
 
230
      /*  If the image is indexed color, ignore interpolation value  */
 
231
      interpolation_type = GIMP_INTERPOLATION_NONE;
 
232
      break;
 
233
 
 
234
    default:
 
235
      g_assert_not_reached ();
 
236
      break;
 
237
    }
 
238
 
 
239
  /*  "Outside" a channel is transparency, not the bg color  */
 
240
  if (GIMP_IS_CHANNEL (pickable))
 
241
    bg_color[0] = TRANSPARENT_OPACITY;
 
242
 
 
243
  /*  setting alpha = 0 will cause the channel's value to be treated
 
244
   *  as alpha and the color channel loops never to be entered
 
245
   */
 
246
  if (tile_manager_bpp (orig_tiles) == 1)
 
247
    alpha = 0;
 
248
 
 
249
  switch (interpolation_type)
 
250
    {
 
251
    case GIMP_INTERPOLATION_NONE:
 
252
      gimp_transform_region_nearest (orig_tiles, destPR,
 
253
                                     dest_x1, dest_y1, dest_x2, dest_y2,
 
254
                                     u1, v1, u2, v2,
 
255
                                     &m, alpha, bg_color, progress);
 
256
      break;
 
257
 
 
258
    case GIMP_INTERPOLATION_LINEAR:
 
259
      gimp_transform_region_linear (orig_tiles, destPR,
 
260
                                    dest_x1, dest_y1, dest_x2, dest_y2,
 
261
                                    u1, v1, u2, v2,
 
262
                                    &m, alpha, supersample, recursion_level,
 
263
                                    bg_color, progress);
 
264
      break;
 
265
 
 
266
    case GIMP_INTERPOLATION_CUBIC:
 
267
      gimp_transform_region_cubic (orig_tiles, destPR,
 
268
                                   dest_x1, dest_y1, dest_x2, dest_y2,
 
269
                                   u1, v1, u2, v2,
 
270
                                   &m, alpha, supersample, recursion_level,
 
271
                                   bg_color, progress);
 
272
      break;
 
273
 
 
274
    case GIMP_INTERPOLATION_LANCZOS:
 
275
      gimp_transform_region_lanczos (orig_tiles, destPR,
 
276
                                     dest_x1, dest_y1, dest_x2, dest_y2,
 
277
                                     u1, v1, u2, v2,
 
278
                                     &m, alpha, supersample, recursion_level,
 
279
                                     bg_color, progress);
 
280
      break;
 
281
    }
 
282
}
 
283
 
 
284
static void
 
285
gimp_transform_region_nearest (TileManager        *orig_tiles,
 
286
                               PixelRegion        *destPR,
 
287
                               gint                dest_x1,
 
288
                               gint                dest_y1,
 
289
                               gint                dest_x2,
 
290
                               gint                dest_y2,
 
291
                               gint                u1,
 
292
                               gint                v1,
 
293
                               gint                u2,
 
294
                               gint                v2,
 
295
                               const GimpMatrix3  *m,
 
296
                               gint                alpha,
 
297
                               const guchar       *bg_color,
 
298
                               GimpProgress       *progress)
 
299
{
 
300
  gdouble   uinc, vinc, winc;  /* increments in source coordinates  */
 
301
  gint      pixels;
 
302
  gint      total;
 
303
  gint      n;
 
304
  gpointer  pr;
 
305
 
 
306
  uinc = m->coeff[0][0];
 
307
  vinc = m->coeff[1][0];
 
308
  winc = m->coeff[2][0];
 
309
 
 
310
  total = destPR->w * destPR->h;
 
311
 
 
312
  for (pr = pixel_regions_register (1, destPR), pixels = 0, n = 0;
 
313
       pr != NULL;
 
314
       pr = pixel_regions_process (pr), n++)
 
315
    {
 
316
      guchar *dest = destPR->data;
 
317
      gint    y;
 
318
 
 
319
      for (y = destPR->y; y < destPR->y + destPR->h; y++)
 
320
        {
 
321
          gint     x     = dest_x1 + destPR->x;
 
322
          gint     width = destPR->w;
 
323
          guchar  *d     = dest;
 
324
          gdouble  tu, tv, tw;   /* undivided source coordinates and divisor */
 
325
 
 
326
          /* set up inverse transform steps */
 
327
          tu = uinc * x + m->coeff[0][1] * (dest_y1 + y) + m->coeff[0][2];
 
328
          tv = vinc * x + m->coeff[1][1] * (dest_y1 + y) + m->coeff[1][2];
 
329
          tw = winc * x + m->coeff[2][1] * (dest_y1 + y) + m->coeff[2][2];
 
330
 
 
331
          while (width--)
 
332
            {
 
333
              gdouble u, v; /* source coordinates */
 
334
              gint    iu, iv;
 
335
 
 
336
              /*  normalize homogeneous coords  */
 
337
              normalize_coords (1, &tu, &tv, &tw, &u, &v);
 
338
 
 
339
              iu = (gint) u;
 
340
              iv = (gint) v;
 
341
 
 
342
              /*  Set the destination pixels  */
 
343
              if (iu >= u1 && iu < u2 &&
 
344
                  iv >= v1 && iv < v2)
 
345
                {
 
346
                  read_pixel_data_1 (orig_tiles, iu - u1, iv - v1, d);
 
347
 
 
348
                  d += destPR->bytes;
 
349
                }
 
350
              else /* not in source range */
 
351
                {
 
352
                  gint b;
 
353
 
 
354
                  for (b = 0; b < destPR->bytes; b++)
 
355
                    *d++ = bg_color[b];
 
356
                }
 
357
 
 
358
              tu += uinc;
 
359
              tv += vinc;
 
360
              tw += winc;
 
361
            }
 
362
 
 
363
          dest += destPR->rowstride;
 
364
        }
 
365
 
 
366
      if (progress)
 
367
        {
 
368
          pixels += destPR->w * destPR->h;
 
369
 
 
370
          if (n % 16 == 0)
 
371
            gimp_progress_set_value (progress,
 
372
                                     (gdouble) pixels / (gdouble) total);
 
373
        }
 
374
    }
 
375
}
 
376
 
 
377
static void
 
378
gimp_transform_region_linear (TileManager        *orig_tiles,
 
379
                              PixelRegion        *destPR,
 
380
                              gint                dest_x1,
 
381
                              gint                dest_y1,
 
382
                              gint                dest_x2,
 
383
                              gint                dest_y2,
 
384
                              gint                u1,
 
385
                              gint                v1,
 
386
                              gint                u2,
 
387
                              gint                v2,
 
388
                              const GimpMatrix3  *m,
 
389
                              gint                alpha,
 
390
                              gboolean            supersample,
 
391
                              gint                recursion_level,
 
392
                              const guchar       *bg_color,
 
393
                              GimpProgress       *progress)
 
394
{
 
395
  PixelSurround *surround;
 
396
  gdouble        uinc, vinc, winc;  /* increments in source coordinates  */
 
397
  gint           pixels;
 
398
  gint           total;
 
399
  gint           n;
 
400
  gpointer       pr;
 
401
 
 
402
  surround = pixel_surround_new (orig_tiles, 2, 2, bg_color);
 
403
 
 
404
  uinc = m->coeff[0][0];
 
405
  vinc = m->coeff[1][0];
 
406
  winc = m->coeff[2][0];
 
407
 
 
408
  total = destPR->w * destPR->h;
 
409
 
 
410
  for (pr = pixel_regions_register (1, destPR), pixels = 0, n = 0;
 
411
       pr != NULL;
 
412
       pr = pixel_regions_process (pr), n++)
 
413
    {
 
414
      guchar *dest = destPR->data;
 
415
      gint    y;
 
416
 
 
417
      for (y = destPR->y; y < destPR->y + destPR->h; y++)
 
418
        {
 
419
          guchar  *d     = dest;
 
420
          gint     width = destPR->w;
 
421
          gdouble  tu[5], tv[5];   /* undivided source coordinates */
 
422
          gdouble  tw[5];          /* divisor                      */
 
423
 
 
424
          /* set up inverse transform steps */
 
425
          untransform_coords (m, dest_x1 + destPR->x, dest_y1 + y, tu, tv, tw);
 
426
 
 
427
          while (width--)
 
428
            {
 
429
              gdouble u[5], v[5]; /* source coordinates */
 
430
              gint    i;
 
431
 
 
432
              /*  normalize homogeneous coords  */
 
433
              normalize_coords (5, tu, tv, tw, u, v);
 
434
 
 
435
              /*  Set the destination pixels  */
 
436
              if (supersample &&
 
437
                  supersample_dtest (u[1], v[1], u[2], v[2],
 
438
                                     u[3], v[3], u[4], v[4]))
 
439
                {
 
440
                  sample_adapt (orig_tiles,
 
441
                                u[0] - u1, v[0] - v1,
 
442
                                u[1] - u1, v[1] - v1,
 
443
                                u[2] - u1, v[2] - v1,
 
444
                                u[3] - u1, v[3] - v1,
 
445
                                u[4] - u1, v[4] - v1,
 
446
                                recursion_level,
 
447
                                d, bg_color, destPR->bytes, alpha);
 
448
                }
 
449
              else
 
450
                {
 
451
                  sample_linear (surround, u[0] - u1, v[0] - v1,
 
452
                                 d, destPR->bytes, alpha);
 
453
                }
 
454
 
 
455
              d += destPR->bytes;
 
456
 
 
457
              for (i = 0; i < 5; i++)
 
458
                {
 
459
                  tu[i] += uinc;
 
460
                  tv[i] += vinc;
 
461
                  tw[i] += winc;
 
462
                }
 
463
            }
 
464
 
 
465
          dest += destPR->rowstride;
 
466
        }
 
467
 
 
468
      if (progress)
 
469
        {
 
470
          pixels += destPR->w * destPR->h;
 
471
 
 
472
          if (n % 16 == 0)
 
473
            gimp_progress_set_value (progress,
 
474
                                     (gdouble) pixels / (gdouble) total);
 
475
        }
 
476
    }
 
477
 
 
478
  pixel_surround_destroy (surround);
 
479
}
 
480
 
 
481
static void
 
482
gimp_transform_region_cubic (TileManager        *orig_tiles,
 
483
                             PixelRegion        *destPR,
 
484
                             gint                dest_x1,
 
485
                             gint                dest_y1,
 
486
                             gint                dest_x2,
 
487
                             gint                dest_y2,
 
488
                             gint                u1,
 
489
                             gint                v1,
 
490
                             gint                u2,
 
491
                             gint                v2,
 
492
                             const GimpMatrix3  *m,
 
493
                             gint                alpha,
 
494
                             gboolean            supersample,
 
495
                             gint                recursion_level,
 
496
                             const guchar       *bg_color,
 
497
                             GimpProgress       *progress)
 
498
{
 
499
  PixelSurround *surround;
 
500
  gdouble        uinc, vinc, winc;  /* increments in source coordinates  */
 
501
  gint           pixels;
 
502
  gint           total;
 
503
  gint           n;
 
504
  gpointer       pr;
 
505
 
 
506
  surround = pixel_surround_new (orig_tiles, 4, 4, bg_color);
 
507
 
 
508
  uinc = m->coeff[0][0];
 
509
  vinc = m->coeff[1][0];
 
510
  winc = m->coeff[2][0];
 
511
 
 
512
  total = destPR->w * destPR->h;
 
513
 
 
514
  for (pr = pixel_regions_register (1, destPR), pixels = 0, n = 0;
 
515
       pr != NULL;
 
516
       pr = pixel_regions_process (pr), n++)
 
517
    {
 
518
      guchar *dest = destPR->data;
 
519
      gint    y;
 
520
 
 
521
      for (y = destPR->y; y < destPR->y + destPR->h; y++)
 
522
        {
 
523
          guchar  *d     = dest;
 
524
          gint     width = destPR->w;
 
525
          gdouble  tu[5], tv[5];   /* undivided source coordinates */
 
526
          gdouble  tw[5];          /* divisor                      */
 
527
 
 
528
          /* set up inverse transform steps */
 
529
          untransform_coords (m, dest_x1 + destPR->x, dest_y1 + y, tu, tv, tw);
 
530
 
 
531
          while (width--)
 
532
            {
 
533
              gdouble u[5], v[5]; /* source coordinates */
 
534
              gint    i;
 
535
 
 
536
              /*  normalize homogeneous coords  */
 
537
              normalize_coords (5, tu, tv, tw, u, v);
 
538
 
 
539
              if (supersample &&
 
540
                  supersample_dtest (u[1], v[1], u[2], v[2],
 
541
                                     u[3], v[3], u[4], v[4]))
 
542
                {
 
543
                  sample_adapt (orig_tiles,
 
544
                                u[0] - u1, v[0] - v1,
 
545
                                u[1] - u1, v[1] - v1,
 
546
                                u[2] - u1, v[2] - v1,
 
547
                                u[3] - u1, v[3] - v1,
 
548
                                u[4] - u1, v[4] - v1,
 
549
                                recursion_level,
 
550
                                d, bg_color, destPR->bytes, alpha);
 
551
                }
 
552
              else
 
553
                {
 
554
                  sample_cubic (surround, u[0] - u1, v[0] - v1,
 
555
                                d, destPR->bytes, alpha);
 
556
                }
 
557
 
 
558
              d += destPR->bytes;
 
559
 
 
560
              for (i = 0; i < 5; i++)
 
561
                {
 
562
                  tu[i] += uinc;
 
563
                  tv[i] += vinc;
 
564
                  tw[i] += winc;
 
565
                }
 
566
            }
 
567
 
 
568
          dest += destPR->rowstride;
 
569
        }
 
570
 
 
571
      if (progress)
 
572
        {
 
573
          pixels += destPR->w * destPR->h;
 
574
 
 
575
          if (n % 16 == 0)
 
576
            gimp_progress_set_value (progress,
 
577
                                     (gdouble) pixels / (gdouble) total);
 
578
        }
 
579
    }
 
580
 
 
581
  pixel_surround_destroy (surround);
 
582
}
 
583
 
 
584
static void
 
585
gimp_transform_region_lanczos (TileManager       *orig_tiles,
 
586
                               PixelRegion       *destPR,
 
587
                               gint               dest_x1,
 
588
                               gint               dest_y1,
 
589
                               gint               dest_x2,
 
590
                               gint               dest_y2,
 
591
                               gint               u1,
 
592
                               gint               v1,
 
593
                               gint               u2,
 
594
                               gint               v2,
 
595
                               const GimpMatrix3 *m,
 
596
                               gint               alpha,
 
597
                               gboolean           supersample,
 
598
                               gint               recursion_level,
 
599
                               const guchar      *bg_color,
 
600
                               GimpProgress      *progress)
 
601
{
 
602
  PixelSurround *surround;
 
603
  gfloat        *lanczos;           /* Lanczos lookup table              */
 
604
  gdouble        uinc, vinc, winc;  /* increments in source coordinates  */
 
605
  gint           pixels;
 
606
  gint           total;
 
607
  gint           n;
 
608
  gpointer       pr;
 
609
 
 
610
  surround = pixel_surround_new (orig_tiles,
 
611
                                 LANCZOS_WIDTH2, LANCZOS_WIDTH2, bg_color);
 
612
 
 
613
  /* allocate and fill lanczos lookup table */
 
614
  lanczos = create_lanczos_lookup ();
 
615
 
 
616
  uinc = m->coeff[0][0];
 
617
  vinc = m->coeff[1][0];
 
618
  winc = m->coeff[2][0];
 
619
 
 
620
  total = destPR->w * destPR->h;
 
621
 
 
622
  for (pr = pixel_regions_register (1, destPR), pixels = 0, n = 0;
 
623
       pr != NULL;
 
624
       pr = pixel_regions_process (pr), n++)
 
625
    {
 
626
      guchar *dest = destPR->data;
 
627
      gint    y;
 
628
 
 
629
      for (y = destPR->y; y < destPR->y + destPR->h; y++)
 
630
        {
 
631
          guchar  *d     = dest;
 
632
          gint     width = destPR->w;
 
633
          gdouble  tu[5], tv[5];   /* undivided source coordinates */
 
634
          gdouble  tw[5];          /* divisor                      */
 
635
 
 
636
          /* set up inverse transform steps */
 
637
          untransform_coords (m, dest_x1 + destPR->x, dest_y1 + y, tu, tv, tw);
 
638
 
 
639
          while (width--)
 
640
            {
 
641
              gdouble u[5], v[5]; /* source coordinates */
 
642
              gint    i;
 
643
 
 
644
              /*  normalize homogeneous coords  */
 
645
              normalize_coords (5, tu, tv, tw, u, v);
 
646
 
 
647
              if (supersample &&
 
648
                  supersample_dtest (u[1], v[1], u[2], v[2],
 
649
                                     u[3], v[3], u[4], v[4]))
 
650
                {
 
651
                  sample_adapt (orig_tiles,
 
652
                                u[0] - u1, v[0] - v1,
 
653
                                u[1] - u1, v[1] - v1,
 
654
                                u[2] - u1, v[2] - v1,
 
655
                                u[3] - u1, v[3] - v1,
 
656
                                u[4] - u1, v[4] - v1,
 
657
                                recursion_level,
 
658
                                d, bg_color, destPR->bytes, alpha);
 
659
                }
 
660
              else
 
661
                {
 
662
                  sample_lanczos (surround, lanczos, u[0] - u1, v[0] - v1,
 
663
                                  d, destPR->bytes, alpha);
 
664
                }
 
665
 
 
666
              d += destPR->bytes;
 
667
 
 
668
              for (i = 0; i < 5; i++)
 
669
                {
 
670
                  tu[i] += uinc;
 
671
                  tv[i] += vinc;
 
672
                  tw[i] += winc;
 
673
                }
 
674
            }
 
675
 
 
676
          dest += destPR->rowstride;
 
677
        }
 
678
 
 
679
      if (progress)
 
680
        {
 
681
          pixels += destPR->w * destPR->h;
 
682
 
 
683
          if (n % 16 == 0)
 
684
            gimp_progress_set_value (progress,
 
685
                                     (gdouble) pixels / (gdouble) total);
 
686
        }
 
687
   }
 
688
 
 
689
  g_free (lanczos);
 
690
  pixel_surround_destroy (surround);
 
691
}
 
692
 
 
693
 
 
694
/*  private functions  */
 
695
 
 
696
static inline void
 
697
untransform_coords (const GimpMatrix3 *m,
 
698
                    gint               x,
 
699
                    gint               y,
 
700
                    gdouble           *tu,
 
701
                    gdouble           *tv,
 
702
                    gdouble           *tw)
 
703
{
 
704
  tu[0] = m->coeff[0][0] * (x    ) + m->coeff[0][1] * (y    ) + m->coeff[0][2];
 
705
  tv[0] = m->coeff[1][0] * (x    ) + m->coeff[1][1] * (y    ) + m->coeff[1][2];
 
706
  tw[0] = m->coeff[2][0] * (x    ) + m->coeff[2][1] * (y    ) + m->coeff[2][2];
 
707
 
 
708
  tu[1] = m->coeff[0][0] * (x - 1) + m->coeff[0][1] * (y    ) + m->coeff[0][2];
 
709
  tv[1] = m->coeff[1][0] * (x - 1) + m->coeff[1][1] * (y    ) + m->coeff[1][2];
 
710
  tw[1] = m->coeff[2][0] * (x - 1) + m->coeff[2][1] * (y    ) + m->coeff[2][2];
 
711
 
 
712
  tu[2] = m->coeff[0][0] * (x    ) + m->coeff[0][1] * (y - 1) + m->coeff[0][2];
 
713
  tv[2] = m->coeff[1][0] * (x    ) + m->coeff[1][1] * (y - 1) + m->coeff[1][2];
 
714
  tw[2] = m->coeff[2][0] * (x    ) + m->coeff[2][1] * (y - 1) + m->coeff[2][2];
 
715
 
 
716
  tu[3] = m->coeff[0][0] * (x + 1) + m->coeff[0][1] * (y    ) + m->coeff[0][2];
 
717
  tv[3] = m->coeff[1][0] * (x + 1) + m->coeff[1][1] * (y    ) + m->coeff[1][2];
 
718
  tw[3] = m->coeff[2][0] * (x + 1) + m->coeff[2][1] * (y    ) + m->coeff[2][2];
 
719
 
 
720
  tu[4] = m->coeff[0][0] * (x    ) + m->coeff[0][1] * (y + 1) + m->coeff[0][2];
 
721
  tv[4] = m->coeff[1][0] * (x    ) + m->coeff[1][1] * (y + 1) + m->coeff[1][2];
 
722
  tw[4] = m->coeff[2][0] * (x    ) + m->coeff[2][1] * (y + 1) + m->coeff[2][2];
 
723
}
 
724
 
 
725
static inline void
 
726
normalize_coords (const gint     coords,
 
727
                  const gdouble *tu,
 
728
                  const gdouble *tv,
 
729
                  const gdouble *tw,
 
730
                  gdouble       *u,
 
731
                  gdouble       *v)
 
732
{
 
733
  gint i;
 
734
 
 
735
  for (i = 0; i < coords; i++)
 
736
    {
 
737
      if (G_LIKELY (tw[i] != 0.0))
 
738
        {
 
739
          u[i] = tu[i] / tw[i];
 
740
          v[i] = tv[i] / tw[i];
 
741
        }
 
742
      else
 
743
        {
 
744
          g_warning ("homogeneous coordinate = 0...\n");
 
745
 
 
746
          u[i] = tu[i];
 
747
          v[i] = tv[i];
 
748
        }
 
749
    }
 
750
}
 
751
 
 
752
 
 
753
#define BILINEAR(jk, j1k, jk1, j1k1, dx, dy) \
 
754
                ((1 - dy) * (jk  + dx * (j1k  - jk)) + \
 
755
                      dy  * (jk1 + dx * (j1k1 - jk1)))
 
756
 
 
757
  /*  u & v are the subpixel coordinates of the point in
 
758
   *  the original selection's floating buffer.
 
759
   *  We need the two pixel coords around them:
 
760
   *  iu to iu + 1, iv to iv + 1
 
761
   */
 
762
static void
 
763
sample_linear (PixelSurround *surround,
 
764
               gdouble        u,
 
765
               gdouble        v,
 
766
               guchar        *color,
 
767
               gint           bytes,
 
768
               gint           alpha)
 
769
{
 
770
  gdouble       a_val, a_recip;
 
771
  gint          i;
 
772
  gint          iu = floor (u);
 
773
  gint          iv = floor (v);
 
774
  gint          rowstride;
 
775
  gdouble       du, dv;
 
776
  const guchar *alphachan;
 
777
  const guchar *data;
 
778
 
 
779
  /* lock the pixel surround */
 
780
  data = pixel_surround_lock (surround, iu, iv, &rowstride);
 
781
 
 
782
  /* the fractional error */
 
783
  du = u - iu;
 
784
  dv = v - iv;
 
785
 
 
786
  /* calculate alpha value of result pixel */
 
787
  alphachan = &data[alpha];
 
788
  a_val = BILINEAR (alphachan[0],         alphachan[bytes],
 
789
                    alphachan[rowstride], alphachan[rowstride + bytes], du, dv);
 
790
 
 
791
  if (a_val <= 0.0)
 
792
    {
 
793
      a_recip = 0.0;
 
794
      color[alpha] = 0.0;
 
795
    }
 
796
  else if (a_val >= 255.0)
 
797
    {
 
798
      a_recip = 1.0 / a_val;
 
799
      color[alpha] = 255;
 
800
    }
 
801
  else
 
802
    {
 
803
      a_recip = 1.0 / a_val;
 
804
      color[alpha] = RINT (a_val);
 
805
    }
 
806
 
 
807
  /*  for colour channels c,
 
808
   *  result = bilinear (c * alpha) / bilinear (alpha)
 
809
   *
 
810
   *  never entered for alpha == 0
 
811
   */
 
812
  for (i = 0; i < alpha; i++)
 
813
    {
 
814
      gint newval;
 
815
 
 
816
      newval = (a_recip *
 
817
                BILINEAR (alphachan[0]                 * data[i],
 
818
                          alphachan[bytes]             * data[bytes + i],
 
819
                          alphachan[rowstride]         * data[rowstride + i],
 
820
                          alphachan[rowstride + bytes] * data[rowstride + bytes + i],
 
821
                          du, dv));
 
822
 
 
823
      color[i] = CLAMP (newval, 0, 255);
 
824
    }
 
825
}
 
826
 
 
827
/* macros to handle conversion to/from fixed point, this fixed point code
 
828
 * uses signed integers, by using 8 bits for the fractional part we have
 
829
 *
 
830
 *  1 bit  sign
 
831
 * 21 bits integer part
 
832
 *  8 bit  fractional part
 
833
 *
 
834
 * 1023 discrete subpixel sample positions should be enough for the needs
 
835
 * of the supersampling algorithm, drawables where the dimensions have a need
 
836
 * exceeding 2^21 ( 2097152px, will typically use terabytes of memory, when
 
837
 * that is the common need, we can probably assume 64 bit integers and adjust
 
838
 * FIXED_SHIFT accordingly.
 
839
 */
 
840
#define FIXED_SHIFT          10
 
841
#define FIXED_UNIT           (1 << FIXED_SHIFT)
 
842
#define DOUBLE2FIXED(val)    ((val) * FIXED_UNIT)
 
843
#define FIXED2DOUBLE(val)    ((val) / FIXED_UNIT)
 
844
 
 
845
/*
 
846
    bilinear interpolation of a fixed point pixel
 
847
*/
 
848
static void
 
849
sample_bi (TileManager  *tm,
 
850
           gint          x,
 
851
           gint          y,
 
852
           guchar       *color,
 
853
           const guchar *bg_color,
 
854
           gint          bpp,
 
855
           gint          alpha)
 
856
{
 
857
  guchar C[4][4];
 
858
  gint   i;
 
859
  gint   xscale = (x & (FIXED_UNIT-1));
 
860
  gint   yscale = (y & (FIXED_UNIT-1));
 
861
 
 
862
  gint   x0 = x >> FIXED_SHIFT;
 
863
  gint   y0 = y >> FIXED_SHIFT;
 
864
  gint   x1 = x0 + 1;
 
865
  gint   y1 = y0 + 1;
 
866
 
 
867
 
 
868
  /*  fill the color with default values, since read_pixel_data_1
 
869
   *  does nothing, when accesses are out of bounds.
 
870
   */
 
871
  for (i = 0; i < 4; i++)
 
872
    *(guint*) (&C[i]) = *(guint*) (bg_color);
 
873
 
 
874
  read_pixel_data_1 (tm, x0, y0, C[0]);
 
875
  read_pixel_data_1 (tm, x1, y0, C[2]);
 
876
  read_pixel_data_1 (tm, x0, y1, C[1]);
 
877
  read_pixel_data_1 (tm, x1, y1, C[3]);
 
878
 
 
879
#define lerp(v1, v2, r) \
 
880
        (((guint)(v1) * (FIXED_UNIT - (guint)(r)) + \
 
881
          (guint)(v2) * (guint)(r)) >> FIXED_SHIFT)
 
882
 
 
883
  color[alpha]= lerp (lerp (C[0][alpha], C[1][alpha], yscale),
 
884
                      lerp (C[2][alpha], C[3][alpha], yscale), xscale);
 
885
 
 
886
  if (color[alpha])
 
887
    { /* to avoid problems, calculate with premultiplied alpha */
 
888
      for (i = 0; i < alpha; i++)
 
889
        {
 
890
          C[0][i] = (C[0][i] * C[0][alpha] / 255);
 
891
          C[1][i] = (C[1][i] * C[1][alpha] / 255);
 
892
          C[2][i] = (C[2][i] * C[2][alpha] / 255);
 
893
          C[3][i] = (C[3][i] * C[3][alpha] / 255);
 
894
        }
 
895
 
 
896
      for (i = 0; i < alpha; i++)
 
897
        color[i] = lerp (lerp (C[0][i], C[1][i], yscale),
 
898
                         lerp (C[2][i], C[3][i], yscale), xscale);
 
899
    }
 
900
  else
 
901
    {
 
902
      for (i = 0; i < alpha; i++)
 
903
        color[i] = 0;
 
904
    }
 
905
#undef lerp
 
906
}
 
907
 
 
908
 
 
909
 
 
910
/*
 
911
 * Returns TRUE if one of the deltas of the
 
912
 * quad edge is > 1.0 (16.16 fixed values).
 
913
 */
 
914
static inline gboolean
 
915
supersample_test (gint x0, gint y0,
 
916
                  gint x1, gint y1,
 
917
                  gint x2, gint y2,
 
918
                  gint x3, gint y3)
 
919
{
 
920
  return (abs (x0 - x1) > FIXED_UNIT ||
 
921
          abs (x1 - x2) > FIXED_UNIT ||
 
922
          abs (x2 - x3) > FIXED_UNIT ||
 
923
          abs (x3 - x0) > FIXED_UNIT ||
 
924
 
 
925
          abs (y0 - y1) > FIXED_UNIT ||
 
926
          abs (y1 - y2) > FIXED_UNIT ||
 
927
          abs (y2 - y3) > FIXED_UNIT ||
 
928
          abs (y3 - y0) > FIXED_UNIT);
 
929
}
 
930
 
 
931
/*
 
932
 *  Returns TRUE if one of the deltas of the
 
933
 *  quad edge is > 1.0 (double values).
 
934
 */
 
935
static inline gboolean
 
936
supersample_dtest (gdouble x0, gdouble y0,
 
937
                   gdouble x1, gdouble y1,
 
938
                   gdouble x2, gdouble y2,
 
939
                   gdouble x3, gdouble y3)
 
940
{
 
941
  return (fabs (x0 - x1) > 1.0 ||
 
942
          fabs (x1 - x2) > 1.0 ||
 
943
          fabs (x2 - x3) > 1.0 ||
 
944
          fabs (x3 - x0) > 1.0 ||
 
945
 
 
946
          fabs (y0 - y1) > 1.0 ||
 
947
          fabs (y1 - y2) > 1.0 ||
 
948
          fabs (y2 - y3) > 1.0 ||
 
949
          fabs (y3 - y0) > 1.0);
 
950
}
 
951
 
 
952
/*
 
953
    sample a grid that is spaced according to the quadraliteral's edges,
 
954
    it subdivides a maximum of level times before sampling.
 
955
    0..3 is a cycle around the quad
 
956
*/
 
957
static void
 
958
get_sample (TileManager  *tm,
 
959
            gint          xc,
 
960
            gint          yc,
 
961
            gint          x0,
 
962
            gint          y0,
 
963
            gint          x1,
 
964
            gint          y1,
 
965
            gint          x2,
 
966
            gint          y2,
 
967
            gint          x3,
 
968
            gint          y3,
 
969
            gint         *cc,
 
970
            gint          level,
 
971
            guint        *color,
 
972
            const guchar *bg_color,
 
973
            gint          bpp,
 
974
            gint          alpha)
 
975
{
 
976
  if (!level || !supersample_test (x0, y0, x1, y1, x2, y2, x3, y3))
 
977
    {
 
978
      gint   i;
 
979
      guchar C[4];
 
980
 
 
981
      sample_bi (tm, xc, yc, C, bg_color, bpp, alpha);
 
982
 
 
983
      for (i = 0; i < bpp; i++)
 
984
        color[i]+= C[i];
 
985
 
 
986
      (*cc)++;  /* increase number of samples taken */
 
987
    }
 
988
  else
 
989
    {
 
990
      gint tx, lx, rx, bx, tlx, trx, blx, brx;
 
991
      gint ty, ly, ry, by, tly, try, bly, bry;
 
992
 
 
993
      /* calculate subdivided corner coordinates (including centercoords
 
994
         thus using a bilinear interpolation,. almost as good as
 
995
         doing the perspective transform for each subpixel coordinate*/
 
996
 
 
997
      tx  = (x0 + x1) / 2;
 
998
      tlx = (x0 + xc) / 2;
 
999
      trx = (x1 + xc) / 2;
 
1000
      lx  = (x0 + x3) / 2;
 
1001
      rx  = (x1 + x2) / 2;
 
1002
      blx = (x3 + xc) / 2;
 
1003
      brx = (x2 + xc) / 2;
 
1004
      bx  = (x3 + x2) / 2;
 
1005
 
 
1006
      ty  = (y0 + y1) / 2;
 
1007
      tly = (y0 + yc) / 2;
 
1008
      try = (y1 + yc) / 2;
 
1009
      ly  = (y0 + y3) / 2;
 
1010
      ry  = (y1 + y2) / 2;
 
1011
      bly = (y3 + yc) / 2;
 
1012
      bry = (y2 + yc) / 2;
 
1013
      by  = (y3 + y2) / 2;
 
1014
 
 
1015
      get_sample (tm,
 
1016
                  tlx,tly,
 
1017
                  x0,y0, tx,ty, xc,yc, lx,ly,
 
1018
                  cc, level-1, color, bg_color, bpp, alpha);
 
1019
 
 
1020
      get_sample (tm,
 
1021
                  trx,try,
 
1022
                  tx,ty, x1,y1, rx,ry, xc,yc,
 
1023
                  cc, level-1, color, bg_color, bpp, alpha);
 
1024
 
 
1025
      get_sample (tm,
 
1026
                  brx,bry,
 
1027
                  xc,yc, rx,ry, x2,y2, bx,by,
 
1028
                  cc, level-1, color, bg_color, bpp, alpha);
 
1029
 
 
1030
      get_sample (tm,
 
1031
                  blx,bly,
 
1032
                  lx,ly, xc,yc, bx,by, x3,y3,
 
1033
                  cc, level-1, color, bg_color, bpp, alpha);
 
1034
    }
 
1035
}
 
1036
 
 
1037
static void
 
1038
sample_adapt (TileManager  *tm,
 
1039
              gdouble       xc,
 
1040
              gdouble       yc,
 
1041
              gdouble       x0,
 
1042
              gdouble       y0,
 
1043
              gdouble       x1,
 
1044
              gdouble       y1,
 
1045
              gdouble       x2,
 
1046
              gdouble       y2,
 
1047
              gdouble       x3,
 
1048
              gdouble       y3,
 
1049
              gint          level,
 
1050
              guchar       *color,
 
1051
              const guchar *bg_color,
 
1052
              gint          bpp,
 
1053
              gint          alpha)
 
1054
{
 
1055
    gint  cc = 0;
 
1056
    gint  i;
 
1057
    guint C[MAX_CHANNELS];
 
1058
 
 
1059
    C[0] = C[1] = C[2] = C[3] = 0;
 
1060
 
 
1061
    get_sample (tm,
 
1062
                DOUBLE2FIXED (xc), DOUBLE2FIXED (yc),
 
1063
                DOUBLE2FIXED (x0), DOUBLE2FIXED (y0),
 
1064
                DOUBLE2FIXED (x1), DOUBLE2FIXED (y1),
 
1065
                DOUBLE2FIXED (x2), DOUBLE2FIXED (y2),
 
1066
                DOUBLE2FIXED (x3), DOUBLE2FIXED (y3),
 
1067
                &cc, level, C, bg_color, bpp, alpha);
 
1068
 
 
1069
    if (!cc)
 
1070
      cc=1;
 
1071
 
 
1072
    color[alpha] = C[alpha] / cc;
 
1073
 
 
1074
    if (color[alpha])
 
1075
      {
 
1076
         /* go from premultiplied to postmultiplied alpha */
 
1077
        for (i = 0; i < alpha; i++)
 
1078
          color[i] = ((C[i] / cc) * 255) / color[alpha];
 
1079
      }
 
1080
    else
 
1081
      {
 
1082
        for (i = 0; i < alpha; i++)
 
1083
          color[i] = 0;
 
1084
      }
 
1085
}
 
1086
 
 
1087
/* access interleaved pixels */
 
1088
#define CUBIC_ROW(dx, row, step) \
 
1089
  gimp_drawable_transform_cubic(dx,\
 
1090
            (row)[0], (row)[step], (row)[step+step], (row)[step+step+step])
 
1091
 
 
1092
#define CUBIC_SCALED_ROW(dx, row, arow, step) \
 
1093
  gimp_drawable_transform_cubic(dx, \
 
1094
            (arow)[0]              * (row)[0], \
 
1095
            (arow)[step]           * (row)[step], \
 
1096
            (arow)[step+step]      * (row)[step+step], \
 
1097
            (arow)[step+step+step] * (row)[step+step+step])
 
1098
 
 
1099
 
 
1100
/*  Note: cubic function no longer clips result. */
 
1101
/*  Inlining this function makes sample_cubic() run about 10% faster. (Sven) */
 
1102
static inline gdouble
 
1103
gimp_drawable_transform_cubic (gdouble dx,
 
1104
                               gint    jm1,
 
1105
                               gint    j,
 
1106
                               gint    jp1,
 
1107
                               gint    jp2)
 
1108
{
 
1109
  gdouble result;
 
1110
 
 
1111
#if 0
 
1112
  /* Equivalent to Gimp 1.1.1 and earlier - some ringing */
 
1113
  result = ((( ( - jm1 + j - jp1 + jp2 ) * dx +
 
1114
               ( jm1 + jm1 - j - j + jp1 - jp2 ) ) * dx +
 
1115
               ( - jm1 + jp1 ) ) * dx + j );
 
1116
  /* Recommended by Mitchell and Netravali - too blurred? */
 
1117
  result = ((( ( - 7 * jm1 + 21 * j - 21 * jp1 + 7 * jp2 ) * dx +
 
1118
               ( 15 * jm1 - 36 * j + 27 * jp1 - 6 * jp2 ) ) * dx +
 
1119
               ( - 9 * jm1 + 9 * jp1 ) ) * dx + (jm1 + 16 * j + jp1) ) / 18.0;
 
1120
#endif
 
1121
 
 
1122
  /* Catmull-Rom - not bad */
 
1123
  result = ((( ( - jm1 + 3 * j - 3 * jp1 + jp2 ) * dx +
 
1124
               ( 2 * jm1 - 5 * j + 4 * jp1 - jp2 ) ) * dx +
 
1125
               ( - jm1 + jp1 ) ) * dx + (j + j) ) / 2.0;
 
1126
 
 
1127
  return result;
 
1128
}
 
1129
 
 
1130
 
 
1131
  /*  u & v are the subpixel coordinates of the point in
 
1132
   *  the original selection's floating buffer.
 
1133
   *  We need the four integer pixel coords around them:
 
1134
   *  iu to iu + 3, iv to iv + 3
 
1135
   */
 
1136
static void
 
1137
sample_cubic (PixelSurround *surround,
 
1138
              gdouble        u,
 
1139
              gdouble        v,
 
1140
              guchar        *color,
 
1141
              gint           bytes,
 
1142
              gint           alpha)
 
1143
{
 
1144
  gdouble       a_val, a_recip;
 
1145
  gint          i;
 
1146
  gint          iu = floor(u);
 
1147
  gint          iv = floor(v);
 
1148
  gint          rowstride;
 
1149
  gdouble       du, dv;
 
1150
  const guchar *data;
 
1151
 
 
1152
  /* lock the pixel surround */
 
1153
  data = pixel_surround_lock (surround, iu - 1 , iv - 1, &rowstride);
 
1154
 
 
1155
  /* the fractional error */
 
1156
  du = u - iu;
 
1157
  dv = v - iv;
 
1158
 
 
1159
  /* calculate alpha of result */
 
1160
  a_val = gimp_drawable_transform_cubic
 
1161
    (dv,
 
1162
     CUBIC_ROW (du, data + alpha + rowstride * 0, bytes),
 
1163
     CUBIC_ROW (du, data + alpha + rowstride * 1, bytes),
 
1164
     CUBIC_ROW (du, data + alpha + rowstride * 2, bytes),
 
1165
     CUBIC_ROW (du, data + alpha + rowstride * 3, bytes));
 
1166
 
 
1167
  if (a_val <= 0.0)
 
1168
    {
 
1169
      a_recip = 0.0;
 
1170
      color[alpha] = 0;
 
1171
    }
 
1172
  else if (a_val > 255.0)
 
1173
    {
 
1174
      a_recip = 1.0 / a_val;
 
1175
      color[alpha] = 255;
 
1176
    }
 
1177
  else
 
1178
    {
 
1179
      a_recip = 1.0 / a_val;
 
1180
      color[alpha] = RINT (a_val);
 
1181
    }
 
1182
 
 
1183
  /*  for colour channels c,
 
1184
   *  result = bicubic (c * alpha) / bicubic (alpha)
 
1185
   *
 
1186
   *  never entered for alpha == 0
 
1187
   */
 
1188
  for (i = 0; i < alpha; i++)
 
1189
    {
 
1190
      gint newval = (a_recip *
 
1191
                     gimp_drawable_transform_cubic
 
1192
                     (dv,
 
1193
                      CUBIC_SCALED_ROW (du,
 
1194
                                        i + data + rowstride * 0,
 
1195
                                        data + alpha + rowstride * 0,
 
1196
                                        bytes),
 
1197
                      CUBIC_SCALED_ROW (du,
 
1198
                                        i + data + rowstride * 1,
 
1199
                                        data + alpha + rowstride * 1,
 
1200
                                        bytes),
 
1201
                      CUBIC_SCALED_ROW (du,
 
1202
                                        i + data + rowstride * 2,
 
1203
                                        data + alpha + rowstride * 2,
 
1204
                                        bytes),
 
1205
                      CUBIC_SCALED_ROW (du,
 
1206
                                        i + data + rowstride * 3,
 
1207
                                        data + alpha + rowstride * 3,
 
1208
                                        bytes)));
 
1209
 
 
1210
      color[i] = CLAMP (newval, 0, 255);
 
1211
    }
 
1212
}
 
1213
 
 
1214
static void
 
1215
sample_lanczos (PixelSurround *surround,
 
1216
                const gfloat  *lanczos,
 
1217
                gdouble        u,
 
1218
                gdouble        v,
 
1219
                guchar        *color,
 
1220
                gint           bytes,
 
1221
                gint           alpha)
 
1222
{
 
1223
  gdouble       x_kernel[LANCZOS_WIDTH2]; /* 1-D kernels of window coeffs */
 
1224
  gdouble       y_kernel[LANCZOS_WIDTH2];
 
1225
  gdouble       x_sum, y_sum;             /* sum of Lanczos weights       */
 
1226
  gdouble       arecip;
 
1227
  gdouble       aval;
 
1228
  gint          su, sv;
 
1229
  gint          b;
 
1230
  gint          i, j;
 
1231
  gint          iu, iv;
 
1232
  gint          rowstride;
 
1233
  const guchar *data;
 
1234
  const guchar *src;
 
1235
 
 
1236
  iu = (gint) u;
 
1237
  iv = (gint) v;
 
1238
 
 
1239
  /* get weight for fractional error */
 
1240
  su = (gint) ((u - iu) * LANCZOS_SPP);
 
1241
  sv = (gint) ((v - iv) * LANCZOS_SPP);
 
1242
 
 
1243
  /* fill 1D kernels */
 
1244
  for (x_sum = y_sum = 0.0, i = LANCZOS_WIDTH; i >= -LANCZOS_WIDTH; i--)
 
1245
    {
 
1246
      gint pos = i * LANCZOS_SPP;
 
1247
 
 
1248
      x_sum += x_kernel[LANCZOS_WIDTH + i] = lanczos[ABS (su - pos)];
 
1249
      y_sum += y_kernel[LANCZOS_WIDTH + i] = lanczos[ABS (sv - pos)];
 
1250
    }
 
1251
 
 
1252
  /* normalise the weighted arrays */
 
1253
  for (i = 0; i < LANCZOS_WIDTH2 ; i++)
 
1254
    {
 
1255
      x_kernel[i] /= x_sum;
 
1256
      y_kernel[i] /= y_sum;
 
1257
    }
 
1258
 
 
1259
  /* lock the pixel surround */
 
1260
  data = pixel_surround_lock (surround,
 
1261
                              iu - LANCZOS_WIDTH, iv - LANCZOS_WIDTH,
 
1262
                              &rowstride);
 
1263
 
 
1264
  src = data + alpha;
 
1265
  aval = 0.0;
 
1266
 
 
1267
  for (j = 0; j < LANCZOS_WIDTH2 ; j++)
 
1268
    {
 
1269
      for (i = 0; i < LANCZOS_WIDTH2 ; i++)
 
1270
        aval += y_kernel[j] * x_kernel[i] * (gdouble) src[i * bytes];
 
1271
 
 
1272
      src += rowstride;
 
1273
    }
 
1274
 
 
1275
  if (aval <= 0.0)
 
1276
    {
 
1277
      arecip = 0.0;
 
1278
      aval = 0;
 
1279
    }
 
1280
  else if (aval > 255.0)
 
1281
    {
 
1282
      arecip = 1.0 / aval;
 
1283
      aval = 255;
 
1284
    }
 
1285
  else
 
1286
    {
 
1287
      arecip = 1.0 / aval;
 
1288
    }
 
1289
 
 
1290
  for (b = 0; b < alpha; b++)
 
1291
    {
 
1292
      const guchar *asrc;
 
1293
      gdouble       newval = 0.0;
 
1294
 
 
1295
      src  = data + b;
 
1296
      asrc = data + alpha;
 
1297
 
 
1298
      for (j = 0; j < LANCZOS_WIDTH2; j++)
 
1299
        {
 
1300
          for (i = 0; i < LANCZOS_WIDTH2; i++)
 
1301
            newval += (y_kernel[j] * x_kernel[i] *
 
1302
                       (gdouble) src[i * bytes] * (gdouble) asrc[i * bytes]);
 
1303
 
 
1304
          src += rowstride;
 
1305
          asrc += rowstride;
 
1306
        }
 
1307
 
 
1308
      newval *= arecip;
 
1309
      color[b] = CLAMP (newval, 0, 255);
 
1310
    }
 
1311
 
 
1312
  color[alpha] = RINT (aval);
 
1313
}