Subversion Repositories gelsvn

Rev

Rev 369 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
369 jab 1
/*
2
    Jonathan Dummer
3
 
4
    image helper functions
5
 
6
    MIT license
7
*/
8
 
9
#include "image_helper.h"
10
#include <stdlib.h>
11
#include <math.h>
12
 
13
/*	Upscaling the image uses simple bilinear interpolation	*/
14
int
15
	up_scale_image
16
	(
17
		const unsigned char* const orig,
18
		int width, int height, int channels,
19
		unsigned char* resampled,
20
		int resampled_width, int resampled_height
21
	)
22
{
23
	float dx, dy;
24
	int x, y, c;
25
 
26
    /* error(s) check	*/
27
    if ( 	(width < 1) || (height < 1) ||
28
            (resampled_width < 2) || (resampled_height < 2) ||
29
            (channels < 1) ||
30
            (NULL == orig) || (NULL == resampled) )
31
    {
32
        /*	signify badness	*/
33
        return 0;
34
    }
35
    /*
36
		for each given pixel in the new map, find the exact location
37
		from the original map which would contribute to this guy
38
	*/
39
    dx = (width - 1.0f) / (resampled_width - 1.0f);
40
    dy = (height - 1.0f) / (resampled_height - 1.0f);
41
    for ( y = 0; y < resampled_height; ++y )
42
    {
43
    	/* find the base y index and fractional offset from that	*/
44
    	float sampley = y * dy;
45
    	int inty = (int)sampley;
46
    	/*	if( inty < 0 ) { inty = 0; } else	*/
47
		if( inty > height - 2 ) { inty = height - 2; }
48
		sampley -= inty;
49
        for ( x = 0; x < resampled_width; ++x )
50
        {
51
			float samplex = x * dx;
52
			int intx = (int)samplex;
53
			int base_index;
54
			/* find the base x index and fractional offset from that	*/
55
			/*	if( intx < 0 ) { intx = 0; } else	*/
56
			if( intx > width - 2 ) { intx = width - 2; }
57
			samplex -= intx;
58
			/*	base index into the original image	*/
59
			base_index = (inty * width + intx) * channels;
60
            for ( c = 0; c < channels; ++c )
61
            {
62
            	/*	do the sampling	*/
63
				float value = 0.5f;
64
				value += orig[base_index]
65
							*(1.0f-samplex)*(1.0f-sampley);
66
				value += orig[base_index+channels]
67
							*(samplex)*(1.0f-sampley);
68
				value += orig[base_index+width*channels]
69
							*(1.0f-samplex)*(sampley);
70
				value += orig[base_index+width*channels+channels]
71
							*(samplex)*(sampley);
72
				/*	move to the next channel	*/
73
				++base_index;
74
            	/*	save the new value	*/
75
            	resampled[y*resampled_width*channels+x*channels+c] =
76
						(unsigned char)(value);
77
            }
78
        }
79
    }
80
    /*	done	*/
81
    return 1;
82
}
83
 
84
int
85
	mipmap_image
86
	(
87
		const unsigned char* const orig,
88
		int width, int height, int channels,
89
		unsigned char* resampled,
90
		int block_size_x, int block_size_y
91
	)
92
{
93
	int mip_width, mip_height;
94
	int i, j, c;
95
 
96
	/*	error check	*/
97
	if( (width < 1) || (height < 1) ||
98
		(channels < 1) || (orig == NULL) ||
99
		(resampled == NULL) ||
100
		(block_size_x < 1) || (block_size_y < 1) )
101
	{
102
		/*	nothing to do	*/
103
		return 0;
104
	}
105
	mip_width = width / block_size_x;
106
	mip_height = height / block_size_y;
107
	if( mip_width < 1 )
108
	{
109
		mip_width = 1;
110
	}
111
	if( mip_height < 1 )
112
	{
113
		mip_height = 1;
114
	}
115
	for( j = 0; j < mip_height; ++j )
116
	{
117
		for( i = 0; i < mip_width; ++i )
118
		{
119
			for( c = 0; c < channels; ++c )
120
			{
121
				const int index = (j*block_size_y)*width*channels + (i*block_size_x)*channels + c;
122
				int sum_value;
123
				int u,v;
124
				int u_block = block_size_x;
125
				int v_block = block_size_y;
126
				int block_area;
127
				/*	do a bit of checking so we don't over-run the boundaries
128
					(necessary for non-square textures!)	*/
129
				if( block_size_x * (i+1) > width )
130
				{
131
					u_block = width - i*block_size_y;
132
				}
133
				if( block_size_y * (j+1) > height )
134
				{
135
					v_block = height - j*block_size_y;
136
				}
137
				block_area = u_block*v_block;
138
				/*	for this pixel, see what the average
139
					of all the values in the block are.
140
					note: start the sum at the rounding value, not at 0	*/
141
				sum_value = block_area >> 1;
142
				for( v = 0; v < v_block; ++v )
143
				for( u = 0; u < u_block; ++u )
144
				{
145
					sum_value += orig[index + v*width*channels + u*channels];
146
				}
147
				resampled[j*mip_width*channels + i*channels + c] = sum_value / block_area;
148
			}
149
		}
150
	}
151
	return 1;
152
}
153
 
