1//
2//  PRCurves.m
3//  PRICE
4//
5//  Created by Riccardo Mottola on 07/08/11.
6//  Copyright 2011-2014 Riccardo Mottola. 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#import "PRCurves.h"
12
13
14@implementation PRCurves
15
16/*
17 * Paramters order:
18 *   Luminance Array
19 *   Red Array
20 *   Green Array
21 *   Blue Array
22 */
23- (PRImage *)filterImage:(PRImage *)image with:(NSArray *)parameters progressPanel:(PRCProgress *)progressPanel
24{
25  PRImage *retImage;
26  NSArray *array;
27  unsigned arrayL[UCHAR_MAX + 1];
28  unsigned arrayR[UCHAR_MAX + 1];
29  unsigned arrayG[UCHAR_MAX + 1];
30  unsigned arrayB[UCHAR_MAX + 1];
31  unsigned i;
32
33  if ([parameters count] != 1 && [parameters count] != 3)
34    {
35      NSLog(@"inconsistent number of parametetrs: %u", (unsigned int)[parameters count]);
36      return nil;
37    }
38
39
40  if ([parameters count] == 1)
41    {
42      array = [parameters objectAtIndex:0];
43      if ([array count] > 0)
44	{
45	  if ([array count] == UCHAR_MAX+1)
46	    {
47	      for (i = 0; i <= UCHAR_MAX; i++)
48		arrayL[i] = [(NSNumber *)[array objectAtIndex: i] unsignedIntValue];
49	    }
50	  else
51	    {
52	      NSLog(@"Incompatible size of parameter array: %u", (unsigned int)[array count]);
53	    }
54	}
55      retImage = [self adjustImage: image :arrayL :NULL :NULL :NULL];
56    }
57  else
58    {
59      array = [parameters objectAtIndex:0];
60      if ([array count] > 0)
61	{
62	  if ([array count] == UCHAR_MAX+1)
63	    {
64	      for (i = 0; i <= UCHAR_MAX; i++)
65		arrayR[i] = [(NSNumber *)[array objectAtIndex: i] unsignedIntValue];
66	    }
67	  else
68	    {
69	      NSLog(@"Incompatible size of parameter array: %u", (unsigned int)[array count]);
70	    }
71	}
72      array = [parameters objectAtIndex:1];
73      if ([array count] > 0)
74	{
75	  if ([array count] == UCHAR_MAX+1)
76	    {
77	      for (i = 0; i <= UCHAR_MAX; i++)
78		arrayG[i] = [(NSNumber *)[array objectAtIndex: i] unsignedIntValue];
79	    }
80	  else
81	    {
82	      NSLog(@"Incompatible size of parameter array: %u", (unsigned int)[array count]);
83	    }
84	}
85      array = [parameters objectAtIndex:2];
86      if ([array count] > 0)
87	{
88	  if ([array count] == UCHAR_MAX+1)
89	    {
90	      for (i = 0; i <= UCHAR_MAX; i++)
91		arrayB[i] = [(NSNumber *)[array objectAtIndex: i] unsignedIntValue];
92	    }
93	  else
94	    {
95	      NSLog(@"Incompatible size of parameter array: %u", (unsigned int)[array count]);
96	    }
97	}
98      retImage = [self adjustImage: image :arrayL :arrayR :arrayG :arrayB];
99    }
100  return retImage;
101}
102
103- (NSString *)actionName
104{
105  return @"Curves";
106}
107
108- (PRImage *)adjustImage :(PRImage *)srcImage :(unsigned *)arrayL :(unsigned *)arrayR :(unsigned *)arrayG :(unsigned *)arrayB
109{
110  NSBitmapImageRep *srcImageRep;
111  PRImage *destImage;
112  NSBitmapImageRep *destImageRep;
113  NSInteger w, h;
114  NSInteger x, y;
115  unsigned char *srcData;
116  unsigned char *destData;
117  int tempValue;
118  NSInteger srcSamplesPerPixel;
119  NSInteger destSamplesPerPixel;
120  NSInteger srcBytesPerRow;
121  NSInteger destBytesPerRow;
122  NSInteger srcBytesPerPixel;
123  NSInteger destBytesPerPixel;
124  BOOL hasAlpha;
125
126
127  /* get source image representation and associated information */
128  srcImageRep = [srcImage bitmapRep];
129
130  w = [srcImageRep pixelsWide];
131  h = [srcImageRep pixelsHigh];
132  srcBytesPerRow = [srcImageRep bytesPerRow];
133  srcSamplesPerPixel = [srcImageRep samplesPerPixel];
134  srcBytesPerPixel = [srcImageRep bitsPerPixel] / 8;
135
136  /* check bith depth and color/greyscale image */
137  hasAlpha = [srcImageRep hasAlpha];
138
139  destSamplesPerPixel = srcSamplesPerPixel;
140  /* allocate destination image and its representation */
141  destImage = [[PRImage alloc] initWithSize:NSMakeSize(w, h)];
142  destImageRep = [[NSBitmapImageRep alloc]
143                initWithBitmapDataPlanes:NULL
144                              pixelsWide:w
145                              pixelsHigh:h
146                           bitsPerSample:[srcImageRep bitsPerSample]
147                         samplesPerPixel:destSamplesPerPixel
148                                hasAlpha:hasAlpha
149                                isPlanar:NO
150                          colorSpaceName:[srcImageRep colorSpaceName]
151                             bytesPerRow:0
152                            bitsPerPixel:0];
153  srcData = [srcImageRep bitmapData];
154  destData = [destImageRep bitmapData];
155  destBytesPerRow = [destImageRep bytesPerRow];
156  destBytesPerPixel = [destImageRep bitsPerPixel] / 8;
157
158  if ([srcImage hasColor])
159    {
160      for (y = 0; y < h; y++)
161	for (x = 0; x < w; x++)
162	  {
163	    tempValue = arrayR[srcData[srcBytesPerRow*y + srcBytesPerPixel*x]];
164	    destData[destBytesPerRow*y + destBytesPerPixel*x] = tempValue;
165
166	    tempValue = arrayG[srcData[srcBytesPerRow*y + srcBytesPerPixel*x + 1]];
167	    destData[destBytesPerRow*y + destBytesPerPixel*x + 1] = tempValue;
168
169	    tempValue = arrayB[srcData[srcBytesPerRow*y + srcBytesPerPixel*x + 2]];
170	    destData[destBytesPerRow*y + destBytesPerPixel*x + 2] = tempValue;
171
172            if (hasAlpha)
173              destData[destBytesPerRow*y + destBytesPerPixel*x + 3] = srcData[srcBytesPerRow*y + srcBytesPerPixel*x + 3];
174	  }
175    }
176  else
177    {
178      for (y = 0; y < h; y++)
179	for (x = 0; x < w; x++)
180	  {
181	    destData[destBytesPerRow*y + destBytesPerPixel*x] = arrayL[srcData[srcBytesPerRow*y + srcBytesPerPixel*x]];
182
183            if (hasAlpha)
184              destData[destBytesPerRow*y + destBytesPerPixel*x + 1] = srcData[srcBytesPerRow*y + srcBytesPerPixel*x + 1];
185	  }
186    }
187
188  [destImage setBitmapRep:destImageRep];
189  [destImageRep release];
190  [destImage autorelease];
191  return destImage;
192}
193
194- (BOOL)displayProgress
195{
196  return NO;
197}
198
199@end
200