1 /*
2 * imagesource_lanczossinc.cpp - Interpolated scaling filter
3 * Implements Sinc interpolation with Lanczos Window:
4 * sin(pi*x)/(pi*x)*sample*sin(pi*x/windowsize)/(pi*x/windowsize)
5 *
6 * Supports Greyscale, RGB and CMYK data
7 * Doesn't (yet) support random access
8 *
9 * Copyright (c) 2004-2008 by Alastair M. Robinson
10 * Distributed under the terms of the GNU General Public License -
11 * see the file named "COPYING" for more details.
12 *
13 */
14
15 #include <iostream>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <math.h>
19
20 #include "imagesource_lanczossinc.h"
21
22 using namespace std;
23
24
25 // 2D scaling is implemented as a chaining of a horizontal, then a vertical scaling;
26
27
~ImageSource_LanczosSinc()28 ImageSource_LanczosSinc::~ImageSource_LanczosSinc()
29 {
30 if(source)
31 delete source;
32 }
33
34
GetRow(int row)35 ISDataType *ImageSource_LanczosSinc::GetRow(int row)
36 {
37 return(source->GetRow(row));
38 }
39
40
ImageSource_LanczosSinc(struct ImageSource * source,int width,int height,int window)41 ImageSource_LanczosSinc::ImageSource_LanczosSinc(struct ImageSource *source,int width,int height,int window)
42 : ImageSource(source), source(source)
43 {
44 this->source=new ImageSource_HLanczosSinc(this->source,width,window);
45 this->source=new ImageSource_VLanczosSinc(this->source,height,window);
46 xres=this->source->xres;
47 yres=this->source->yres;
48 this->randomaccess=this->source->randomaccess;
49 this->width=width;
50 this->height=height;
51 }
52
53
54 // Sinc function.
55
56 #ifndef M_PI
57 #define M_PI 3.14159265358979323846
58 #endif
59
sinc(double x)60 static double sinc(double x)
61 {
62 x*=M_PI;
63 if(x==0.0)
64 return(1.0);
65 else
66 return(sin(x)/x);
67 }
68
69
70 // The row cache is just a simplistic ring-buffer type cache which handles
71 // the details of tracking several rows of "support" data.
72 // The temporary data does have to be float - or at least wider than ISDataType
73 // and must be clamped since the ringing artifiacts inherent in Lanczos Sinc
74 // can push values out of range.
75
76 class ISLanczosSinc_RowCache
77 {
78 public:
79 ISLanczosSinc_RowCache(ImageSource_VLanczosSinc *source);
80 ~ISLanczosSinc_RowCache();
81 double *GetRow(int row);
82 double *GetCacheRow(int row);
83 private:
84 ImageSource_VLanczosSinc *source;
85 double *cache;
86 double *rowbuffer;
87 int currentrow;
88 };
89
90
~ISLanczosSinc_RowCache()91 ISLanczosSinc_RowCache::~ISLanczosSinc_RowCache()
92 {
93 if(cache)
94 free(cache);
95 if(rowbuffer)
96 free(rowbuffer);
97 }
98
99
ISLanczosSinc_RowCache(ImageSource_VLanczosSinc * source)100 ISLanczosSinc_RowCache::ISLanczosSinc_RowCache(ImageSource_VLanczosSinc *source)
101 : source(source), cache(NULL), rowbuffer(NULL), currentrow(-1)
102 {
103 cache=(double *)malloc(sizeof(double)*source->samplesperpixel*source->width*source->support);
104 rowbuffer=(double *)malloc(sizeof(double)*source->samplesperpixel*source->width);
105 }
106
107
GetRow(int row)108 double *ISLanczosSinc_RowCache::GetRow(int row)
109 {
110 for(int i=0;i<source->width*source->samplesperpixel;++i)
111 rowbuffer[i]=0.0;
112
113 for(int i=0;i<source->support;++i)
114 {
115 int p=i-source->windowsize;
116 int sr=(row*source->source->height)/source->height;
117 double *src=GetCacheRow(sr+p);
118 double f=source->coeff[row*source->support+i];
119 for(int x=0;x<source->width*source->samplesperpixel;++x)
120 {
121 rowbuffer[x]+=f*src[x];
122 }
123 }
124 return(rowbuffer);
125 }
126
127
GetCacheRow(int row)128 double *ISLanczosSinc_RowCache::GetCacheRow(int row)
129 {
130 if(row<0)
131 row=0;
132 if(row>=source->source->height)
133 row=source->source->height-1;
134 int crow=row%source->support;
135 {
136 double *rowptr=cache+crow*source->samplesperpixel*source->width;
137 if(row>currentrow)
138 {
139 currentrow=row;
140 ISDataType *src=source->source->GetRow(row);
141 for(int i=0;i<source->width*source->samplesperpixel;++i)
142 {
143 rowptr[i]=src[i];
144 }
145 }
146 return(rowptr);
147 }
148 }
149
150
151 // Vertical scaling
152
153
~ImageSource_VLanczosSinc()154 ImageSource_VLanczosSinc::~ImageSource_VLanczosSinc()
155 {
156 if(cache)
157 delete cache;
158 if(source)
159 delete source;
160 if(coeff)
161 free(coeff);
162 }
163
164
GetRow(int row)165 ISDataType *ImageSource_VLanczosSinc::GetRow(int row)
166 {
167 int i;
168
169 if(row==currentrow)
170 return(rowbuffer);
171
172 double *srcdata=cache->GetRow(row);
173
174 for(i=0;i<width*samplesperpixel;++i)
175 {
176 double s=srcdata[i];
177 if(s<0.0) s=0.0;
178 if(s>IS_SAMPLEMAX) s=IS_SAMPLEMAX;
179 rowbuffer[i]=int(s);
180 }
181
182 currentrow=row;
183
184 return(rowbuffer);
185 }
186
187
188 // Since Lanczos Sinc is a relatively expensive algorithm to compute in realtime
189 // and the row / column coefficients are constant we precompute them here.
190
PreCalc()191 void ImageSource_VLanczosSinc::PreCalc()
192 {
193 for(int y=0;y<height;++y)
194 {
195 double c=y*source->height; c/=height;
196 int ci=int(c);
197 double f=c-ci;
198 for(int i=0; i<support; ++i)
199 {
200 int p=i-windowsize;
201 double v=f-p;
202 coeff[support*y+i]=sinc(v)*sinc(v/windowsize);
203 }
204 }
205 }
206
207
ImageSource_VLanczosSinc(struct ImageSource * source,int height,int windowsize)208 ImageSource_VLanczosSinc::ImageSource_VLanczosSinc(struct ImageSource *source,int height,int windowsize)
209 : ImageSource(source), source(source), windowsize(windowsize)
210 {
211 this->height=height;
212 yres=(source->yres*height); yres/=source->height;
213
214 support=windowsize*2+1;
215 coeff=(double *)malloc(sizeof(double)*height*support);
216 PreCalc();
217 cache=new ISLanczosSinc_RowCache(this);
218 MakeRowBuffer();
219 randomaccess=false;
220 }
221
222
223 // Horizontal scaling
224
225
GetRow(int row)226 ISDataType *ImageSource_HLanczosSinc::GetRow(int row)
227 {
228 if(row==currentrow)
229 return(rowbuffer);
230
231 ISDataType *src=source->GetRow(row);
232 for(int x=0;x<width;++x)
233 {
234 int sx=(x*source->width)/width;
235 for(int s=0;s<samplesperpixel;++s)
236 {
237 double a=0.0;
238 for(int p=0;p<support;++p)
239 {
240 int lsx=sx+p-windowsize;
241 if(lsx<0) lsx=0;
242 if(lsx>=source->width) lsx=source->width-1;
243
244 a+=src[lsx*samplesperpixel+s]*coeff[x*support+p];
245 }
246 if(a<0.0) a=0.0;
247 if(a>IS_SAMPLEMAX) a=IS_SAMPLEMAX;
248 rowbuffer[x*samplesperpixel+s]=a;
249 }
250 }
251
252 currentrow=row;
253
254 return(rowbuffer);
255 }
256
257
258 // Since Lanczos Sinc is a relatively expensive algorithm to compute in realtime
259 // and the row / column coefficients are constant we precompute them here.
260
PreCalc()261 void ImageSource_HLanczosSinc::PreCalc()
262 {
263 for(int x=0;x<width;++x)
264 {
265 double c=x*source->width; c/=width;
266 int ci=int(c);
267 double f=c-ci;
268 for(int i=0; i<support; ++i)
269 {
270 int p=i-windowsize;
271 double v=f-p;
272 coeff[support*x+i]=sinc(v)*sinc(v/windowsize);
273 }
274 }
275 }
276
277
ImageSource_HLanczosSinc(struct ImageSource * source,int width,int windowsize)278 ImageSource_HLanczosSinc::ImageSource_HLanczosSinc(struct ImageSource *source,int width,int windowsize)
279 : ImageSource(source), source(source), windowsize(windowsize)
280 {
281 this->width=width;
282 xres=(source->xres*width); xres/=source->width;
283
284 support=windowsize*2+1;
285 coeff=(double *)malloc(sizeof(double)*width*support);
286 PreCalc();
287 MakeRowBuffer();
288 }
289
290
~ImageSource_HLanczosSinc()291 ImageSource_HLanczosSinc::~ImageSource_HLanczosSinc()
292 {
293 if(source)
294 delete source;
295 if(coeff)
296 free(coeff);
297 }
298
299
300
301