154
int
155
	scale_image_RGB_to_NTSC_safe
156
	(
157
		unsigned char* orig,
158
		int width, int height, int channels
159
	)
160
{
161
	const float scale_lo = 16.0f - 0.499f;
162
	const float scale_hi = 235.0f + 0.499f;
163
	int i, j;
164
	int nc = channels;
165
	unsigned char scale_LUT[256];
166
	/*	error check	*/
167
	if( (width < 1) || (height < 1) ||
168
		(channels < 1) || (orig == NULL) )
169
	{
170
		/*	nothing to do	*/
171
		return 0;
172
	}
173
	/*	set up the scaling Look Up Table	*/
174
	for( i = 0; i < 256; ++i )
175
	{
176
		scale_LUT[i] = (unsigned char)((scale_hi - scale_lo) * i / 255.0f + scale_lo);
177
	}
178
	/*	for channels = 2 or 4, ignore the alpha component	*/
179
	nc -= 1 - (channels & 1);
180
	/*	OK, go through the image and scale any non-alpha components	*/
181
	for( i = 0; i < width*height*channels; i += channels )
182
	{
183
		for( j = 0; j < nc; ++j )
184
		{
185
			orig[i+j] = scale_LUT[orig[i+j]];
186
		}
187
	}
188
	return 1;
189
}
190
 
191
unsigned char clamp_byte( int x ) { return ( (x) < 0 ? (0) : ( (x) > 255 ? 255 : (x) ) ); }
192
 
193
/*
194
	This function takes the RGB components of the image
195
	and converts them into YCoCg.  3 components will be
196
	re-ordered to CoYCg (for optimum DXT1 compression),
197
	while 4 components will be ordered CoCgAY (for DXT5
198
	compression).
199
*/
200
int
201
	convert_RGB_to_YCoCg
202
	(
203
		unsigned char* orig,
204
		int width, int height, int channels
205
	)
206
{
207
	int i;
208
	/*	error check	*/
209
	if( (width < 1) || (height < 1) ||
210
		(channels < 3) || (channels > 4) ||
211
		(orig == NULL) )
212
	{
213
		/*	nothing to do	*/
214
		return -1;
215
	}
216
	/*	do the conversion	*/
217
	if( channels == 3 )
218
	{
219
		for( i = 0; i < width*height*3; i += 3 )
220
		{
221
			int r = orig[i+0];
222
			int g = (orig[i+1] + 1) >> 1;
223
			int b = orig[i+2];
224
			int tmp = (2 + r + b) >> 2;
225
			/*	Co	*/
226
			orig[i+0] = clamp_byte( 128 + ((r - b + 1) >> 1) );
227
			/*	Y	*/
228
			orig[i+1] = clamp_byte( g + tmp );
229
			/*	Cg	*/
230
			orig[i+2] = clamp_byte( 128 + g - tmp );
231
		}
232
	} else
233
	{
234
		for( i = 0; i < width*height*4; i += 4 )
235
		{
236
			int r = orig[i+0];
237
			int g = (orig[i+1] + 1) >> 1;
238
			int b = orig[i+2];
239
			unsigned char a = orig[i+3];
240
			int tmp = (2 + r + b) >> 2;
241
			/*	Co	*/
242
			orig[i+0] = clamp_byte( 128 + ((r - b + 1) >> 1) );
243
			/*	Cg	*/
244
			orig[i+1] = clamp_byte( 128 + g - tmp );
245
			/*	Alpha	*/
246
			orig[i+2] = a;
247
			/*	Y	*/
248
			orig[i+3] = clamp_byte( g + tmp );
249
		}
250
	}
251
	/*	done	*/
252
	return 0;
253
}
254
 
255
/*
256
	This function takes the YCoCg components of the image
257
	and converts them into RGB.  See above.
258
*/
259
int
260
	convert_YCoCg_to_RGB
261
	(
262
		unsigned char* orig,
263
		int width, int height, int channels
264
	)
265
{
266
	int i;
267
	/*	error check	*/
268
	if( (width < 1) || (height < 1) ||
269
		(channels < 3) || (channels > 4) ||
270
		(orig == NULL) )
271
	{
272
		/*	nothing to do	*/
273
		return -1;
274
	}
275
	/*	do the conversion	*/
276
	if( channels == 3 )
277
	{
278
		for( i = 0; i < width*height*3; i += 3 )
279
		{
280
			int co = orig[i+0] - 128;
281
			int y  = orig[i+1];
282
			int cg = orig[i+2] - 128;
283
			/*	R	*/
284
			orig[i+0] = clamp_byte( y + co - cg );
285
			/*	G	*/
286
			orig[i+1] = clamp_byte( y + cg );
287
			/*	B	*/
288
			orig[i+2] = clamp_byte( y - co - cg );
289
		}
290
	} else
291
	{
292
		for( i = 0; i < width*height*4; i += 4 )
293
		{
294
			int co = orig[i+0] - 128;
295
			int cg = orig[i+1] - 128;
296
			unsigned char a  = orig[i+2];
297
			int y  = orig[i+3];
298
			/*	R	*/
299
			orig[i+0] = clamp_byte( y + co - cg );
300
			/*	G	*/
301
			orig[i+1] = clamp_byte( y + cg );
302
			/*	B	*/
303
			orig[i+2] = clamp_byte( y - co - cg );
304
			/*	A	*/
305
			orig[i+3] = a;
306
		}
307
	}
308
	/*	done	*/
309
	return 0;
310
}
311
 
