Coin Logo Coin3D is Free Software,
published under the BSD 3-clause license.
https://coin3d.github.io
https://www.kongsberg.com/en/kogt/
resize.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) Kongsberg Oil & Gas Technologies
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /*
18  * Filtered Image Rescaling
19  *
20  * by Dale Schumacher
21  */
22 
23 /*
24  * Slightly modified by pederb to be able to use it
25  * in simage.
26  *
27  */
28 
29 
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <math.h>
34 #include <assert.h>
35 
36 /* Need to include this so the compiler knows that the simage_resize()
37  method should be defined with __declspec(dllexport) under
38  MSWindows. */
39 #include <simage.h>
40 
41 
42 #ifndef M_PI
43 #define M_PI 3.14159265358979323846
44 #endif /* !M_PI */
45 
46 typedef struct {
47  int xsize; /* horizontal size of the image in Pixels */
48  int ysize; /* vertical size of the image in Pixels */
49  int bpp; /* bytes per pixel */
50  unsigned char * data; /* pointer to first scanline of image */
51  int span; /* byte offset between two scanlines */
52 } Image;
53 
54 static void
55 get_row(unsigned char * row, Image * image, int y)
56 {
57  assert(y >= 0);
58  assert(y < image->ysize);
59 
60  memcpy(row,
61  image->data + (y * image->span),
62  (image->bpp * image->xsize));
63 }
64 
65 static void
66 get_column(unsigned char * column, Image * image, int x)
67 {
68  int i, j, d, bpp, ysize;
69  unsigned char * p;
70 
71  assert(x >= 0);
72  assert(x < image->xsize);
73 
74  d = image->span;
75  bpp = image->bpp;
76  ysize = image->ysize;
77  for(i = 0, p = image->data + x * bpp; i < ysize; p += d, i++) {
78  for (j = 0; j < bpp; j++) {
79  *column++ = p[j];
80  }
81  }
82 }
83 
84 static void
85 put_pixel(Image * image, int x, int y, float * data)
86 {
87  int i, bpp;
88  unsigned char * p;
89  float val;
90 
91  assert(x >= 0);
92  assert(x < image->xsize);
93  assert(y >= 0);
94  assert(y < image->ysize);
95 
96  bpp = image->bpp;
97  p = image->data + image->span * y + x * bpp;
98  for (i = 0; i < bpp; i++) {
99  val = data[i];
100  if (val < 0.0f) val = 0.0f;
101  else if (val > 255.0f) val = 255.0f;
102  *p++ = (unsigned char) val;
103  }
104 }
105 
106 
107 /*
108  * filter function definitions
109  */
110 
111 #define filter_support (1.0f)
112 
113 static float
114 filter(float t)
115 {
116  /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */
117  if(t < 0.0f) t = -t;
118  if(t < 1.0f) return((2.0f * t - 3.0f) * t * t + 1.0f);
119  return(0.0f);
120 }
121 
122 #define box_support (0.5f)
123 
124 static float
125 box_filter(float t)
126 {
127  if((t > -0.5f) && (t <= 0.5f)) return(1.0f);
128  return(0.0f);
129 }
130 
131 #define triangle_support (1.0f)
132 
133 static float
135 {
136  if(t < 0.0f) t = -t;
137  if(t < 1.0f) return(1.0f - t);
138  return(0.0f);
139 }
140 
141 #define bell_support (1.5f)
142 
143 static float
144 bell_filter(float t) /* box (*) box (*) box */
145 {
146  if(t < 0.0f) t = -t;
147  if(t < 0.5f) return(0.75f - (t * t));
148  if(t < 1.5f) {
149  t = (t - 1.5f);
150  return(0.5f * (t * t));
151  }
152  return(0.0f);
153 }
154 
155 #define B_spline_support (2.0f)
156 
157 static float
158 B_spline_filter(float t) /* box (*) box (*) box (*) box */
159 {
160  float tt;
161 
162  if(t < 0.0f) t = -t;
163  if(t < 1.0f) {
164  tt = t * t;
165  return((.5f * tt * t) - tt + (2.0f / 3.0f));
166  } else if(t < 2.0f) {
167  t = 2.0f - t;
168  return((1.0f / 6.0f) * (t * t * t));
169  }
170  return(0.0f);
171 }
172 
173 static float
174 sinc(float x)
175 {
176  x *= (float)M_PI;
177  if(x != 0.0f) return (float)(sin(x) / x);
178  return(1.0f);
179 }
180 
181 #define Lanczos3_support (3.0f)
182 
183 static float
185 {
186  if(t < 0.0f) t = -t;
187  if(t < 3.0f) return(sinc(t) * sinc(t/3.0f));
188  return(0.0f);
189 }
190 
191 #define Mitchell_support (2.0)
192 
193 #define B (1.0f / 3.0f)
194 #define C (1.0f / 3.0f)
195 
196 static float
198 {
199  float tt;
200 
201  tt = t * t;
202  if(t < 0.0f) t = -t;
203  if(t < 1.0f) {
204  t = (((12.0f - 9.0f * B - 6.0f * C) * (t * tt))
205  + ((-18.0f + 12.0f * B + 6.0f * C) * tt)
206  + (6.0f - 2.0f * B));
207  return (t / 6.0f);
208  }
209  else if (t < 2.0f) {
210  t = (((-1.0f * B - 6.0f * C) * (t * tt))
211  + ((6.0f * B + 30.0f * C) * tt)
212  + ((-12.0f * B - 48.0f * C) * t)
213  + (8.0f * B + 24.0f * C));
214  return (t / 6.0f);
215  }
216  return(0.0f);
217 }
218 
219 /*
220  * image rescaling routine
221  */
222 
223 typedef struct {
224  int pixel;
225  float weight;
226 } CONTRIB;
227 
228 typedef struct {
229  int n; /* number of contributors */
230  CONTRIB * p; /* pointer to list of contributions */
231 } CLIST;
232 
233 static Image *
234 new_image(int xsize, int ysize, int bpp, unsigned char * data)
235 {
236  Image * img = (Image*) malloc(sizeof(Image));
237  img->xsize = xsize;
238  img->ysize = ysize;
239  img->bpp = bpp;
240  img->span = xsize * bpp;
241  img->data = data;
242  if (data == NULL) img->data = (unsigned char*) malloc((size_t)img->span*img->ysize);
243  return img;
244 }
245 
246 static void
247 zoom(Image * dst, /* destination image structure */
248  Image * src, /* source image structure */
249  float (*filterf)(float), /* filter function */
250  float fwidth) /* filter width (support) */
251 {
252  CLIST * contrib;
253  Image * tmp; /* intermediate image */
254  float xscale, yscale; /* zoom scale factors */
255  int i, j, k, b; /* loop variables */
256  int n; /* pixel number */
257  int left, right; /* filter calculation variables */
258  float center; /* filter calculation variables */
259  float width, fscale, weight; /* filter calculation variables */
260  unsigned char * raster; /* a row or column of pixels */
261  float pixel[4]; /* one pixel */
262  int bpp;
263  unsigned char * dstptr;
264  int dstxsize, dstysize;
265 
266  bpp = src->bpp;
267  dstxsize = dst->xsize;
268  dstysize = dst->ysize;
269 
270  /* create intermediate image to hold horizontal zoom */
271  tmp = new_image(dstxsize, src->ysize, dst->bpp, NULL);
272  xscale = (float) dstxsize / (float) src->xsize;
273  yscale = (float) dstysize / (float) src->ysize;
274 
275  /* pre-calculate filter contributions for a row */
276  contrib = (CLIST *)calloc(dstxsize, sizeof(CLIST));
277  if(xscale < 1.0f) {
278  width = fwidth / xscale;
279  fscale = 1.0f / xscale;
280  for(i = 0; i < dstxsize; i++) {
281  contrib[i].n = 0;
282  contrib[i].p = (CONTRIB *)calloc((int) (width * 2 + 1),
283  sizeof(CONTRIB));
284  center = (float) i / xscale;
285  left = (int) ceil(center - width);
286  right = (int) floor(center + width);
287  for(j = left; j <= right; j++) {
288  weight = center - (float) j;
289  weight = (*filterf)(weight / fscale) / fscale;
290  if(j < 0) {
291  n = -j;
292  }
293  else if(j >= src->xsize) {
294  n = (src->xsize - j) + src->xsize - 1;
295  }
296  else {
297  n = j;
298  }
299  k = contrib[i].n++;
300  contrib[i].p[k].pixel = n*bpp;
301  contrib[i].p[k].weight = weight;
302  }
303  }
304  }
305  else {
306  for(i = 0; i < dstxsize; i++) {
307  contrib[i].n = 0;
308  contrib[i].p = (CONTRIB *)calloc((int) (fwidth * 2 + 1),
309  sizeof(CONTRIB));
310  center = (float) i / xscale;
311  left = (int) ceil(center - fwidth);
312  right = (int) floor(center + fwidth);
313  for(j = left; j <= right; j++) {
314  weight = center - (float) j;
315  weight = (*filterf)(weight);
316  if(j < 0) {
317  n = -j;
318  }
319  else if(j >= src->xsize) {
320  n = (src->xsize - j) + src->xsize - 1;
321  }
322  else {
323  n = j;
324  }
325  k = contrib[i].n++;
326  contrib[i].p[k].pixel = n*bpp;
327  contrib[i].p[k].weight = weight;
328  }
329  }
330  }
331 
332  /* apply filter to zoom horizontally from src to tmp */
333  raster = (unsigned char *)calloc(src->xsize, src->bpp);
334 
335  dstptr = tmp->data;
336 
337  for(k = 0; k < tmp->ysize; k++) {
338  get_row(raster, src, k);
339  for(i = 0; i < tmp->xsize; i++) {
340  for (b = 0; b < bpp; b++) pixel[b] = 0.0f;
341  for(j = 0; j < contrib[i].n; j++) {
342  for (b = 0; b < bpp; b++) {
343  pixel[b] += raster[contrib[i].p[j].pixel+b]
344  * contrib[i].p[j].weight;
345  }
346  }
347 #if 1 /* obsoleted 2001-11-18 pederb. Too slow */
348  put_pixel(tmp, i, k, pixel);
349 #else /* new code */
350  for (b = 0; b < bpp; b++) {
351  float val = pixel[b];
352  if (val < 0.0f) val = 0.0f;
353  else if (val > 255.0f) val = 255.0f;
354  *dstptr++ = (unsigned char ) val;
355  }
356 #endif /* new, faster code */
357  }
358  }
359  free(raster);
360 
361  /* free the memory allocated for horizontal filter weights */
362  for(i = 0; i < tmp->xsize; i++) {
363  free(contrib[i].p);
364  }
365  free(contrib);
366 
367  /* pre-calculate filter contributions for a column */
368  contrib = (CLIST *)calloc(dstysize, sizeof(CLIST));
369  if(yscale < 1.0f) {
370  width = fwidth / yscale;
371  fscale = 1.0f / yscale;
372  for(i = 0; i < dstysize; i++) {
373  contrib[i].n = 0;
374  contrib[i].p = (CONTRIB *)calloc((int) (width * 2 + 1),
375  sizeof(CONTRIB));
376  center = (float) i / yscale;
377  left = (int) ceil(center - width);
378  right = (int) floor(center + width);
379  for(j = left; j <= right; j++) {
380  weight = center - (float) j;
381  weight = (*filterf)(weight / fscale) / fscale;
382  if(j < 0) {
383  n = -j;
384  }
385  else if(j >= tmp->ysize) {
386  n = (tmp->ysize - j) + tmp->ysize - 1;
387  }
388  else {
389  n = j;
390  }
391  k = contrib[i].n++;
392  contrib[i].p[k].pixel = n*bpp;
393  contrib[i].p[k].weight = weight;
394  }
395  }
396  }
397  else {
398  for(i = 0; i < dstysize; i++) {
399  contrib[i].n = 0;
400  contrib[i].p = (CONTRIB *)calloc((int) (fwidth * 2 + 1),
401  sizeof(CONTRIB));
402  center = (float) i / yscale;
403  left = (int) ceil(center - fwidth);
404  right = (int) floor(center + fwidth);
405  for(j = left; j <= right; j++) {
406  weight = center - (float) j;
407  weight = (*filterf)(weight);
408  if(j < 0) {
409  n = -j;
410  }
411  else if(j >= tmp->ysize) {
412  n = (tmp->ysize - j) + tmp->ysize - 1;
413  }
414  else {
415  n = j;
416  }
417  k = contrib[i].n++;
418  contrib[i].p[k].pixel = n*bpp;
419  contrib[i].p[k].weight = weight;
420  }
421  }
422  }
423 
424  /* apply filter to zoom vertically from tmp to dst */
425  raster = (unsigned char *) calloc(tmp->ysize, tmp->bpp);
426  for(k = 0; k < dstxsize; k++) {
427  get_column(raster, tmp, k);
428  dstptr = dst->data + k * bpp;
429  for(i = 0; i < dstysize; i++) {
430  for (b = 0; b < bpp; b++) pixel[b] = 0.0f;
431  for(j = 0; j < contrib[i].n; ++j) {
432  for (b = 0; b < bpp; b++) {
433  pixel[b] += raster[contrib[i].p[j].pixel+b]
434  * contrib[i].p[j].weight;
435  }
436  }
437 #if 1 /* obsoleted 2001-11-18 pederb. Too slow */
438  put_pixel(dst, k, i, pixel);
439 #else /* new code */
440  for (b = 0; b < bpp; b++) {
441  float val = pixel[b];
442  if (val < 0.0f) val = 0.0f;
443  else if (val > 255.0f) val = 255.0f;
444  dstptr[b] = (unsigned char) val;
445  }
446 #endif /* new, faster code */
447  dstptr += bpp * dstxsize;
448  }
449  }
450 
451  free(raster);
452 
453  /* free the memory allocated for vertical filter weights */
454  for(i = 0; i < dstysize; ++i) {
455  free(contrib[i].p);
456  }
457  free(contrib);
458  free(tmp->data);
459  free(tmp);
460 }
461 
462 /*
463  * a pretty lame resize-function
464  */
465 static unsigned char *
466 simage_resize_fast(unsigned char *src, int width,
467  int height, int num_comp,
468  int newwidth, int newheight)
469 {
470  float sx, sy, dx, dy;
471  int src_bpr, dest_bpr, xstop, ystop, x, y, offset, i;
472  unsigned char *dest =
473  (unsigned char*) malloc((size_t)newwidth*newheight*num_comp);
474 
475  dx = ((float)width)/((float)newwidth);
476  dy = ((float)height)/((float)newheight);
477  src_bpr = width * num_comp;
478  dest_bpr = newwidth * num_comp;
479 
480  sy = 0.0f;
481  ystop = newheight * dest_bpr;
482  xstop = newwidth * num_comp;
483  for (y = 0; y < ystop; y += dest_bpr) {
484  sx = 0.0f;
485  for (x = 0; x < xstop; x += num_comp) {
486  offset = ((int)sy)*src_bpr + ((int)sx)*num_comp;
487  for (i = 0; i < num_comp; i++) dest[x+y+i] = src[offset+i];
488  sx += dx;
489  }
490  sy += dy;
491  }
492  return dest;
493 }
494 
495 
496 // FIXME: pederb suspects that MSVC++ v6 mis-compiles some code in the
497 // resize functionality -- which again causes a crash whenever (?) a
498 // resize is attempted with a simage-library compiled in release mode.
499 // This sounds very nasty with regard to application programmers using
500 // Coin / simage, and should be investigated ASAP. 20010904 mortene.
501 
502 // UPDATE: I haven't observed any crashes in the resize functionality
503 // for several years. That goes for debug builds as well as for
504 // release builds. Perhaps the bug has been fixed in the latest
505 // service pack, SP5 (which I'm using). 20031210 thammer.
506 
507 // FIXME: methinks the type of the first argument should have been
508 // ``const unsigned char *''. Can't change it now, though, as it'd
509 // probably break ABI compatibility (?). Wait for simage2. 20010809 mortene.
510 
511 unsigned char *
512 simage_resize(unsigned char * src, int width,
513  int height, int num_comp,
514  int newwidth, int newheight)
515 {
516  unsigned char * dstdata;
517  Image * srcimg, * dstimg;
518 
519 #if 0 /* for comparing speed of resize functions */
520  return simage_resize_fast(src, width,
521  height, num_comp,
522  newwidth, newheight);
523 #endif /* testing only */
524  srcimg = new_image(width, height, num_comp, src);
525  dstimg = new_image(newwidth, newheight, num_comp, NULL);
526 
527  /* Using the bell filter as default */
528  zoom(dstimg, srcimg, bell_filter, bell_support);
529 
530  dstdata = dstimg->data;
531  free(srcimg);
532  free(dstimg);
533  return dstdata;
534 }
int ysize
Definition: resize.c:48
int bpp
Definition: resize.c:49
static float triangle_filter(float t)
Definition: resize.c:134
#define M_PI
Definition: resize.c:43
static float box_filter(float t)
Definition: resize.c:125
#define C
Definition: resize.c:194
int span
Definition: resize.c:51
static float Lanczos3_filter(float t)
Definition: resize.c:184
static void put_pixel(Image *image, int x, int y, float *data)
Definition: resize.c:85
int n
Definition: resize.c:229
Definition: resize.c:46
static unsigned char * simage_resize_fast(unsigned char *src, int width, int height, int num_comp, int newwidth, int newheight)
Definition: resize.c:466
int pixel
Definition: resize.c:224
static float Mitchell_filter(float t)
Definition: resize.c:197
static float sinc(float x)
Definition: resize.c:174
static float B_spline_filter(float t)
Definition: resize.c:158
#define B
Definition: resize.c:193
Windows specific information.
int xsize
Definition: resize.c:47
float weight
Definition: resize.c:225
unsigned char * simage_resize(unsigned char *src, int width, int height, int num_comp, int newwidth, int newheight)
Definition: resize.c:512
static void get_row(unsigned char *row, Image *image, int y)
Definition: resize.c:55
Definition: resize.c:228
static float filter(float t)
Definition: resize.c:114
unsigned char * data
Definition: resize.c:50
CONTRIB * p
Definition: resize.c:230
#define bell_support
Definition: resize.c:141
static Image * new_image(int xsize, int ysize, int bpp, unsigned char *data)
Definition: resize.c:234
static void get_column(unsigned char *column, Image *image, int x)
Definition: resize.c:66
static float bell_filter(float t)
Definition: resize.c:144
static void zoom(Image *dst, Image *src, float(*filterf)(float), float fwidth)
Definition: resize.c:247