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