1 //-----------------------------------------------------------------------------
2 //
3 // ImageLib Utility Sources
4 // Copyright (C) 2000-2002 by Denton Woods
5 // Last modified: 05/25/2001 <--Y2K Compliant! =]
6 //
7 // Filename: src-ILU/src/ilu_scale2d.c
8 //
9 // Description: Scales an image.
10 //
11 //-----------------------------------------------------------------------------
12
13
14 // NOTE: Don't look at this file if you wish to preserve your sanity!
15
16
17 #include "ilu_internal.h"
18 #include "ilu_states.h"
19
20
21 ILimage *iluScale2DNear_(ILimage *Image, ILimage *Scaled, ILuint Width, ILuint Height);
22 ILimage *iluScale2DLinear_(ILimage *Image, ILimage *Scaled, ILuint Width, ILuint Height);
23 ILimage *iluScale2DBilinear_(ILimage *Image, ILimage *Scaled, ILuint Width, ILuint Height);
24
25 static ILuint x1, x2;
26 static ILuint NewY1, NewY2, NewX1, NewX2, Size, x, y, c;
27 static ILdouble ScaleX, ScaleY, t1, t2, t3, t4, f, ft, NewX;
28 static ILdouble Table[2][4]; // Assumes we don't have larger than 32-bit images.
29 static ILuint ImgBps, SclBps;
30 static ILushort *ShortPtr, *SShortPtr;
31 static ILuint *IntPtr, *SIntPtr;
32 static ILfloat *FloatPtr, *SFloatPtr;
33
34
35
iluScale2D_(ILimage * Image,ILimage * Scaled,ILuint Width,ILuint Height)36 ILimage *iluScale2D_(ILimage *Image, ILimage *Scaled, ILuint Width, ILuint Height)
37 {
38 if (Image == NULL) {
39 ilSetError(ILU_ILLEGAL_OPERATION);
40 return IL_FALSE;
41 }
42
43 ScaleX = (ILfloat)Width / Image->Width;
44 ScaleY = (ILfloat)Height / Image->Height;
45
46 if (iluFilter == ILU_NEAREST)
47 return iluScale2DNear_(Image, Scaled, Width, Height);
48 else if (iluFilter == ILU_LINEAR)
49 return iluScale2DLinear_(Image, Scaled, Width, Height);
50 // iluFilter == ILU_BILINEAR
51 return iluScale2DBilinear_(Image, Scaled, Width, Height);
52 }
53
54
iluScale2DNear_(ILimage * Image,ILimage * Scaled,ILuint Width,ILuint Height)55 ILimage *iluScale2DNear_(ILimage *Image, ILimage *Scaled, ILuint Width, ILuint Height)
56 {
57 ImgBps = Image->Bps / Image->Bpc;
58 SclBps = Scaled->Bps / Scaled->Bpc;
59
60 switch (Image->Bpc)
61 {
62 case 1:
63 for (y = 0; y < Height; y++) {
64 NewY1 = y * SclBps;
65 NewY2 = (ILuint)(y / ScaleY) * ImgBps;
66 for (x = 0; x < Width; x++) {
67 NewX1 = x * Scaled->Bpp;
68 NewX2 = (ILuint)(x / ScaleX) * Image->Bpp;
69 for (c = 0; c < Scaled->Bpp; c++) {
70 Scaled->Data[NewY1 + NewX1 + c] = Image->Data[NewY2 + NewX2 + c];
71 x1 = 0;
72 }
73 }
74 }
75 break;
76
77 case 2:
78 ShortPtr = (ILushort*)Image->Data;
79 SShortPtr = (ILushort*)Scaled->Data;
80 for (y = 0; y < Height; y++) {
81 NewY1 = y * SclBps;
82 NewY2 = (ILuint)(y / ScaleY) * ImgBps;
83 for (x = 0; x < Width; x++) {
84 NewX1 = x * Scaled->Bpp;
85 NewX2 = (ILuint)(x / ScaleX) * Image->Bpp;
86 for (c = 0; c < Scaled->Bpp; c++) {
87 SShortPtr[NewY1 + NewX1 + c] = ShortPtr[NewY2 + NewX2 + c];
88 x1 = 0;
89 }
90 }
91 }
92 break;
93
94 case 4:
95 IntPtr = (ILuint*)Image->Data;
96 SIntPtr = (ILuint*)Scaled->Data;
97 for (y = 0; y < Height; y++) {
98 NewY1 = y * SclBps;
99 NewY2 = (ILuint)(y / ScaleY) * ImgBps;
100 for (x = 0; x < Width; x++) {
101 NewX1 = x * Scaled->Bpp;
102 NewX2 = (ILuint)(x / ScaleX) * Image->Bpp;
103 for (c = 0; c < Scaled->Bpp; c++) {
104 SIntPtr[NewY1 + NewX1 + c] = IntPtr[NewY2 + NewX2 + c];
105 x1 = 0;
106 }
107 }
108 }
109 break;
110 }
111
112 return Scaled;
113 }
114
115
iluScale2DLinear_(ILimage * Image,ILimage * Scaled,ILuint Width,ILuint Height)116 ILimage *iluScale2DLinear_(ILimage *Image, ILimage *Scaled, ILuint Width, ILuint Height)
117 {
118 ImgBps = Image->Bps / Image->Bpc;
119 SclBps = Scaled->Bps / Scaled->Bpc;
120
121 switch (Image->Bpc)
122 {
123 case 1:
124 for (y = 0; y < Height; y++) {
125 NewY1 = (ILuint)(y / ScaleY) * ImgBps;
126 for (x = 0; x < Width; x++) {
127 t1 = x / (ILdouble)Width;
128 t4 = t1 * Width;
129 t2 = t4 - (ILuint)(t4);
130 ft = t2 * IL_PI;
131 f = (1.0 - cos(ft)) * .5;
132 NewX1 = ((ILuint)(t4 / ScaleX)) * Image->Bpp;
133 NewX2 = ((ILuint)(t4 / ScaleX) + 1) * Image->Bpp;
134
135 Size = y * SclBps + x * Scaled->Bpp;
136 for (c = 0; c < Scaled->Bpp; c++) {
137 x1 = Image->Data[NewY1 + NewX1 + c];
138 x2 = Image->Data[NewY1 + NewX2 + c];
139 Scaled->Data[Size + c] = (ILubyte)((1.0 - f) * x1 + f * x2);
140 }
141 }
142 }
143 break;
144
145 case 2:
146 ShortPtr = (ILushort*)Image->Data;
147 SShortPtr = (ILushort*)Scaled->Data;
148 for (y = 0; y < Height; y++) {
149 NewY1 = (ILuint)(y / ScaleY) * ImgBps;
150 for (x = 0; x < Width; x++) {
151 t1 = x / (ILdouble)Width;
152 t4 = t1 * Width;
153 t2 = t4 - (ILuint)(t4);
154 ft = t2 * IL_PI;
155 f = (1.0 - cos(ft)) * .5;
156 NewX1 = ((ILuint)(t4 / ScaleX)) * Image->Bpp;
157 NewX2 = ((ILuint)(t4 / ScaleX) + 1) * Image->Bpp;
158
159 Size = y * SclBps + x * Scaled->Bpp;
160 for (c = 0; c < Scaled->Bpp; c++) {
161 x1 = ShortPtr[NewY1 + NewX1 + c];
162 x2 = ShortPtr[NewY1 + NewX2 + c];
163 SShortPtr[Size + c] = (ILushort)((1.0 - f) * x1 + f * x2);
164 }
165 }
166 }
167 break;
168
169 case 4:
170 IntPtr = (ILuint*)Image->Data;
171 SIntPtr = (ILuint*)Scaled->Data;
172 for (y = 0; y < Height; y++) {
173 NewY1 = (ILuint)(y / ScaleY) * ImgBps;
174 for (x = 0; x < Width; x++) {
175 t1 = x / (ILdouble)Width;
176 t4 = t1 * Width;
177 t2 = t4 - (ILuint)(t4);
178 ft = t2 * IL_PI;
179 f = (1.0 - cos(ft)) * .5;
180 NewX1 = ((ILuint)(t4 / ScaleX)) * Image->Bpp;
181 NewX2 = ((ILuint)(t4 / ScaleX) + 1) * Image->Bpp;
182
183 Size = y * SclBps + x * Scaled->Bpp;
184 for (c = 0; c < Scaled->Bpp; c++) {
185 x1 = IntPtr[NewY1 + NewX1 + c];
186 x2 = IntPtr[NewY1 + NewX2 + c];
187 SIntPtr[Size + c] = (ILuint)((1.0 - f) * x1 + f * x2);
188 }
189 }
190 }
191 break;
192 }
193
194 return Scaled;
195 }
196
197
198 // Rewrote using an algorithm described by Paul Nettle at
199 // http://www.gamedev.net/reference/articles/article669.asp.
iluScale2DBilinear_(ILimage * Image,ILimage * Scaled,ILuint Width,ILuint Height)200 ILimage *iluScale2DBilinear_(ILimage *Image, ILimage *Scaled, ILuint Width, ILuint Height)
201 {
202 ILfloat ul, ll, ur, lr;
203 ILfloat FracX, FracY;
204 ILfloat SrcX, SrcY;
205 ILuint iSrcX, iSrcY, iSrcXPlus1, iSrcYPlus1, ulOff, llOff, urOff, lrOff;
206
207 // only downscale is allowed
208 assert(ScaleX>0 && ScaleX<=1.0f);
209 assert(ScaleY>0 && ScaleY<=1.0f);
210
211 // scale factors should match images size
212 assert( ((ILfloat)Width -0.5f) / ScaleX < Image->Width );
213 assert( ((ILfloat)Height-0.5f) / ScaleY < Image->Height );
214
215 ImgBps = Image->Bps / Image->Bpc;
216 SclBps = Scaled->Bps / Scaled->Bpc;
217
218 switch (Image->Bpc)
219 {
220 case 1:
221 for (y = 0; y < Height; y++) {
222 for (x = 0; x < Width; x++) {
223 // Calculate where we want to choose pixels from in our source image.
224 SrcX = (ILfloat)(x+0.5f) / (ILfloat)ScaleX;
225 SrcY = (ILfloat)(y+0.5f) / (ILfloat)ScaleY;
226 // indices of upper-left pixel
227 iSrcX = (ILuint)(SrcX-0.5f);
228 iSrcY = (ILuint)(SrcY-0.5f);
229 // how far SrcX and SrcY are from upper-left pixel center
230 FracX = SrcX - (ILfloat)(iSrcX) - 0.5f;
231 FracY = SrcY - (ILfloat)(iSrcY) - 0.5f;
232
233 // We do not want to go past the right edge of the image or past the last line in the image,
234 // so this takes care of that. Normally, iSrcXPlus1 is iSrcX + 1, but if this is past the
235 // right side, we have to bring it back to iSrcX. The same goes for iSrcYPlus1.
236 if (iSrcX < Image->Width - 1)
237 iSrcXPlus1 = iSrcX + 1;
238 else
239 iSrcXPlus1 = iSrcX;
240 if (iSrcY < Image->Height - 1)
241 iSrcYPlus1 = iSrcY + 1;
242 else
243 iSrcYPlus1 = iSrcY;
244
245 // Find out how much we want each of the four pixels contributing to the final values.
246 ul = (1.0f - FracX) * (1.0f - FracY);
247 ll = (1.0f - FracX) * FracY;
248 ur = FracX * (1.0f - FracY);
249 lr = FracX * FracY;
250
251 for (c = 0; c < Scaled->Bpp; c++) {
252 // We just calculate the offsets for each pixel here...
253 ulOff = iSrcY * Image->Bps + iSrcX * Image->Bpp + c;
254 llOff = iSrcYPlus1 * Image->Bps + iSrcX * Image->Bpp + c;
255 urOff = iSrcY * Image->Bps + iSrcXPlus1 * Image->Bpp + c;
256 lrOff = iSrcYPlus1 * Image->Bps + iSrcXPlus1 * Image->Bpp + c;
257
258 // ...and then we do the actual interpolation here.
259 Scaled->Data[y * Scaled->Bps + x * Scaled->Bpp + c] = (ILubyte)(
260 ul * Image->Data[ulOff] + ll * Image->Data[llOff] + ur * Image->Data[urOff] + lr * Image->Data[lrOff]);
261 }
262 }
263 }
264 break;
265
266 case 2:
267 ShortPtr = (ILushort*)Image->Data;
268 SShortPtr = (ILushort*)Scaled->Data;
269 Height--; // Only use regular Height once in the following loop.
270 for (y = 0; y < Height; y++) {
271 NewY1 = (ILuint)(y / ScaleY) * ImgBps;
272 NewY2 = (ILuint)((y+1) / ScaleY) * ImgBps;
273 for (x = 0; x < Width; x++) {
274 NewX = Width / ScaleX;
275 t1 = x / (ILdouble)Width;
276 t4 = t1 * Width;
277 t2 = t4 - (ILuint)(t4);
278 t3 = (1.0 - t2);
279 t4 = t1 * NewX;
280 NewX1 = (ILuint)(t4) * Image->Bpp;
281 NewX2 = (ILuint)(t4 + 1) * Image->Bpp;
282
283 for (c = 0; c < Scaled->Bpp; c++) {
284 Table[0][c] = t3 * ShortPtr[NewY1 + NewX1 + c] +
285 t2 * ShortPtr[NewY1 + NewX2 + c];
286
287 Table[1][c] = t3 * ShortPtr[NewY2 + NewX1 + c] +
288 t2 * ShortPtr[NewY2 + NewX2 + c];
289 }
290
291 // Linearly interpolate between the table values.
292 t1 = y / (ILdouble)(Height + 1); // Height+1 is the real height now.
293 t3 = (1.0 - t1);
294 Size = y * SclBps + x * Scaled->Bpp;
295 for (c = 0; c < Scaled->Bpp; c++) {
296 SShortPtr[Size + c] =
297 (ILushort)(t3 * Table[0][c] + t1 * Table[1][c]);
298 }
299 }
300 }
301
302 // Calculate the last row.
303 NewY1 = (ILuint)(Height / ScaleY) * ImgBps;
304 for (x = 0; x < Width; x++) {
305 NewX = Width / ScaleX;
306 t1 = x / (ILdouble)Width;
307 t4 = t1 * Width;
308 ft = (t4 - (ILuint)(t4)) * IL_PI;
309 f = (1.0 - cos(ft)) * .5; // Cosine interpolation
310 NewX1 = (ILuint)(t1 * NewX) * Image->Bpp;
311 NewX2 = (ILuint)(t1 * NewX + 1) * Image->Bpp;
312
313 Size = Height * SclBps + x * Image->Bpp;
314 for (c = 0; c < Scaled->Bpp; c++) {
315 SShortPtr[Size + c] = (ILushort)((1.0 - f) * ShortPtr[NewY1 + NewX1 + c] +
316 f * ShortPtr[NewY1 + NewX2 + c]);
317 }
318 }
319 break;
320
321 case 4:
322 if (Image->Type != IL_FLOAT) {
323 IntPtr = (ILuint*)Image->Data;
324 SIntPtr = (ILuint*)Scaled->Data;
325 Height--; // Only use regular Height once in the following loop.
326 for (y = 0; y < Height; y++) {
327 NewY1 = (ILuint)(y / ScaleY) * ImgBps;
328 NewY2 = (ILuint)((y+1) / ScaleY) * ImgBps;
329 for (x = 0; x < Width; x++) {
330 NewX = Width / ScaleX;
331 t1 = x / (ILdouble)Width;
332 t4 = t1 * Width;
333 t2 = t4 - (ILuint)(t4);
334 t3 = (1.0 - t2);
335 t4 = t1 * NewX;
336 NewX1 = (ILuint)(t4) * Image->Bpp;
337 NewX2 = (ILuint)(t4 + 1) * Image->Bpp;
338
339 for (c = 0; c < Scaled->Bpp; c++) {
340 Table[0][c] = t3 * IntPtr[NewY1 + NewX1 + c] +
341 t2 * IntPtr[NewY1 + NewX2 + c];
342
343 Table[1][c] = t3 * IntPtr[NewY2 + NewX1 + c] +
344 t2 * IntPtr[NewY2 + NewX2 + c];
345 }
346
347 // Linearly interpolate between the table values.
348 t1 = y / (ILdouble)(Height + 1); // Height+1 is the real height now.
349 t3 = (1.0 - t1);
350 Size = y * SclBps + x * Scaled->Bpp;
351 for (c = 0; c < Scaled->Bpp; c++) {
352 SIntPtr[Size + c] =
353 (ILuint)(t3 * Table[0][c] + t1 * Table[1][c]);
354 }
355 }
356 }
357
358 // Calculate the last row.
359 NewY1 = (ILuint)(Height / ScaleY) * ImgBps;
360 for (x = 0; x < Width; x++) {
361 NewX = Width / ScaleX;
362 t1 = x / (ILdouble)Width;
363 t4 = t1 * Width;
364 ft = (t4 - (ILuint)(t4)) * IL_PI;
365 f = (1.0 - cos(ft)) * .5; // Cosine interpolation
366 NewX1 = (ILuint)(t1 * NewX) * Image->Bpp;
367 NewX2 = (ILuint)(t1 * NewX + 1) * Image->Bpp;
368
369 Size = Height * SclBps + x * Image->Bpp;
370 for (c = 0; c < Scaled->Bpp; c++) {
371 SIntPtr[Size + c] = (ILuint)((1.0 - f) * IntPtr[NewY1 + NewX1 + c] +
372 f * IntPtr[NewY1 + NewX2 + c]);
373 }
374 }
375
376 }
377
378 else { // IL_FLOAT
379 FloatPtr = (ILfloat*)Image->Data;
380 SFloatPtr = (ILfloat*)Scaled->Data;
381 Height--; // Only use regular Height once in the following loop.
382
383 for (y = 0; y < Height; y++) {
384
385 NewY1 = (ILuint)(y / ScaleY) * ImgBps;
386
387 NewY2 = (ILuint)((y+1) / ScaleY) * ImgBps;
388
389 for (x = 0; x < Width; x++) {
390
391 NewX = Width / ScaleX;
392
393 t1 = x / (ILdouble)Width;
394
395 t4 = t1 * Width;
396
397 t2 = t4 - (ILuint)(t4);
398
399 t3 = (1.0 - t2);
400
401 t4 = t1 * NewX;
402
403 NewX1 = (ILuint)(t4) * Image->Bpp;
404
405 NewX2 = (ILuint)(t4 + 1) * Image->Bpp;
406
407
408
409 for (c = 0; c < Scaled->Bpp; c++) {
410
411 Table[0][c] = t3 * FloatPtr[NewY1 + NewX1 + c] +
412
413 t2 * FloatPtr[NewY1 + NewX2 + c];
414
415
416
417 Table[1][c] = t3 * FloatPtr[NewY2 + NewX1 + c] +
418
419 t2 * FloatPtr[NewY2 + NewX2 + c];
420
421 }
422
423
424
425 // Linearly interpolate between the table values.
426
427 t1 = y / (ILdouble)(Height + 1); // Height+1 is the real height now.
428
429 t3 = (1.0 - t1);
430
431 Size = y * SclBps + x * Scaled->Bpp;
432
433 for (c = 0; c < Scaled->Bpp; c++) {
434
435 SFloatPtr[Size + c] =
436
437 (ILfloat)(t3 * Table[0][c] + t1 * Table[1][c]);
438
439 }
440
441 }
442
443 }
444
445
446
447 // Calculate the last row.
448
449 NewY1 = (ILuint)(Height / ScaleY) * ImgBps;
450
451 for (x = 0; x < Width; x++) {
452
453 NewX = Width / ScaleX;
454
455 t1 = x / (ILdouble)Width;
456
457 t4 = t1 * Width;
458
459 ft = (t4 - (ILuint)(t4)) * IL_PI;
460
461 f = (1.0 - cos(ft)) * .5; // Cosine interpolation
462
463 NewX1 = (ILuint)(t1 * NewX) * Image->Bpp;
464
465 NewX2 = (ILuint)(t1 * NewX + 1) * Image->Bpp;
466
467
468
469 Size = Height * SclBps + x * Image->Bpp;
470
471 for (c = 0; c < Scaled->Bpp; c++) {
472
473 SFloatPtr[Size + c] = (ILfloat)((1.0 - f) * FloatPtr[NewY1 + NewX1 + c] +
474
475 f * FloatPtr[NewY1 + NewX2 + c]);
476
477 }
478
479 }
480
481 }
482
483 break;
484 }
485
486 return Scaled;
487 }
488