1//
2//  PRScale.m
3//  PRICE
4//
5//  Created by Riccardo Mottola on Wed Jan 19 2005.
6//  Copyright (c) 2005-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#include <math.h>
12#import "PRScale.h"
13
14
15@implementation PRScale
16
17- (PRImage *)filterImage:(PRImage *)image with:(NSArray *)parameters progressPanel:(PRCProgress *)progressPanel
18{
19    int pixelsX;
20    int pixelsY;
21    int method;
22
23    /* interpret the parameters */
24    pixelsX = [[parameters objectAtIndex:0] intValue];
25    pixelsY = [[parameters objectAtIndex:1] intValue];
26    method = [[parameters objectAtIndex:2] intValue];
27
28    return [self scaleImage:image :pixelsX :pixelsY :method :progressPanel];
29}
30
31- (NSString *)actionName
32{
33    return @"Scale";
34}
35
36- (PRImage *)scaleImage :(PRImage *)srcImage :(int)sizeX :(int)sizeY :(int)method :(PRCProgress *)prPanel
37{
38  NSBitmapImageRep *srcImageRep;
39  PRImage *destImage;
40  NSBitmapImageRep *destImageRep;
41  NSInteger origW, origH;
42  NSInteger x, y;
43  NSInteger i;
44  unsigned char *srcData;
45  unsigned char *destData;
46  NSInteger srcSamplesPerPixel;
47  NSInteger destSamplesPerPixel;
48  register NSInteger srcBytesPerPixel;
49  register NSInteger destBytesPerPixel;
50  register NSInteger srcBytesPerRow;
51  register NSInteger destBytesPerRow;
52  float xRatio, yRatio;
53
54    progressSteps = 0;
55    totalProgressSteps = 2;
56    progPanel = prPanel;
57
58    /* get source image representation and associated information */
59    if (progPanel != nil)
60    {
61        [self setActivity:@"Get image size"];
62        [self advanceProgress];
63    }
64    srcImageRep = [srcImage bitmapRep];
65    srcBytesPerRow = [srcImageRep bytesPerRow];
66    srcSamplesPerPixel = [srcImageRep samplesPerPixel];
67    srcBytesPerPixel = [srcImageRep bitsPerPixel] / 8;
68
69    origW = [srcImageRep pixelsWide];
70    origH = [srcImageRep pixelsHigh];
71
72
73    xRatio = (float)origW / (float)sizeX;
74    yRatio = (float)origH / (float)sizeY;
75
76
77    destImage = [[PRImage alloc] initWithSize:NSMakeSize(sizeX, sizeY)];
78    destSamplesPerPixel = [srcImageRep samplesPerPixel];
79    destImageRep = [[NSBitmapImageRep alloc]
80                     initWithBitmapDataPlanes:NULL
81                     pixelsWide:sizeX
82                     pixelsHigh:sizeY
83                     bitsPerSample:8
84                     samplesPerPixel:destSamplesPerPixel
85                     hasAlpha:[srcImageRep hasAlpha]
86                     isPlanar:NO
87                     colorSpaceName:[srcImageRep colorSpaceName]
88                     bytesPerRow:destSamplesPerPixel*sizeX
89                     bitsPerPixel:0];
90
91    srcData = [srcImageRep bitmapData];
92    destData = [destImageRep bitmapData];
93    destBytesPerRow = [destImageRep bytesPerRow];
94    destBytesPerPixel = [destImageRep bitsPerPixel] / 8;
95
96    if (progPanel != nil)
97    {
98        [self setActivity:@"Scale"];
99        [self advanceProgress];
100    }
101
102    if (method == NEAREST_NEIGHBOUR)
103    {
104        for (y = 0; y < sizeY; y++)
105            for (x = 0; x < sizeX; x++)
106                for (i = 0; i < srcSamplesPerPixel; i++)
107                    destData[destBytesPerRow * y + destBytesPerPixel * (sizeX + x) + i] = srcData[srcBytesPerRow * (int)(y * yRatio)  + srcBytesPerPixel * (int)(x * xRatio) + i];
108    }
109    else if (method == BILINEAR)
110      {
111	/*
112	  w,h : original width and height
113	  v1, v2, v3, 4: four original corner values
114	  v' : new computed value
115
116	  v' = v1(1-w)(1-h) + v2(w)(1-h) + v3(h)(1-w) + v3(w)(h)
117	*/
118        int v1, v2, v3, v4;
119        register int x0, y0;
120
121        for (y = 0; y < sizeY-1; y++)
122	  for (x = 0; x < sizeX-1; x++)
123	    {
124	      register float xDiff, yDiff;
125	      float xFloat, yFloat;
126
127	      xFloat = (float)x * xRatio;
128	      yFloat = (float)y * yRatio;
129	      x0 = (int)(xFloat);
130	      y0 = (int)(yFloat);
131	      xDiff = (xFloat - x0);
132	      yDiff = (yFloat - y0);
133	      for (i = 0; i < srcSamplesPerPixel; i++)
134		{
135		  v1 = srcData[srcBytesPerRow * y0 + srcBytesPerPixel * x0 + i];
136		  v2 = srcData[srcBytesPerRow * y0 + srcBytesPerPixel * (x0+1) + i];
137		  v3 = srcData[srcBytesPerRow * (y0+1) + srcBytesPerPixel * x0 + i];
138		  v4 = srcData[srcBytesPerRow * (y0+1) + srcBytesPerPixel * (x0+1) + i];
139
140		  destData[destBytesPerPixel * (y * sizeX + x) + i] = \
141		    (int)(v1*(1-xDiff)*(1-yDiff) + \
142			  v2*xDiff*(1-yDiff) + \
143			  v3*yDiff*(1-xDiff) + \
144			  v4*xDiff*yDiff);
145		}
146	    }
147	/* we left out one pixel at the right and bottom border */
148	y = sizeY-1;
149	for (x = 0; x < sizeX-1; x++)
150	  {
151	    register float xDiff, yDiff;
152	    float xFloat, yFloat;
153
154	    xFloat = (float)x * xRatio;
155	    yFloat = (float)y * yRatio;
156	    x0 = (int)(xFloat);
157	    y0 = (int)(yFloat);
158	    xDiff = (xFloat - x0);
159	    yDiff = (yFloat - y0);
160
161	    for (i = 0; i < srcSamplesPerPixel; i++)
162	      {
163		v1 = srcData[srcBytesPerRow * y0 + srcBytesPerPixel * x0 + i];
164		v2 = srcData[srcBytesPerRow * y0 + srcBytesPerPixel * (x0+1) + i];
165
166		destData[destSamplesPerPixel * (y * sizeX + x) + i] = \
167		  (int)(v1*(1-xDiff)*(1-yDiff) + \
168			v2*xDiff*(1-yDiff));
169	      }
170	  }
171
172	x = sizeX-1;
173	for (y = 0; y < sizeY-1; y++)
174	  {
175	    register float xDiff, yDiff;
176	    float xFloat, yFloat;
177
178	    xFloat = (float)x * xRatio;
179	    yFloat = (float)y * yRatio;
180	    x0 = (int)(xFloat);
181	    y0 = (int)(yFloat);
182	    xDiff = (xFloat - x0);
183	    yDiff = (yFloat - y0);
184	    for (i = 0; i < srcSamplesPerPixel; i++)
185	      {
186		v1 = srcData[srcBytesPerRow * y0 + srcBytesPerPixel * x0 + i];
187		v3 = srcData[srcBytesPerRow * (y0+1) + srcBytesPerPixel * x0 + i];
188
189		destData[destBytesPerPixel * (y * sizeX + x) + i] = \
190		  (int)(v1*(1-xDiff)*(1-yDiff) + \
191			v3*yDiff*(1-xDiff));
192	      }
193	  }
194	/* the bottom right corner */
195	{
196	  register float xDiff, yDiff;
197	  float xFloat, yFloat;
198
199	  xFloat = (float)x * xRatio;
200	  yFloat = (float)y * yRatio;
201	  x0 = (int)(xFloat);
202	  y0 = (int)(yFloat);
203	  xDiff = (xFloat - x0);
204	  yDiff = (yFloat - y0);
205	  for (i = 0; i < srcBytesPerPixel; i++)
206	    {
207	      v1 = srcData[srcBytesPerRow * y0 + srcBytesPerPixel * x0 + i];
208
209	      destData[destBytesPerPixel * (y * sizeX + x) + i] = \
210		(int)(v1*(1-xDiff)*(1-yDiff));
211	    }
212	}
213      } else
214      NSLog(@"Unknown scaling method");
215    if (progPanel != nil)
216    {
217        [self setActivity:@"Done"];
218        [self showProgress];
219    }
220
221    [destImage setBitmapRep:destImageRep];
222    [destImageRep release];
223    [destImage autorelease];
224    return destImage;
225}
226
227@end
228