823bc4e9ce2ed9974ccda9c799f84740aba7c684
[platform/upstream/cups.git] / filter / image-zoom.c
1 /*
2  * "$Id: image-zoom.c 9502 2011-01-21 23:56:14Z mike $"
3  *
4  *   cupsImage zoom routines for CUPS.
5  *
6  *   Copyright 2007-2011 by Apple Inc.
7  *   Copyright 1993-2006 by Easy Software Products.
8  *
9  *   These coded instructions, statements, and computer programs are the
10  *   property of Apple Inc. and are protected by Federal copyright
11  *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
12  *   which should have been included with this file.  If this file is
13  *   file is missing or damaged, see the license at "http://www.cups.org/".
14  *
15  *   This file is subject to the Apple OS-Developed Software exception.
16  *
17  * Contents:
18  *
19  *   _cupsImageZoomDelete() - Free a zoom record...
20  *   _cupsImageZoomFill()   - Fill a zoom record...
21  *   _cupsImageZoomNew()    - Allocate a pixel zoom record...
22  *   zoom_bilinear()        - Fill a zoom record with image data utilizing
23  *                            bilinear interpolation.
24  *   zoom_nearest()         - Fill a zoom record quickly using nearest-neighbor
25  *                            sampling.
26  */
27
28 /*
29  * Include necessary headers...
30  */
31
32 #include "image-private.h"
33
34
35 /*
36  * Local functions...
37  */
38
39 static void     zoom_bilinear(cups_izoom_t *z, int iy);
40 static void     zoom_nearest(cups_izoom_t *z, int iy);
41
42
43 /*
44  * '_cupsImageZoomDelete()' - Free a zoom record...
45  */
46
47 void
48 _cupsImageZoomDelete(cups_izoom_t *z)   /* I - Zoom record to free */
49 {
50   free(z->rows[0]);
51   free(z->rows[1]);
52   free(z->in);
53   free(z);
54 }
55
56
57 /*
58  * '_cupsImageZoomFill()' - Fill a zoom record with image data utilizing bilinear
59  *                         interpolation.
60  */
61
62 void
63 _cupsImageZoomFill(cups_izoom_t *z,     /* I - Zoom record to fill */
64                    int     iy)          /* I - Zoom image row */
65 {
66   switch (z->type)
67   {
68     case CUPS_IZOOM_FAST :
69         zoom_nearest(z, iy);
70         break;
71
72     default :
73         zoom_bilinear(z, iy);
74         break;
75   }
76 }
77
78
79 /*
80  * '_cupsImageZoomNew()' - Allocate a pixel zoom record...
81  */
82
83 cups_izoom_t *
84 _cupsImageZoomNew(
85     cups_image_t  *img,                 /* I - cupsImage to zoom */
86     int           xc0,                  /* I - Upper-lefthand corner */
87     int           yc0,                  /* I - ... */
88     int           xc1,                  /* I - Lower-righthand corner */
89     int           yc1,                  /* I - ... */
90     int           xsize,                /* I - Final width of image */
91     int           ysize,                /* I - Final height of image */
92     int           rotated,              /* I - Non-zero if image is rotated 90 degs */
93     cups_iztype_t type)                 /* I - Zoom type */
94 {
95   cups_izoom_t  *z;                     /* New zoom record */
96   int           flip;                   /* Flip on X axis? */
97
98
99   if (xsize > CUPS_IMAGE_MAX_WIDTH ||
100       ysize > CUPS_IMAGE_MAX_HEIGHT ||
101       (xc1 - xc0) > CUPS_IMAGE_MAX_WIDTH ||
102       (yc1 - yc0) > CUPS_IMAGE_MAX_HEIGHT)
103     return (NULL);              /* Protect against integer overflow */
104
105   if ((z = (cups_izoom_t *)calloc(1, sizeof(cups_izoom_t))) == NULL)
106     return (NULL);
107
108   z->img     = img;
109   z->row     = 0;
110   z->depth   = cupsImageGetDepth(img);
111   z->rotated = rotated;
112   z->type    = type;
113
114   if (xsize < 0)
115   {
116     flip  = 1;
117     xsize = -xsize;
118   }
119   else
120   {
121     flip  = 0;
122   }
123
124   if (rotated)
125   {
126     z->xorig   = xc1;
127     z->yorig   = yc0;
128     z->width   = yc1 - yc0 + 1;
129     z->height  = xc1 - xc0 + 1;
130     z->xsize   = xsize;
131     z->ysize   = ysize;
132     z->xmod    = z->width % z->xsize;
133     z->xstep   = z->width / z->xsize;
134     z->xincr   = 1;
135     z->ymod    = z->height % z->ysize;
136     z->ystep   = z->height / z->ysize;
137     z->yincr   = 1;
138     z->instep  = z->xstep * z->depth;
139     z->inincr  = /* z->xincr * */ z->depth; /* z->xincr is always 1 */
140
141     if (z->width < img->ysize)
142       z->xmax = z->width;
143     else
144       z->xmax = z->width - 1;
145
146     if (z->height < img->xsize)
147       z->ymax = z->height;
148     else
149       z->ymax = z->height - 1;
150   }
151   else
152   {
153     z->xorig   = xc0;
154     z->yorig   = yc0;
155     z->width   = xc1 - xc0 + 1;
156     z->height  = yc1 - yc0 + 1;
157     z->xsize   = xsize;
158     z->ysize   = ysize;
159     z->xmod    = z->width % z->xsize;
160     z->xstep   = z->width / z->xsize;
161     z->xincr   = 1;
162     z->ymod    = z->height % z->ysize;
163     z->ystep   = z->height / z->ysize;
164     z->yincr   = 1;
165     z->instep  = z->xstep * z->depth;
166     z->inincr  = /* z->xincr * */ z->depth; /* z->xincr is always 1 */
167
168     if (z->width < img->xsize)
169       z->xmax = z->width;
170     else
171       z->xmax = z->width - 1;
172
173     if (z->height < img->ysize)
174       z->ymax = z->height;
175     else
176       z->ymax = z->height - 1;
177   }
178
179   if (flip)
180   {
181     z->instep = -z->instep;
182     z->inincr = -z->inincr;
183   }
184
185   if ((z->rows[0] = (cups_ib_t *)malloc(z->xsize * z->depth)) == NULL)
186   {
187     free(z);
188     return (NULL);
189   }
190
191   if ((z->rows[1] = (cups_ib_t *)malloc(z->xsize * z->depth)) == NULL)
192   {
193     free(z->rows[0]);
194     free(z);
195     return (NULL);
196   }
197
198   if ((z->in = (cups_ib_t *)malloc(z->width * z->depth)) == NULL)
199   {
200     free(z->rows[0]);
201     free(z->rows[1]);
202     free(z);
203     return (NULL);
204   }
205
206   return (z);
207 }
208
209
210 /*
211  * 'zoom_bilinear()' - Fill a zoom record with image data utilizing bilinear
212  *                     interpolation.
213  */
214
215 static void
216 zoom_bilinear(cups_izoom_t *z,          /* I - Zoom record to fill */
217               int          iy)          /* I - Zoom image row */
218 {
219   cups_ib_t     *r,                     /* Row pointer */
220                 *inptr;                 /* Pixel pointer */
221   int           xerr0,                  /* X error counter */
222                 xerr1;                  /* ... */
223   int           ix,
224                 x,
225                 count,
226                 z_depth,
227                 z_xstep,
228                 z_xincr,
229                 z_instep,
230                 z_inincr,
231                 z_xmax,
232                 z_xmod,
233                 z_xsize;
234
235
236   if (iy > z->ymax)
237     iy = z->ymax;
238
239   z->row ^= 1;
240
241   z_depth  = z->depth;
242   z_xsize  = z->xsize;
243   z_xmax   = z->xmax;
244   z_xmod   = z->xmod;
245   z_xstep  = z->xstep;
246   z_xincr  = z->xincr;
247   z_instep = z->instep;
248   z_inincr = z->inincr;
249
250   if (z->rotated)
251     cupsImageGetCol(z->img, z->xorig - iy, z->yorig, z->width, z->in);
252   else
253     cupsImageGetRow(z->img, z->xorig, z->yorig + iy, z->width, z->in);
254
255   if (z_inincr < 0)
256     inptr = z->in + (z->width - 1) * z_depth;
257   else
258     inptr = z->in;
259
260   for (x = z_xsize, xerr0 = z_xsize, xerr1 = 0, ix = 0, r = z->rows[z->row];
261        x > 0;
262        x --)
263   {
264     if (ix < z_xmax)
265     {
266       for (count = 0; count < z_depth; count ++)
267         *r++ = (inptr[count] * xerr0 + inptr[z_depth + count] * xerr1) / z_xsize;
268     }
269     else
270     {
271       for (count = 0; count < z_depth; count ++)
272         *r++ = inptr[count];
273     }
274
275     ix    += z_xstep;
276     inptr += z_instep;
277     xerr0 -= z_xmod;
278     xerr1 += z_xmod;
279
280     if (xerr0 <= 0)
281     {
282       xerr0 += z_xsize;
283       xerr1 -= z_xsize;
284       ix    += z_xincr;
285       inptr += z_inincr;
286     }
287   }
288 }
289
290
291 /*
292  * 'zoom_nearest()' - Fill a zoom record quickly using nearest-neighbor
293  *                    sampling.
294  */
295
296 static void
297 zoom_nearest(cups_izoom_t *z,           /* I - Zoom record to fill */
298              int          iy)           /* I - Zoom image row */
299 {
300   cups_ib_t     *r,                     /* Row pointer */
301                 *inptr;                 /* Pixel pointer */
302   int           xerr0;                  /* X error counter */
303   int           ix,
304                 x,
305                 count,
306                 z_depth,
307                 z_xstep,
308                 z_xincr,
309                 z_instep,
310                 z_inincr,
311                 z_xmod,
312                 z_xsize;
313
314
315   if (iy > z->ymax)
316     iy = z->ymax;
317
318   z->row ^= 1;
319
320   z_depth  = z->depth;
321   z_xsize  = z->xsize;
322   z_xmod   = z->xmod;
323   z_xstep  = z->xstep;
324   z_xincr  = z->xincr;
325   z_instep = z->instep;
326   z_inincr = z->inincr;
327
328   if (z->rotated)
329     cupsImageGetCol(z->img, z->xorig - iy, z->yorig, z->width, z->in);
330   else
331     cupsImageGetRow(z->img, z->xorig, z->yorig + iy, z->width, z->in);
332
333   if (z_inincr < 0)
334     inptr = z->in + (z->width - 1) * z_depth;
335   else
336     inptr = z->in;
337
338   for (x = z_xsize, xerr0 = z_xsize, ix = 0, r = z->rows[z->row];
339        x > 0;
340        x --)
341   {
342     for (count = 0; count < z_depth; count ++)
343       *r++ = inptr[count];
344
345     ix    += z_xstep;
346     inptr += z_instep;
347     xerr0 -= z_xmod;
348
349     if (xerr0 <= 0)
350     {
351       xerr0 += z_xsize;
352       ix    += z_xincr;
353       inptr += z_inincr;
354     }
355   }
356 }
357
358
359 /*
360  * End of "$Id: image-zoom.c 9502 2011-01-21 23:56:14Z mike $".
361  */