1//
2//  PRConvolve55.m
3//  PRICE
4//
5//  Created by Riccardo Mottola on Sat Jan 18 2003.
6//  Copyright (c) 2003-2014 Carduus. All rights reserved.
7//
8// This application is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
9// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
10
11
12#include <math.h>
13#include <limits.h>
14
15#import "PRConvolve55.h"
16#import "PRGrayscaleFilter.h"
17
18@implementation PRConvolve55
19
20- (PRImage *)filterImage:(PRImage *)image with:(NSArray *)parameters progressPanel:(PRCProgress *)progressPanel
21{
22    NSArray     *convArray;
23    int         convMat[5][5];
24    int         offset;
25    float       scale;
26    BOOL        autoScale;
27    int         i, j, k;
28
29    /* interpret the parameters */
30    convArray = [parameters objectAtIndex:0];
31
32    k = 0;
33    for (i = 0; i < 5; i++)
34        for (j = 0; j < 5; j++)
35            convMat[i][j] = [[convArray objectAtIndex:k++] intValue];
36
37    offset = [[parameters objectAtIndex:1] intValue];
38    scale = [[parameters objectAtIndex:2] floatValue];
39    autoScale = [[parameters objectAtIndex:3] boolValue];
40
41    return [self convolveImage:image :convMat :offset :scale :autoScale :progressPanel];
42}
43
44- (NSString *)actionName
45{
46    return @"Convolve 5x5";
47}
48
49- (PRImage *)convolveImage:(PRImage *)srcImage :(int[5][5])convMat :(int)offset :(float)scale :(BOOL)autoScale :(PRCProgress *)prPan
50{
51  NSBitmapImageRep   *srcImageRep;
52  PRImage            *destImage;
53  NSBitmapImageRep   *destImageRep;
54  NSInteger          w, h;
55  NSInteger          x, y; /* image scanning variables */
56  NSInteger          i, j; /* convolve matrix scanning */
57  unsigned char      *srcData;
58  unsigned char      *destData;
59  NSInteger          srcSamplesPerPixel;
60  NSInteger          destSamplesPerPixel;
61  register NSInteger srcBytesPerRow;
62  register NSInteger destBytesPerRow;
63  register NSInteger srcBytesPerPixel;
64  register NSInteger destBytesPerPixel;
65  float              normalizeFactor;
66  int                minVal, maxVal;
67  BOOL               hasAlpha;
68
69    progressSteps = 0;
70    totalProgressSteps = 2;
71    if (autoScale)
72        totalProgressSteps++;
73    progPanel = prPan;
74
75    /* get source image representation and associated information */
76    if (progPanel != nil)
77    {
78        [self setActivity:@"get image representation"];
79        [self advanceProgress];
80    }
81    srcImageRep = [srcImage bitmapRep];
82
83    w = [srcImageRep pixelsWide];
84    h = [srcImageRep pixelsHigh];
85    srcBytesPerRow = [srcImageRep bytesPerRow];
86    srcSamplesPerPixel = [srcImageRep samplesPerPixel];
87    srcBytesPerPixel = [srcImageRep bitsPerPixel] / 8;
88    destSamplesPerPixel = srcSamplesPerPixel;
89
90    /* check bith depth and color/greyscale image */
91    hasAlpha = [srcImage hasAlpha];
92
93    /* allocate destination image and its representation */
94    destImage = [[PRImage alloc] initWithSize:NSMakeSize(w, h)];
95    destImageRep = [[NSBitmapImageRep alloc]
96                initWithBitmapDataPlanes:NULL
97                              pixelsWide:w
98                              pixelsHigh:h
99                           bitsPerSample:[srcImageRep bitsPerSample]
100                         samplesPerPixel:[srcImageRep samplesPerPixel]
101                                hasAlpha:hasAlpha
102                                isPlanar:NO
103                          colorSpaceName:[srcImageRep colorSpaceName]
104                             bytesPerRow:0
105                            bitsPerPixel:0];
106    srcData = [srcImageRep bitmapData];
107    destData = [destImageRep bitmapData];
108    destBytesPerRow = [destImageRep bytesPerRow];
109    destBytesPerPixel = [destImageRep bitsPerPixel] / 8;
110
111    if ([srcImage hasColor])
112    {
113        int convSumR, convSumG, convSumB;
114
115        if (autoScale)
116        {
117            if (progPanel != nil)
118            {
119                [self setActivity:@"Evaluating range"];
120                [self advanceProgress];
121            }
122            minVal = INT_MAX;
123            maxVal = INT_MIN;
124
125            /* calibrate output range */
126            for (y = 0 + 2; y < h - 3; y++)
127                for (x = 0 + 2; x < w - 3; x++)
128                {
129                    convSumR = 0;
130                    convSumG = 0;
131                    convSumB = 0;
132                    for (i = -2; i <= 2; i++)
133                        for (j = -2; j <= 2; j++)
134                        {
135                            convSumR += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
136                            convSumG += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 1];
137                            convSumB += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 2];
138                        }
139                    if (convSumR + convSumG + convSumB > maxVal)
140                        maxVal = convSumR + convSumG + convSumB;
141                    if (convSumR + convSumG + convSumB < minVal)
142                        minVal = convSumR + convSumG + convSumB;
143                }
144
145            maxVal = maxVal / 3;
146            minVal = minVal / 3;
147            printf("Max %d, min %d\n", maxVal, minVal);
148            normalizeFactor = (float)fabs(maxVal -minVal)/(float)UCHAR_MAX;
149            printf("normalize factor: %f\n", normalizeFactor);
150            offset = -minVal;
151            scale = normalizeFactor;
152        }
153
154        printf("offset: %d, scale:%f\n", offset, scale);
155
156        if (progPanel != nil)
157        {
158            [self setActivity:@"convolving"];
159            [self advanceProgress];
160        }
161        /* execute the actual filtering */
162        /* the borders */
163        for (y = 0; y < 0 + 2; y++)
164        {
165            /* top left corner */
166            for (x = 0; x < (0 + 2); x++)
167            {
168                convSumR = 0;
169                convSumG = 0;
170                convSumB = 0;
171                for (i = -2; i <= -1 - y; i++)
172                {
173                    for (j = -2; j <= -1 - x; j++)
174                    {
175                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+(-i-1)) * srcBytesPerRow + (x+(-j-1))*srcBytesPerPixel];
176                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+(-i-1)) * srcBytesPerRow + (x+(-j-1))*srcBytesPerPixel + 1];
177                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+(-i-1)) * srcBytesPerRow + (x+(-j-1))*srcBytesPerPixel + 2];
178                    }
179                    for (j = 0 - x; j <= 2; j++)
180                    {
181                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+(-i-1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
182                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+(-i-1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 1];
183                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+(-i-1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 2];
184                    }
185                }
186                for (i = 0 - y; i <= 2; i++)
187                {
188                    for (j = -2; j <= -1 - x; j++)
189                    {
190                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j-1))*srcBytesPerPixel];
191                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j-1))*srcBytesPerPixel + 1];
192                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j-1))*srcBytesPerPixel + 2];
193                    }
194                    for (j = 0 - x; j <= 2; j++)
195                    {
196                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
197                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 1];
198                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 2];
199                    }
200                }
201                convSumR += offset;
202                convSumG += offset;
203                convSumB += offset;
204                convSumR = (int)rint((float)convSumR / scale);
205                convSumG = (int)rint((float)convSumG / scale);
206                convSumB = (int)rint((float)convSumB / scale);
207                if (convSumR < 0)
208                    convSumR = 0;
209                if (convSumG < 0)
210                    convSumG = 0;
211                if (convSumB < 0)
212                    convSumB = 0;
213                if (convSumR > UCHAR_MAX)
214                    convSumR = UCHAR_MAX;
215                if (convSumG > UCHAR_MAX)
216                    convSumG = UCHAR_MAX;
217                if (convSumB > UCHAR_MAX)
218                    convSumB = UCHAR_MAX;
219                destData[destBytesPerRow * y + destBytesPerPixel * x]     = (unsigned char)convSumR;
220                destData[destBytesPerRow * y + destBytesPerPixel * x + 1] = (unsigned char)convSumG;
221                destData[destBytesPerRow * y + destBytesPerPixel * x + 2] = (unsigned char)convSumB;
222            }
223            /* top band */
224            for (x = (0 + 2); x < (w - 3); x++)
225            {
226                convSumR = 0;
227                convSumG = 0;
228                convSumB = 0;
229                for (i = -2; i <= -1 - y; i++)
230                    for (j = -2; j <= 2; j++)
231                    {
232                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+(-i-1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
233                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+(-i-1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 1];
234                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+(-i-1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 2];
235                    }
236                for (i = 0 - y; i <= 2; i++)
237                    for (j = -2; j <= 2; j++)
238                    {
239                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
240                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 1];
241                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 2];
242                    }
243                convSumR += offset;
244                convSumG += offset;
245                convSumB += offset;
246                convSumR = (int)rint((float)convSumR / scale);
247                convSumG = (int)rint((float)convSumG / scale);
248                convSumB = (int)rint((float)convSumB / scale);
249                if (convSumR < 0)
250                    convSumR = 0;
251                if (convSumG < 0)
252                    convSumG = 0;
253                if (convSumB < 0)
254                    convSumB = 0;
255                if (convSumR > UCHAR_MAX)
256                    convSumR = UCHAR_MAX;
257                if (convSumG > UCHAR_MAX)
258                    convSumG = UCHAR_MAX;
259                if (convSumB > UCHAR_MAX)
260                    convSumB = UCHAR_MAX;
261                destData[destBytesPerRow * y + destBytesPerPixel * x]     = (unsigned char)convSumR;
262                destData[destBytesPerRow * y + destBytesPerPixel * x + 1] = (unsigned char)convSumG;
263                destData[destBytesPerRow * y + destBytesPerPixel * x + 2] = (unsigned char)convSumB;
264            }
265            /* top right corner */
266            for (x = (w - 3); x < w; x++)
267            {
268                convSumR = 0;
269                convSumG = 0;
270                convSumB = 0;
271                for (i = -2; i <= -1 - y; i++)
272                {
273                    for (j = -2; j <= -1 - (x - w); j++)
274                    {
275                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+(-i-1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
276                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+(-i-1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 1];
277                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+(-i-1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 2];
278                    }
279                    for (j = 0 - (x - w); j <= 2; j++)
280                    {
281                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+(-i-1)) * srcBytesPerRow + (x+(-j+1))*srcBytesPerPixel];
282                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+(-i-1)) * srcBytesPerRow + (x+(-j+1))*srcBytesPerPixel + 1];
283                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+(-i-1)) * srcBytesPerRow + (x+(-j+1))*srcBytesPerPixel + 2];
284                    }
285                }
286                for (i = 0 - y; i <= 2; i++)
287                {
288                    for (j = -2; j <= -1 - (x - w); j++)
289                    {
290                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
291                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 1];
292                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 2];
293                    }
294                    for (j = 0 - (x - w); j <= 2; j++)
295                    {
296                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j+1))*srcBytesPerPixel];
297                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j+1))*srcBytesPerPixel + 1];
298                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j+1))*srcBytesPerPixel + 2];
299                    }
300                }
301                convSumR += offset;
302                convSumG += offset;
303                convSumB += offset;
304                convSumR = (int)rint((float)convSumR / scale);
305                convSumG = (int)rint((float)convSumG / scale);
306                convSumB = (int)rint((float)convSumB / scale);
307                if (convSumR < 0)
308                    convSumR = 0;
309                if (convSumG < 0)
310                    convSumG = 0;
311                if (convSumB < 0)
312                    convSumB = 0;
313                if (convSumR > UCHAR_MAX)
314                    convSumR = UCHAR_MAX;
315                if (convSumG > UCHAR_MAX)
316                    convSumG = UCHAR_MAX;
317                if (convSumB > UCHAR_MAX)
318                    convSumB = UCHAR_MAX;
319                destData[destBytesPerRow * y + destBytesPerPixel * x]     = (unsigned char)convSumR;
320                destData[destBytesPerRow * y + destBytesPerPixel * x + 1] = (unsigned char)convSumG;
321                destData[destBytesPerRow * y + destBytesPerPixel * x + 2] = (unsigned char)convSumB;
322            }
323        }
324        for (y = 0 + 2; y < h - 3; y++)
325        {
326            /* left band */
327            for (x = 0; x < (0 + 2); x++)
328            {
329                convSumR = 0;
330                convSumG = 0;
331                convSumB = 0;
332                for (i = -2; i <= 2; i++)
333                {
334                    for (j = -2; j <= -1 - x; j++)
335                    {
336                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j-1))*srcBytesPerPixel];
337                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j-1))*srcBytesPerPixel + 1];
338                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j-1))*srcBytesPerPixel + 2];
339                    }
340                    for (j = 0 - x; j <= 2; j++)
341                    {
342                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
343                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 1];
344                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 2];
345                    }
346                }
347                convSumR += offset;
348                convSumG += offset;
349                convSumB += offset;
350                convSumR = (int)rint((float)convSumR / scale);
351                convSumG = (int)rint((float)convSumG / scale);
352                convSumB = (int)rint((float)convSumB / scale);
353                if (convSumR < 0)
354                    convSumR = 0;
355                if (convSumG < 0)
356                    convSumG = 0;
357                if (convSumB < 0)
358                    convSumB = 0;
359                if (convSumR > UCHAR_MAX)
360                    convSumR = UCHAR_MAX;
361                if (convSumG > UCHAR_MAX)
362                    convSumG = UCHAR_MAX;
363                if (convSumB > UCHAR_MAX)
364                    convSumB = UCHAR_MAX;
365                destData[destBytesPerRow * y + destBytesPerPixel * x]     = (unsigned char)convSumR;
366                destData[destBytesPerRow * y + destBytesPerPixel * x + 1] = (unsigned char)convSumG;
367                destData[destBytesPerRow * y + destBytesPerPixel * x + 2] = (unsigned char)convSumB;
368            }
369            /* right band */
370            for (x = (w - 3); x < w; x++)
371            {
372                convSumR = 0;
373                convSumG = 0;
374                convSumB = 0;
375                for (i = -2; i <= 2; i++)
376                {
377                    for (j = -2; j <= -1 - (x - w); j++)
378                    {
379                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
380                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 1];
381                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 2];
382                    }
383                    for (j = 0 - (x - w); j <= 2; j++)
384                    {
385                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j+1))*srcBytesPerPixel];
386                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j+1))*srcBytesPerPixel + 1];
387                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j+1))*srcBytesPerPixel + 2];
388                    }
389                }
390                convSumR += offset;
391                convSumG += offset;
392                convSumB += offset;
393                convSumR = (int)rint((float)convSumR / scale);
394                convSumG = (int)rint((float)convSumG / scale);
395                convSumB = (int)rint((float)convSumB / scale);
396                if (convSumR < 0)
397                    convSumR = 0;
398                if (convSumG < 0)
399                    convSumG = 0;
400                if (convSumB < 0)
401                    convSumB = 0;
402                if (convSumR > UCHAR_MAX)
403                    convSumR = UCHAR_MAX;
404                if (convSumG > UCHAR_MAX)
405                    convSumG = UCHAR_MAX;
406                if (convSumB > UCHAR_MAX)
407                    convSumB = UCHAR_MAX;
408                destData[destBytesPerRow * y + destBytesPerPixel * x]     = (unsigned char)convSumR;
409                destData[destBytesPerRow * y + destBytesPerPixel * x + 1] = (unsigned char)convSumG;
410                destData[destBytesPerRow * y + destBytesPerPixel * x + 2] = (unsigned char)convSumB;
411            }
412        }
413        for (y = h - 3; y < h; y++)
414        {
415            /* bottom left corner */
416            for (x = 0; x < (0 + 2); x++)
417            {
418                convSumR = 0;
419                convSumG = 0;
420                convSumB = 0;
421                for (i = -2; i <= -1 - (y - h); i++)
422                {
423                    for (j = -2; j <= -1 - x; j++)
424                    {
425                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j-1))*srcBytesPerPixel];
426                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j-1))*srcBytesPerPixel + 1];
427                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j-1))*srcBytesPerPixel + 2];
428                    }
429                    for (j = 0 - x; j <= 2; j++)
430                    {
431                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
432                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 1];
433                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 2];
434                    }
435                }
436                for (i = 0 - (y - h); i <= 2; i++)
437                {
438                    for (j = -2; j <= -1 - x; j++)
439                    {
440                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+(-i+1)) * srcBytesPerRow + (x+(-j-1))*srcBytesPerPixel];
441                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+(-i+1)) * srcBytesPerRow + (x+(-j-1))*srcBytesPerPixel + 1];
442                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+(-i+1)) * srcBytesPerRow + (x+(-j-1))*srcBytesPerPixel + 2];
443                    }
444                    for (j = 0 - x; j <= 2; j++)
445                    {
446                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+(-i+1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
447                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+(-i+1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 1];
448                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+(-i+1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 2];
449                    }
450                }
451                convSumR += offset;
452                convSumG += offset;
453                convSumB += offset;
454                convSumR = (int)rint((float)convSumR / scale);
455                convSumG = (int)rint((float)convSumG / scale);
456                convSumB = (int)rint((float)convSumB / scale);
457                if (convSumR < 0)
458                    convSumR = 0;
459                if (convSumG < 0)
460                    convSumG = 0;
461                if (convSumB < 0)
462                    convSumB = 0;
463                if (convSumR > UCHAR_MAX)
464                    convSumR = UCHAR_MAX;
465                if (convSumG > UCHAR_MAX)
466                    convSumG = UCHAR_MAX;
467                if (convSumB > UCHAR_MAX)
468                    convSumB = UCHAR_MAX;
469                destData[destBytesPerRow * y + destBytesPerPixel * x]     = (unsigned char)convSumR;
470                destData[destBytesPerRow * y + destBytesPerPixel * x + 1] = (unsigned char)convSumG;
471                destData[destBytesPerRow * y + destBytesPerPixel * x + 2] = (unsigned char)convSumB;
472            }
473            /* bottom band */
474            for (x = (0 + 2); x < (w - 3); x++)
475            {
476                convSumR = 0;
477                convSumG = 0;
478                convSumB = 0;
479                for (i = -2; i <= -1 - (y - h); i++)
480                    for (j = -2; j <= 2; j++)
481                    {
482                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
483                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 1];
484                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 2];
485                    }
486                for (i = 0 - (y - h); i <= 2; i++)
487                    for (j = -2; j <= 2; j++)
488                    {
489                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+(-i+1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
490                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+(-i+1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 1];
491                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+(-i+1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 2];
492                    }
493                        convSumR += offset;
494                convSumG += offset;
495                convSumB += offset;
496                convSumR = (int)rint((float)convSumR / scale);
497                convSumG = (int)rint((float)convSumG / scale);
498                convSumB = (int)rint((float)convSumB / scale);
499                if (convSumR < 0)
500                    convSumR = 0;
501                if (convSumG < 0)
502                    convSumG = 0;
503                if (convSumB < 0)
504                    convSumB = 0;
505                if (convSumR > UCHAR_MAX)
506                    convSumR = UCHAR_MAX;
507                if (convSumG > UCHAR_MAX)
508                    convSumG = UCHAR_MAX;
509                if (convSumB > UCHAR_MAX)
510                    convSumB = UCHAR_MAX;
511                destData[destBytesPerRow * y + destBytesPerPixel * x]     = (unsigned char)convSumR;
512                destData[destBytesPerRow * y + destBytesPerPixel * x + 1] = (unsigned char)convSumG;
513                destData[destBytesPerRow * y + destBytesPerPixel * x + 2] = (unsigned char)convSumB;
514            }
515            /* bottom right corner */
516            for (x = (w - 3); x < w; x++)
517            {
518                convSumR = 0;
519                convSumG = 0;
520                convSumB = 0;
521                for (i = -2; i <= -1 - (y - h); i++)
522                {
523                    for (j = -2; j <= -1 - (x - w); j++)
524                    {
525                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
526                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 1];
527                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 2];
528                    }
529                    for (j = 0 - (x - w); j <= 2; j++)
530                    {
531                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j+1))*srcBytesPerPixel];
532                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j+1))*srcBytesPerPixel + 1];
533                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j+1))*srcBytesPerPixel + 2];
534                    }
535                }
536                for (i = 0 - (y - h); i <= 2; i++)
537                {
538                    for (j = -2; j <= -1 - (x - w); j++)
539                    {
540                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+(-i+1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
541                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+(-i+1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 1];
542                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+(-i+1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 2];
543                    }
544                    for (j = 0 - (x - w); j <= 2; j++)
545                    {
546                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+(-i+1)) * srcBytesPerRow + (x+(-j+1))*srcBytesPerPixel];
547                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+(-i+1)) * srcBytesPerRow + (x+(-j+1))*srcBytesPerPixel + 1];
548                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+(-i+1)) * srcBytesPerRow + (x+(-j+1))*srcBytesPerPixel + 2];
549                    }
550                }
551                convSumR += offset;
552                convSumG += offset;
553                convSumB += offset;
554                convSumR = (int)rint((float)convSumR / scale);
555                convSumG = (int)rint((float)convSumG / scale);
556                convSumB = (int)rint((float)convSumB / scale);
557                if (convSumR < 0)
558                    convSumR = 0;
559                if (convSumG < 0)
560                    convSumG = 0;
561                if (convSumB < 0)
562                    convSumB = 0;
563                if (convSumR > UCHAR_MAX)
564                    convSumR = UCHAR_MAX;
565                if (convSumG > UCHAR_MAX)
566                    convSumG = UCHAR_MAX;
567                if (convSumB > UCHAR_MAX)
568                    convSumB = UCHAR_MAX;
569                destData[destBytesPerRow * y + destBytesPerPixel * x]     = (unsigned char)convSumR;
570                destData[destBytesPerRow * y + destBytesPerPixel * x + 1] = (unsigned char)convSumG;
571                destData[destBytesPerRow * y + destBytesPerPixel * x + 2] = (unsigned char)convSumB;
572            }
573        }
574
575
576        /* the core */
577        for (y = 0 + 2; y < h - 3; y++)
578            for (x = (0 + 2); x < (w - 3); x++)
579            {
580                convSumR = 0;
581                convSumG = 0;
582                convSumB = 0;
583                for (i = -2; i <= 2; i++)
584                    for (j = -2; j <= 2; j++)
585                    {
586                        convSumR += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
587                        convSumG += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 1];
588                        convSumB += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel + 2];
589                    }
590                convSumR += offset;
591                convSumG += offset;
592                convSumB += offset;
593                convSumR = (int)rint((float)convSumR / scale);
594                convSumG = (int)rint((float)convSumG / scale);
595                convSumB = (int)rint((float)convSumB / scale);
596                if (convSumR < 0)
597                    convSumR = 0;
598                if (convSumG < 0)
599                    convSumG = 0;
600                if (convSumB < 0)
601                    convSumB = 0;
602                if (convSumR > UCHAR_MAX)
603                    convSumR = UCHAR_MAX;
604                if (convSumG > UCHAR_MAX)
605                    convSumG = UCHAR_MAX;
606                if (convSumB > UCHAR_MAX)
607                    convSumB = UCHAR_MAX;
608                destData[destBytesPerRow * y + destBytesPerPixel * x]     = (unsigned char)convSumR;
609                destData[destBytesPerRow * y + destBytesPerPixel * x + 1] = (unsigned char)convSumG;
610                destData[destBytesPerRow * y + destBytesPerPixel * x + 2] = (unsigned char)convSumB;
611            }
612    } else
613    {
614        int convSum;
615
616        if (autoScale)
617        {
618            if (progPanel != nil)
619            {
620                [self setActivity:@"Evaluating range"];
621                [self advanceProgress];
622            }
623            minVal = INT_MAX;
624            maxVal = INT_MIN;
625
626            /* calibrate output range */
627            for (y = 0 + 2; y < h - 3; y++)
628                for (x = 0 + 2; x < w - 3; x++)
629                {
630                    convSum = 0;
631                    for (i = -2; i <= 2; i++)
632                        for (j = -2; j <= 2; j++)
633                            convSum += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
634
635                    if (convSum > maxVal)
636                        maxVal = convSum;
637                    if (convSum < minVal)
638                        minVal = convSum;
639                }
640            printf("Max %d, min %d\n", maxVal, minVal);
641            normalizeFactor = (float)fabs(maxVal -minVal)/(float)UCHAR_MAX;
642            printf("normalize factor: %f\n", normalizeFactor);
643            offset = -minVal;
644            scale = normalizeFactor;
645        }
646
647        printf("offset: %d, scale:%f\n", offset, scale);
648
649        if (progPanel != nil)
650        {
651            [self setActivity:@"convolving"];
652            [self advanceProgress];
653        }
654
655        /* execute the actual filtering */
656        /* the borders */
657        for (y = 0; y < 0 + 2; y++)
658        {
659            /* top left corner */
660            for (x = 0; x < 0 + 2; x++)
661            {
662                convSum = 0;
663                for (i = -2; i <= -1 - y; i++)
664                {
665                    for (j = -2; j <= -1 - x; j++)
666                        convSum += convMat[i+2][j+2] * (int)srcData[(y+(-i-1)) * srcBytesPerRow + (x+(-j-1))*srcBytesPerPixel];
667                    for (j = 0 - x; j <= 2; j++)
668                        convSum += convMat[i+2][j+2] * (int)srcData[(y+(-i-1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
669                }
670                for (i = 0 - y; i <= 2; i++)
671                {
672                    for (j = -2; j <= -1 - x; j++)
673                        convSum += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j-1))*srcBytesPerPixel];
674                    for (j = 0 - x; j <= 2; j++)
675                        convSum += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
676                }
677                convSum += offset;
678                convSum = (int)rint((float)convSum / scale);
679                if (convSum < 0)
680                    convSum = 0;
681                if (convSum > UCHAR_MAX)
682                    convSum = UCHAR_MAX;
683                destData[destBytesPerRow * y + destBytesPerPixel * x] = (unsigned char)convSum;
684            }
685            /* top band */
686            for (x = 0 + 2; x < w - 3; x++)
687            {
688                convSum = 0;
689                for (i = -2; i <= -1 - y; i++)
690                    for (j = -2; j <= 2; j++)
691                        convSum += convMat[i+2][j+2] * (int)srcData[(y+(-i-1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
692                for (i = 0 - y; i <= 2; i++)
693                    for (j = -2; j <= 2; j++)
694                        convSum += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
695                convSum += offset;
696                convSum = (int)rint((float)convSum / scale);
697                if (convSum < 0)
698                    convSum = 0;
699                if (convSum > UCHAR_MAX)
700                    convSum = UCHAR_MAX;
701                destData[destBytesPerRow * y + destBytesPerPixel * x] = (unsigned char)convSum;
702            }
703            /* top right corner */
704            for (x = w - 3; x < w; x++)
705            {
706                convSum = 0;
707                for (i = -2; i <= -1 - y; i++)
708                {
709                    for (j = -2; j <= -1 - (x - w); j++)
710                        convSum += convMat[i+2][j+2] * (int)srcData[(y+(-i-1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
711                    for (j = 0 - (x - w); j <= 2; j++)
712                        convSum += convMat[i+2][j+2] * (int)srcData[(y+(-i-1)) * srcBytesPerRow + (x+(-j+1))*srcBytesPerPixel];
713                }
714                for (i = 0 - y; i <= 2; i++)
715                {
716                    for (j = -2; j <= -1 - (x - w); j++)
717                        convSum += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
718                    for (j = 0 - (x - w); j <= 2; j++)
719                        convSum += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j+1))*srcBytesPerPixel];
720                }
721                convSum += offset;
722                convSum = (int)rint((float)convSum / scale);
723                if (convSum < 0)
724                    convSum = 0;
725                if (convSum > UCHAR_MAX)
726                    convSum = UCHAR_MAX;
727                destData[destBytesPerRow * y + destBytesPerPixel * x] = (unsigned char)convSum;
728            }
729        }
730        for (y = 0 + 2; y < h - 3; y++)
731        {
732            /* left band */
733            for (x = 0; x < 0 + 2; x++)
734            {
735                convSum = 0;
736                for (i = -2; i <= 2; i++)
737                {
738                    for (j = -2; j <= -1 - x; j++)
739                        convSum += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j-1))*srcBytesPerPixel];
740                    for (j = 0 - x; j <= 2; j++)
741                        convSum += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
742                }
743                convSum += offset;
744                convSum = (int)rint((float)convSum / scale);
745                if (convSum < 0)
746                    convSum = 0;
747                if (convSum > UCHAR_MAX)
748                    convSum = UCHAR_MAX;
749                destData[destBytesPerRow * y + destBytesPerPixel * x] = (unsigned char)convSum;
750            }
751            /* right band */
752            for (x = w - 3; x < w; x++)
753            {
754                convSum = 0;
755                for (i = -2; i <= 2; i++)
756                {
757                    for (j = -2; j <= -1 - (x - w); j++)
758                        convSum += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
759                    for (j = 0 - (x - w); j <= 2; j++)
760                        convSum += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j+1))*srcBytesPerPixel];
761                }
762                convSum += offset;
763                convSum = (int)rint((float)convSum / scale);
764                if (convSum < 0)
765                    convSum = 0;
766                if (convSum > UCHAR_MAX)
767                    convSum = UCHAR_MAX;
768                destData[destBytesPerRow * y + destBytesPerPixel * x] = (unsigned char)convSum;
769            }
770        }
771        for (y = h - 3; y < h; y++)
772        {
773            /* bottom left corner */
774            for (x = 0; x < 0 + 2; x++)
775            {
776                convSum = 0;
777                for (i = -2; i <= -1 - (y - h); i++)
778                {
779                    for (j = -2; j <= -1 - x; j++)
780                        convSum += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j-1))*srcBytesPerPixel];
781                    for (j = 0 - x; j <= 2; j++)
782                        convSum += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
783                }
784                for (i = 0 - (y - h); i <= 2; i++)
785                {
786                    for (j = -2; j <= -1 - x; j++)
787                        convSum += convMat[i+2][j+2] * (int)srcData[(y+(-i+1)) * srcBytesPerRow + (x+(-j-1))*srcBytesPerPixel];
788                    for (j = 0 - x; j <= 2; j++)
789                        convSum += convMat[i+2][j+2] * (int)srcData[(y+(-i+1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
790                }
791                convSum += offset;
792                convSum = (int)rint((float)convSum / scale);
793                if (convSum < 0)
794                    convSum = 0;
795                if (convSum > UCHAR_MAX)
796                    convSum = UCHAR_MAX;
797                destData[destBytesPerRow * y + destBytesPerPixel * x] = (unsigned char)convSum;
798            }
799            /* bottom band */
800            for (x = 0 + 2; x < w - 3; x++)
801            {
802                convSum = 0;
803                for (i = -2; i <= -1 - (y - h); i++)
804                    for (j = -2; j <= 2; j++)
805                        convSum += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
806                for (i = 0 - (y - h); i <= 2; i++)
807                    for (j = -2; j <= 2; j++)
808                        convSum += convMat[i+2][j+2] * (int)srcData[(y+(-i+1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
809                convSum += offset;
810                convSum = (int)rint((float)convSum / scale);
811                if (convSum < 0)
812                    convSum = 0;
813                if (convSum > UCHAR_MAX)
814                    convSum = UCHAR_MAX;
815                destData[destBytesPerRow * y + destBytesPerPixel * x] = (unsigned char)convSum;
816            }
817            /* bottom right corner */
818            for (x = w - 3; x < w; x++)
819            {
820                convSum = 0;
821                for (i = -2; i <= -1 - (y - h); i++)
822                {
823                    for (j = -2; j <= -1 - (x - w); j++)
824                        convSum += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
825                    for (j = 0 - (x - w); j <= 2; j++)
826                        convSum += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+(-j+1))*srcBytesPerPixel];
827                }
828                for (i = 0 - (y - h); i <= 2; i++)
829                {
830                    for (j = -2; j <= -1 - (x - w); j++)
831                        convSum += convMat[i+2][j+2] * (int)srcData[(y+(-i+1)) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
832                    for (j = 0 - (x - w); j <= 2; j++)
833                        convSum += convMat[i+2][j+2] * (int)srcData[(y+(-i+1)) * srcBytesPerRow + (x+(-j+1))*srcBytesPerPixel];
834                }
835                convSum += offset;
836                convSum = (int)rint((float)convSum / scale);
837                if (convSum < 0)
838                    convSum = 0;
839                if (convSum > UCHAR_MAX)
840                    convSum = UCHAR_MAX;
841                destData[destBytesPerRow * y + destBytesPerPixel * x] = (unsigned char)convSum;
842            }
843        }
844        /* the core */
845        for (y = 0 + 2; y < h - 3; y++)
846            for (x = 0 + 2; x < w - 3; x++)
847            {
848                convSum = 0;
849                for (i = -2; i <= 2; i++)
850                    for (j = -2; j <= 2; j++)
851                        convSum += convMat[i+2][j+2] * (int)srcData[(y+i) * srcBytesPerRow + (x+j)*srcBytesPerPixel];
852                convSum += offset;
853                convSum = (int)rint((float)convSum / scale);
854                if (convSum < 0)
855                    convSum = 0;
856                if (convSum > UCHAR_MAX)
857                    convSum = UCHAR_MAX;
858                destData[destBytesPerRow * y + destBytesPerPixel * x] = (unsigned char)convSum;
859            }
860    }
861
862    /* preserve Alpha Channel if present */
863    if (hasAlpha)
864      {
865        for (y = 0; y < h; y++)
866          for (x = 0; x < w; x++)
867            destData[destBytesPerRow * y + destBytesPerPixel * x + (destSamplesPerPixel-1)] = srcData[srcBytesPerRow * y + srcBytesPerPixel * x + (srcSamplesPerPixel-1)];
868      }
869
870    if (progPanel != nil)
871    {
872        [self setActivity:@"Done"];
873        [self showProgress];
874    }
875    [destImage setBitmapRep:destImageRep];
876    [destImageRep release];
877    [destImage autorelease];
878    return destImage;
879}
880
881
882@end
883