~ubuntu-branches/debian/sid/scribus/sid

« back to all changes in this revision

Viewing changes to scribus/libart/art_render_misc.c

  • Committer: Bazaar Package Importer
  • Author(s): Oleksandr Moskalenko
  • Date: 2008-07-02 13:42:07 UTC
  • mto: (4.1.1 sid) (20.1.1 experimental) (1.2.1)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20080702134207-h9h384v0wxjmaf8y
Tags: upstream-1.3.3.12.dfsg
ImportĀ upstreamĀ versionĀ 1.3.3.12.dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This file is part of the KDE project.
 
2
 * art_render_misc.c: Here I store some routines I feel should be in libart :)
 
3
 *
 
4
 * Copyright (C) 2002, The Karbon Developers
 
5
 *
 
6
 * This code is adapted from :
 
7
 *
 
8
 * art_render_gradient.c: Gradient image source for modular rendering.
 
9
 *
 
10
 * Libart_LGPL - library of basic graphic primitives
 
11
 * Copyright (C) 2000 Raph Levien
 
12
 *
 
13
 * This library is free software; you can redistribute it and/or
 
14
 * modify it under the terms of the GNU Library General Public
 
15
 * License as published by the Free Software Foundation; either
 
16
 * version 2 of the License, or (at your option) any later version.
 
17
 *
 
18
 * This library is distributed in the hope that it will be useful,
 
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
21
 * Library General Public License for more details.
 
22
 *
 
23
 * You should have received a copy of the GNU Library General Public
 
24
 * License along with this library; if not, write to the
 
25
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
26
 * Boston, MA 02111-1307, USA.
 
27
 *
 
28
 * Authors: Raph Levien <raph@acm.org>
 
29
 *          Alexander Larsson <alla@lysator.liu.se>
 
30
 */
 
31
 
 
32
#include "scconfig.h"
 
33
 
 
34
#include "art_render_misc.h"
 
35
 
 
36
#include <math.h>
 
37
 
 
38
typedef struct _ArtImageSourceGradLin ArtImageSourceGradLin;
 
39
typedef struct _ArtImageSourceGradRad ArtImageSourceGradRad;
 
40
typedef struct _ArtImageSourceGradCon ArtImageSourceGradCon;
 
41
 
 
42
struct _ArtImageSourceGradLin {
 
43
  ArtImageSource super;
 
44
  const ArtGradientLinear *gradient;
 
45
};
 
46
 
 
47
struct _ArtImageSourceGradRad {
 
48
  ArtImageSource super;
 
49
  const ArtGradientRadial *gradient;
 
50
  double a;
 
51
};
 
52
 
 
53
struct _ArtImageSourceGradCon {
 
54
  ArtImageSource super;
 
55
  const ArtGradientConical *gradient;
 
56
};
 
57
 
 
58
 
 
59
#define EPSILON 1e-6
 
60
 
 
61
/**
 
62
 * art_karbon_render_gradient_setpix: Set a gradient pixel.
 
63
 * @render: The render object.
 
64
 * @dst: Pointer to destination (where to store pixel).
 
65
 * @n_stops: Number of stops in @stops.
 
66
 * @stops: The stops for the gradient.
 
67
 * @offset: The offset.
 
68
 *
 
69
 * @n_stops must be > 0.
 
70
 *
 
71
 * Sets a gradient pixel, storing it at @dst.
 
72
 **/
 
73
static void
 
74
art_karbon_render_gradient_setpix (ArtRender *render,
 
75
                            art_u8 *dst,
 
76
                            int n_stops, ArtGradientStop *stops,
 
77
                            double offset)
 
