]> bicyclesonthemoon.info Git - ott/enhance/blob - nofading.c
nofading online
[ott/enhance] / nofading.c
1 /*
2 nofading.c
3 The tool to remove fading from an image
4 04.12.2022
5
6 Copyright (C) 2015, 2022  Balthasar Szczepański
7
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU Affero General Public License as
10 published by the Free Software Foundation, either version 3 of the
11 License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU Affero General Public License for more details.
17
18 You should have received a copy of the GNU Affero General Public License
19 along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
21
22 Requires Dev Image Library (libdevil) (http://openil.sourceforge.net/)
23 on Pentium III libdevil must be recompiled with
24 --disable-ssl2 --disable-ssl3
25 (https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=572954)
26
27 */
28
29 #include <stdint.h>
30 #include <getopt.h>
31 #include <inttypes.h>
32 #include <errno.h>
33 #include <unistd.h>
34
35 #include "core.h"
36 #include "nofading.h"
37
38 #define UPDATE_RANGE(val, low, high) \
39 { \
40         if ((val) < (low)) \
41                 (low) = (val); \
42         if ((val) > (high)) \
43                 (high) = (val); \
44 }
45
46 char NOFADING_MISSING_ARGS[] = "Missing parameters.\nnofading [-a -c -f] inPix outPix [framesize]\n";
47
48 struct nofading_data
49 {
50         uint_fast8_t individual_channels;
51         uint_fast8_t individual_frames;
52         uint_fast8_t enhance_alpha;
53         ILuint red_low;
54         ILuint red_high;
55         ILuint green_low;
56         ILuint green_high;
57         ILuint blue_low;
58         ILuint blue_high;
59         ILuint alpha_low;
60         ILuint alpha_high;
61         ILuint max;
62 };
63
64 ILuint enhance_fading_1ch (ILuint val, ILuint low, ILuint high, ILuint max);
65 int find_fading_range (ILuint n, struct PixelInfo *p, void *data);
66 int enhance_fading (ILuint n, struct PixelInfo *p, void *data);
67
68 int subtool_nofading (int argc, char **argv, int argi, char **err)
69 {
70         uint_fast16_t frame_t = 0;
71         uint_fast16_t frame_b = 0;
72         uint_fast16_t frame_l = 0;
73         uint_fast16_t frame_r = 0;
74         ILint x0 = 0;
75         ILint y0 = 0;
76         ILint width = 0;
77         ILint height = 0;
78         ILint frames;
79         ILint loops;
80         ILint f;
81         
82         struct nofading_data data;
83         struct IL_full_info info;
84         
85         struct option long_options[] = {
86                 {"enhance-alpha",       no_argument, NULL, 'a'},
87                 {"no-alpha",            no_argument, NULL, 'n'},
88                 {"individual-channels", no_argument, NULL, 'c'},
89                 {"individual-frames",   no_argument, NULL, 'f'},
90                 {"help",                no_argument, NULL, 'h'},
91                 {0,                     0,           0,    0}
92         };
93         char short_options[] = "acfh0";
94         
95         int opt;
96         int r;
97         
98         FLAG_TYPE flags = CAN_BE_MULTIPLE | CAN_BE_OVER_8BIT;
99         
100         data.individual_channels = 0;
101         data.individual_frames = 0;
102         data.enhance_alpha = 0;
103         
104         optind = argi;
105         while ((opt = getopt_long(argc, argv, short_options, long_options, NULL)) != -1)
106         {
107                 switch (opt)
108                 {
109                 case 'a':
110                         data.enhance_alpha = 1;
111                         break;
112                 case 'n':
113                         flags |= CANNOT_HAVE_ALPHA;
114                         break;
115                 case 'c':
116                         data.individual_channels = 1;
117                         break;
118                 case 'f':
119                         data.individual_frames = 1;
120                         flags |= IN_WINDOW;
121                         break;
122                 case 'h':
123                         /* help */
124                         break;
125                 }
126         }
127         
128         if (argc < optind + 2)
129         {
130                 *err = NOFADING_MISSING_ARGS;
131                 return EINVAL;
132         }
133         
134         if (argc >= optind + 6)
135         {
136                 sscanf(argv[optind+2], "%"SCNuFAST16, &frame_t);
137                 sscanf(argv[optind+3], "%"SCNuFAST16, &frame_b);
138                 sscanf(argv[optind+4], "%"SCNuFAST16, &frame_l);
139                 sscanf(argv[optind+5], "%"SCNuFAST16, &frame_r);
140         }
141         else if  (argc >= optind + 4)
142         {
143                 sscanf(argv[optind+2], "%"SCNuFAST16, &frame_t);
144                 frame_b = frame_t;
145                 sscanf(argv[optind+3], "%"SCNuFAST16, &frame_l);
146                 frame_r = frame_l;
147         }
148         else if  (argc >= optind + 3)
149         {
150                 sscanf(argv[optind+2], "%"SCNuFAST16, &frame_t);
151                 frame_b = frame_t;
152                 frame_l = frame_t;
153                 frame_r = frame_t;
154         }
155         else
156         {
157                 frame_t = 0;
158                 frame_b = 0;
159                 frame_l = 0;
160                 frame_r = 0;
161         }
162         
163         if ((frame_t==0) && (frame_b==0) && (frame_l==0) && (frame_r==0))
164                 flags |= OK_PALETTE_ONLY;
165         else
166                 flags |= CANNOT_BE_INDEXED | IN_WINDOW;
167         
168         r = reserve_pictures(1);
169         if (r)
170         {
171                 *err = CREATE_FAILED;
172                 return r;
173         }
174         
175         r = load_picture(0, argv[optind], &info, &flags);
176         if (r)
177         {
178                 *err = LOAD_FAILED;
179                 return r;
180         }
181         
182         if (data.individual_frames)
183         {
184                 loops = info.num_images+1;
185                 frames = 1;
186         }
187         else
188         {
189                 loops = 1;
190                 frames = info.num_images+1;
191         }
192         
193         for (f=0; f<loops; ++f)
194         {
195                 data.red_low   = 0xFFFFFFFF;
196                 data.green_low = 0xFFFFFFFF;
197                 data.blue_low  = 0xFFFFFFFF;
198                 data.alpha_low = 0xFFFFFFFF;
199                 data.red_high  = 0x00000000;
200                 data.green_high= 0x00000000;
201                 data.blue_high = 0x00000000;
202                 data.alpha_high= 0x00000000;
203                 
204                 get_info(0, &info, f);
205                 data.max = upscale_value(0xFF,info.image_bpc);
206                 if (f==0)
207                 {
208                         if (flags & IN_WINDOW) 
209                         {
210                                 x0 = frame_l;
211                                 y0 = frame_t;
212                                 width = info.image_width - frame_l - frame_r;
213                                 height = info.image_height - frame_t - frame_b;
214                         }
215                 }
216                 
217                 r = perform_action_1picture (
218                         0,
219                         x0, y0, f, width, height, frames,
220                         &find_fading_range,
221                         flags | NOT_WRITABLE,
222                         &data
223                 );
224                 if (r)
225                 {
226                         *err = CONVERT_FAILED;
227                         return r;
228                 }
229                 r = perform_action_1picture (
230                         0,
231                         x0, y0, f, width, height, frames,
232                         &enhance_fading,
233                         flags,
234                         &data
235                 );
236         }
237         
238         r = save_picture (0, argv[optind+1], flags);
239         if (r)
240         {
241                 *err = SAVE_FAILED;
242                 return r;
243         }
244         
245         return 0;
246 }
247
248 int find_fading_range (ILuint n, struct PixelInfo *p, void *data)
249 {
250         struct nofading_data *d;
251         
252         d = data;
253         
254         if (p->flags & EFF_GRAY)
255         {
256                 UPDATE_RANGE(p->value, d->green_low, d->green_high);
257         }
258         else if (d->individual_channels)
259         {
260                 UPDATE_RANGE(p->red,   d->red_low,   d->red_high);
261                 UPDATE_RANGE(p->green, d->green_low, d->green_high);
262                 UPDATE_RANGE(p->blue,  d->blue_low,  d->blue_high);
263         }
264         else
265         {
266                 UPDATE_RANGE(p->red,   d->green_low, d->green_high);
267                 UPDATE_RANGE(p->green, d->green_low, d->green_high);
268                 UPDATE_RANGE(p->blue,  d->green_low, d->green_high);
269         }
270         if ((p->flags & EFF_ALPHA) && (d->enhance_alpha))
271         {
272                 UPDATE_RANGE(p->alpha, d->alpha_low, d->alpha_high);
273         }
274         
275         return 0;
276 }
277
278 ILuint enhance_fading_1ch (ILuint val, ILuint low, ILuint high, ILuint max)
279 {
280         ILint64 y;
281         
282         if (low == high)
283                 return val;
284         
285         y = (((ILint64)val) - low) * max / (high - low);
286         return (ILuint)((y>max)?max:((y<0)?0:y));
287 }
288
289 int enhance_fading (ILuint n, struct PixelInfo *p, void *data)
290 {
291         struct nofading_data *d;
292         
293         d = data;
294         
295         if (p->flags & EFF_GRAY)
296                 p->value = enhance_fading_1ch(p->value, d->green_low, d->green_high, d->max);
297         else if (d->individual_channels)
298         {
299                 p->red   = enhance_fading_1ch(p->red  , d->red_low,   d->red_high,   d->max);
300                 p->green = enhance_fading_1ch(p->green, d->green_low, d->green_high, d->max);
301                 p->blue  = enhance_fading_1ch(p->blue , d->blue_low,  d->blue_high,  d->max);
302         }
303         else
304         {
305                 p->red   = enhance_fading_1ch(p->red  , d->green_low, d->green_high, d->max);
306                 p->green = enhance_fading_1ch(p->green, d->green_low, d->green_high, d->max);
307                 p->blue  = enhance_fading_1ch(p->blue , d->green_low, d->green_high, d->max);
308         }
309         if ((p->flags & EFF_ALPHA) && (d->enhance_alpha))
310                 p->alpha = enhance_fading_1ch(p->alpha, d->alpha_low, d->alpha_high, d->max);
311
312         return 0;
313 }