312
float
313
find_max_RGBE
314
(
315
	unsigned char *image,
316
    int width, int height
317
)
318
{
319
	float max_val = 0.0f;
320
	unsigned char *img = image;
321
	int i, j;
322
	for( i = width * height; i > 0; --i )
323
	{
324
		/* float scale = powf( 2.0f, img[3] - 128.0f ) / 255.0f; */
373 jrf 325
		float scale = (float)ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 );
369 jab 326
		for( j = 0; j < 3; ++j )
327
		{
328
			if( img[j] * scale > max_val )
329
			{
330
				max_val = img[j] * scale;
331
			}
332
		}
333
		/* next pixel */
334
		img += 4;
335
	}
336
	return max_val;
337
}
338
 
339
int
340
RGBE_to_RGBdivA
341
(
342
    unsigned char *image,
343
    int width, int height,
344
    int rescale_to_max
345
)
346
{
347
	/* local variables */
348
	int i, iv;
349
	unsigned char *img = image;
350
	float scale = 1.0f;
351
	/* error check */
352
	if( (!image) || (width < 1) || (height < 1) )
353
	{
354
		return 0;
355
	}
356
	/* convert (note: no negative numbers, but 0.0 is possible) */
357
	if( rescale_to_max )
358
	{
359
		scale = 255.0f / find_max_RGBE( image, width, height );
360
	}
361
	for( i = width * height; i > 0; --i )
362
	{
363
		/* decode this pixel, and find the max */
364
		float r,g,b,e, m;
365
		/* e = scale * powf( 2.0f, img[3] - 128.0f ) / 255.0f; */
373 jrf 366
		e = scale * (float)ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 );
369 jab 367
		r = e * img[0];
368
		g = e * img[1];
369
		b = e * img[2];
370
		m = (r > g) ? r : g;
371
		m = (b > m) ? b : m;
372
		/* and encode it into RGBdivA */
373 jrf 373
		iv = (m != 0.0f) ? (int)(255.0f / m) : 1;
369 jab 374
		iv = (iv < 1) ? 1 : iv;
375
		img[3] = (iv > 255) ? 255 : iv;
376
		iv = (int)(img[3] * r + 0.5f);
377
		img[0] = (iv > 255) ? 255 : iv;
378
		iv = (int)(img[3] * g + 0.5f);
379
		img[1] = (iv > 255) ? 255 : iv;
380
		iv = (int)(img[3] * b + 0.5f);
381
		img[2] = (iv > 255) ? 255 : iv;
382
		/* and on to the next pixel */
383
		img += 4;
384
	}
385
	return 1;
386
}
387
 
388
int
389
RGBE_to_RGBdivA2
390
(
391
    unsigned char *image,
392
    int width, int height,
393
    int rescale_to_max
394
)
395
{
396
	/* local variables */
397
	int i, iv;
398
	unsigned char *img = image;
399
	float scale = 1.0f;
400
	/* error check */
401
	if( (!image) || (width < 1) || (height < 1) )
402
	{
403
		return 0;
404
	}
405
	/* convert (note: no negative numbers, but 0.0 is possible) */
406
	if( rescale_to_max )
407
	{
408
		scale = 255.0f * 255.0f / find_max_RGBE( image, width, height );
409
	}
410
	for( i = width * height; i > 0; --i )
411
	{
412
		/* decode this pixel, and find the max */
413
		float r,g,b,e, m;
414
		/* e = scale * powf( 2.0f, img[3] - 128.0f ) / 255.0f; */
373 jrf 415
		e = scale * (float)ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 );
369 jab 416
		r = e * img[0];
417
		g = e * img[1];
418
		b = e * img[2];
419
		m = (r > g) ? r : g;
420
		m = (b > m) ? b : m;
421
		/* and encode it into RGBdivA */
373 jrf 422
		iv = (m != 0.0f) ? (int)sqrtf( 255.0f * 255.0f / m ) : 1;
369 jab 423
		iv = (iv < 1) ? 1 : iv;
424
		img[3] = (iv > 255) ? 255 : iv;
425
		iv = (int)(img[3] * img[3] * r / 255.0f + 0.5f);
426
		img[0] = (iv > 255) ? 255 : iv;
427
		iv = (int)(img[3] * img[3] * g / 255.0f + 0.5f);
428
		img[1] = (iv > 255) ? 255 : iv;
429
		iv = (int)(img[3] * img[3] * b / 255.0f + 0.5f);
430
		img[2] = (iv > 255) ? 255 : iv;
431
		/* and on to the next pixel */
432
		img += 4;
433
	}
434
	return 1;
435
}