78
{
 
79
  int ix;
 
80
  int j;
 
81
  double off0, off1;
 
82
  int n_ch = render->n_chan + 1;
 
83
 
 
84
  for (ix = 0; ix < n_stops; ix++)
 
85
    if (stops[ix].offset > offset)
 
86
      break;
 
87
  /* stops[ix - 1].offset < offset < stops[ix].offset */
 
88
  if (ix > 0 && ix < n_stops)
 
89
    {
 
90
      off0 = stops[ix - 1].offset;
 
91
      off1 = stops[ix].offset;
 
92
      if (fabs (off1 - off0) > EPSILON)
 
93
        {
 
94
          double interp;
 
95
 
 
96
          interp = (offset - off0) / (off1 - off0);
 
97
          for (j = 0; j < n_ch; j++)
 
98
            {
 
99
              int z0, z1;
 
100
              int z;
 
101
              z0 = stops[ix - 1].color[j];
 
102
              z1 = stops[ix].color[j];
 
103
              z = floor (z0 + (z1 - z0) * interp + 0.5);
 
104
              if (render->buf_depth == 8)
 
105
                dst[j] = ART_PIX_8_FROM_MAX (z);
 
106
              else /* (render->buf_depth == 16) */
 
107
                ((art_u16 *)dst)[j] = z;
 
108
            }
 
109
          return;
 
110
        }
 
111
    }
 
112
  else if (ix == n_stops)
 
113
    ix--;
 
114
 
 
115
  for (j = 0; j < n_ch; j++)
 
116
    {
 
117
      int z;
 
118
      z = stops[ix].color[j];
 
119
      if (render->buf_depth == 8)
 
120
        dst[j] = ART_PIX_8_FROM_MAX (z);
 
121
      else /* (render->buf_depth == 16) */
 
122
        ((art_u16 *)dst)[j] = z;
 
123
    }
 
124
}
 
125
 
 
126
static void
 
127
art_karbon_render_gradient_linear_done (ArtRenderCallback *self, ArtRender *render)
 
128
{
 
129
  art_free (self);
 
130
}
 
131
 
 
132
static void
 
133
art_karbon_render_gradient_linear_render (ArtRenderCallback *self, ArtRender *render,
 
134
                                   art_u8 *dest, int y)
 
135
{
 
136
  ArtImageSourceGradLin *z = (ArtImageSourceGradLin *)self;
 
137
  const ArtGradientLinear *gradient = z->gradient;
 
138
  int pixstride = (render->n_chan + 1) * (render->depth >> 3);
 
139
  int x;
 
140
  int width = render->x1 - render->x0;
 
141
  double offset, d_offset;
 
142
  double actual_offset;
 
143
  int n_stops = gradient->n_stops;
 
144
  ArtGradientStop *stops = gradient->stops;
 
145
  art_u8 *bufp = render->image_buf;
 
146
  ArtGradientSpread spread = gradient->spread;
 
147
 
 
148
  offset = render->x0 * gradient->a + y * gradient->b + gradient->c;
 
149
  d_offset = gradient->a;
 
150
 
 
151
  for (x = 0; x < width; x++)
 
152
    {
 
153
      if (spread == ART_GRADIENT_PAD)
 
154
        actual_offset = offset;
 
155
      else if (spread == ART_GRADIENT_REPEAT)
 
156
        actual_offset = offset - floor (offset);
 
157
      else /* (spread == ART_GRADIENT_REFLECT) */
 
158
        {
 
159
          double tmp;
 
160
 
 
161
          tmp = offset - 2 * floor (0.5 * offset);
 
162
          actual_offset = tmp > 1 ? 2 - tmp : tmp;
 
163
        }
 
164
      art_karbon_render_gradient_setpix (render, bufp, n_stops, stops, actual_offset);
 
165
      offset += d_offset;
 
166
      bufp += pixstride;
 
167
    }
 
168
}
 
169
 
 
170
static void
 
171
art_karbon_render_gradient_linear_negotiate (ArtImageSource *self, ArtRender *render,
 
172
                                      ArtImageSourceFlags *p_flags,
 
173
                                      int *p_buf_depth, ArtAlphaType *p_alpha)
 
174
{
 
175
  self->super.render = art_karbon_render_gradient_linear_render;
 
176
  *p_flags = 0;
 
177
  *p_buf_depth = render->depth;
 
178
  *p_alpha = ART_ALPHA_PREMUL;
 
179
}
 
180
 
 
181
/**
 
182
 * art_karbon_render_gradient_linear: Add a linear gradient image source.
 
183
 * @render: The render object.
 
184
 * @gradient: The linear gradient.
 
185
 *
 
186
 * Adds the linear gradient @gradient as the image source for rendering
 
187
 * in the render object @render.
 
188
 **/
 
189
void
 
190
art_karbon_render_gradient_linear (ArtRender *render,
 
191
                            const ArtGradientLinear *gradient,
 
192
                            ArtFilterLevel level)
 
193
{
 
194
  ArtImageSourceGradLin *image_source = art_new (ArtImageSourceGradLin, 1);
 
195
 
 
196
  image_source->super.super.render = NULL;
 
197
  image_source->super.super.done = art_karbon_render_gradient_linear_done;
 
198
  image_source->super.negotiate = art_karbon_render_gradient_linear_negotiate;
 
199
 
 
200
  image_source->gradient = gradient;
 
201
 
 
202
  art_render_add_image_source (render, &image_source->super);
 
203
}
 
