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