204
 
 
205
static void
 
206
art_karbon_render_gradient_radial_done (ArtRenderCallback *self, ArtRender *render)
 
207
{
 
208
  art_free (self);
 
209
}
 
210
 
 
211
static void
 
212
art_karbon_render_gradient_radial_render (ArtRenderCallback *self, ArtRender *render,
 
213
                                   art_u8 *dest, int y)
 
214
{
 
215
  ArtImageSourceGradRad *z = (ArtImageSourceGradRad *)self;
 
216
  const ArtGradientRadial *gradient = z->gradient;
 
217
  int pixstride = (render->n_chan + 1) * (render->depth >> 3);
 
218
  int x;
 
219
  int x0 = render->x0;
 
220
  int width = render->x1 - x0;
 
221
  int n_stops = gradient->n_stops;
 
222
  ArtGradientStop *stops = gradient->stops;
 
223
  art_u8 *bufp = render->image_buf;
 
224
  double fx = gradient->fx;
 
225
  double fy = gradient->fy;
 
226
  double dx, dy;
 
227
  double *affine = gradient->affine;
 
228
  double aff0 = affine[0];
 
229
  double aff1 = affine[1];
 
230
  const double a = z->a;
 
231
  const double arecip = 1.0 / a;
 
232
  double b, db;
 
233
  double c, dc, ddc;
 
234
  double b_a, db_a;
 
235
  double rad, drad, ddrad;
 
236
  ArtGradientSpread spread = gradient->spread;
 
237
 
 
238
  dx = x0 * aff0 + y * affine[2] + affine[4] - fx;
 
239
  dy = x0 * aff1 + y * affine[3] + affine[5] - fy;
 
240
  b = dx * fx + dy * fy;
 
241
  db = aff0 * fx + aff1 * fy;
 
242
  c = dx * dx + dy * dy;
 
243
  dc = 2 * aff0 * dx + aff0 * aff0 + 2 * aff1 * dy + aff1 * aff1;
 
244
  ddc = 2 * aff0 * aff0 + 2 * aff1 * aff1;
 
245
 
 
246
  b_a = b * arecip;
 
247
  db_a = db * arecip;
 
248
 
 
249
  rad = b_a * b_a + c * arecip;
 
250
  drad = 2 * b_a * db_a + db_a * db_a + dc * arecip;
 
251
  ddrad = 2 * db_a * db_a + ddc * arecip;
 
252
 
 
253
  for (x = 0; x < width; x++)
 
254
    {
 
255
      double z;
 
256
 
 
257
      if (rad > 0)
 
258
        z = b_a + sqrt (rad);
 
259
      else
 
260
        z = b_a;
 
261
 
 
262
    if (spread == ART_GRADIENT_REPEAT)
 
263
          z = z - floor (z);
 
264
    else if (spread == ART_GRADIENT_REFLECT)
 
265
    {
 
266
          double tmp;
 
267
 
 
268
          tmp = z - 2 * floor (0.5 * z);
 
269
          z = tmp > 1 ? 2 - tmp : tmp;
 
270
    }
 
271
 
 
272
      art_karbon_render_gradient_setpix (render, bufp, n_stops, stops, z);
 
273
      bufp += pixstride;
 
274
      b_a += db_a;
 
275
      rad += drad;
 
276
      drad += ddrad;
 
277
    }
 
278
}
 
279
 
 
280
static void
 
281
art_karbon_render_gradient_radial_negotiate (ArtImageSource *self, ArtRender *render,
 
282
                                      ArtImageSourceFlags *p_flags,
 
283
                                      int *p_buf_depth, ArtAlphaType *p_alpha)
 
284
{
 
285
  self->super.render = art_karbon_render_gradient_radial_render;
 
286
  *p_flags = 0;
 
287
  *p_buf_depth = render->depth;
 
288
  *p_alpha = ART_ALPHA_PREMUL;
 
289
}
 
290
 
 
291
/**
 
292
 * art_karbon_render_gradient_radial: Add a radial gradient image source.
 
293
 * @render: The render object.
 
294
 * @gradient: The radial gradient.
 
295
 *
 
296
 * Adds the radial gradient @gradient as the image source for rendering
 
297
 * in the render object @render.
 
298
 **/
 
299
void
 
300
art_karbon_render_gradient_radial (ArtRender *render,
 
301
                            const ArtGradientRadial *gradient,
 
302
                            ArtFilterLevel level)
 
303
{
 
304
  ArtImageSourceGradRad *image_source = art_new (ArtImageSourceGradRad, 1);
 
305
  double fx = gradient->fx;
 
306
  double fy = gradient->fy;
 
307
 
 
308
  image_source->super.super.render = NULL;
 
309
  image_source->super.super.done = art_karbon_render_gradient_radial_done;
 
310
  image_source->super.negotiate = art_karbon_render_gradient_radial_negotiate;
 
311
 
 
312
  image_source->gradient = gradient;
 
313
  /* todo: sanitycheck fx, fy? */
 
314
  image_source->a = 1 - fx * fx - fy * fy;
 
315
 
 
316
  art_render_add_image_source (render, &image_source->super);
 
317
}
 
318
 
 
319
/* Conical */
 
320
 
 
321
static void
 
322
art_render_gradient_conical_done (ArtRenderCallback *self, ArtRender *render)
 
323
{
 
324
  art_free (self);
 
325
}
 
326
 
 
327
static void
 
328
art_render_gradient_conical_render (ArtRenderCallback *self, ArtRender *render,
 
329
                                   art_u8 *dest, int y)
 
330
{
 
331
  ArtImageSourceGradCon *z = (ArtImageSourceGradCon *)self;
 
332
  const ArtGradientConical *gradient = z->gradient;
 
333
  int pixstride = (render->n_chan + 1) * (render->depth >> 3);
 
334
  int x;
 
335
  int x0 = render->x0;
 
336
  int width = render->x1 - x0;
 
337
  int n_stops = gradient->n_stops;
 
338
  ArtGradientStop *stops = gradient->stops;
 
339
  art_u8 *bufp = render->image_buf;
 
340
  double cx = gradient->cx;
 
341
  double cy = gradient->cy;
 
342
  double r = gradient->r;
 
343
  double dx, dy;
 
344
  ArtGradientSpread spread = gradient->spread;
 
345
 
 
346
  dy = fabs(y) - fabs(cy);
 
347
 
 
348
  for (x = 0; x < width; x++)
 
349
    {
 
350
      double z;
 
351
        dx = fabs(x0 + x) - fabs(cx);
 
352
 
 
353
        z = (fabs(dx) + fabs(dy)) / (r);
 
354
 
 
355
    if (spread == ART_GRADIENT_REPEAT)
 
356
          z = z - floor (z);
 
357
    else if (spread == ART_GRADIENT_REFLECT)
 
358
    {
 
359
          double tmp;
 
360
 
 
361
          tmp = z - 2 * floor (0.5 * z);
 
362
          z = tmp > 1 ? 2 - tmp : tmp;
 
363
    }
 
364
 
 
365
      art_karbon_render_gradient_setpix (render, bufp, n_stops, stops, z);
 
366
      bufp += pixstride;
 
367
    }
 
368
}
 
369
 
 
370
static void
 
371
art_render_gradient_conical_negotiate (ArtImageSource *self, ArtRender *render,
 
372
                                      ArtImageSourceFlags *p_flags,
 
373
                                      int *p_buf_depth, ArtAlphaType *p_alpha)
 
374
{
 
375
  self->super.render = art_render_gradient_conical_render;
 
376
  *p_flags = 0;
 
377
  *p_buf_depth = render->depth;
 
378
  *p_alpha = ART_ALPHA_PREMUL;
 
379
}
 
380
 
 
381
/**
 
382
 * art_render_gradient_radial: Add a radial gradient image source.
 
383
 * @render: The render object.
 
384
 * @gradient: The radial gradient.
 
385
 *
 
386
 * Adds the radial gradient @gradient as the image source for rendering
 
387
 * in the render object @render.
 
388
 **/
 
389
void
 
390
art_karbon_render_gradient_conical (ArtRender *render,
 
391
                            const ArtGradientConical *gradient,
 
392
                            ArtFilterLevel level)
 
393
{
 
394
  ArtImageSourceGradCon *image_source = art_new (ArtImageSourceGradCon, 1);
 
395
 
 
396
  image_source->super.super.render = NULL;
 
397
  image_source->super.super.done = art_render_gradient_conical_done;
 
398
  image_source->super.negotiate = art_render_gradient_conical_negotiate;
 
399
 
 
400
  image_source->gradient = gradient;
 
401
 
 
402
  art_render_add_image_source (render, &image_source->super);
 
403
}
 
404