3 The tool to remove fading from an image
6 Copyright (C) 2015, 2022 Balthasar Szczepański
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.
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.
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/>.
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)
38 #define UPDATE_RANGE(val, low, high) \
46 char NOFADING_MISSING_ARGS[] = "Missing parameters.\nnofading [-a -c -f] inPix outPix [framesize]\n";
50 uint_fast8_t individual_channels;
51 uint_fast8_t individual_frames;
52 uint_fast8_t enhance_alpha;
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);
68 int subtool_nofading (int argc, char **argv, int argi, char **err)
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;
82 struct nofading_data data;
83 struct IL_full_info info;
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'},
93 char short_options[] = "acfh0";
98 FLAG_TYPE flags = CAN_BE_MULTIPLE | CAN_BE_OVER_8BIT;
100 data.individual_channels = 0;
101 data.individual_frames = 0;
102 data.enhance_alpha = 0;
105 while ((opt = getopt_long(argc, argv, short_options, long_options, NULL)) != -1)
110 data.enhance_alpha = 1;
113 flags |= CANNOT_HAVE_ALPHA;
116 data.individual_channels = 1;
119 data.individual_frames = 1;
128 if (argc < optind + 2)
130 *err = NOFADING_MISSING_ARGS;
134 if (argc >= optind + 6)
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);
141 else if (argc >= optind + 4)
143 sscanf(argv[optind+2], "%"SCNuFAST16, &frame_t);
145 sscanf(argv[optind+3], "%"SCNuFAST16, &frame_l);
148 else if (argc >= optind + 3)
150 sscanf(argv[optind+2], "%"SCNuFAST16, &frame_t);
163 if ((frame_t==0) && (frame_b==0) && (frame_l==0) && (frame_r==0))
164 flags |= OK_PALETTE_ONLY;
166 flags |= CANNOT_BE_INDEXED | IN_WINDOW;
168 r = reserve_pictures(1);
171 *err = CREATE_FAILED;
175 r = load_picture(0, argv[optind], &info, &flags);
182 if (data.individual_frames)
184 loops = info.num_images+1;
190 frames = info.num_images+1;
193 for (f=0; f<loops; ++f)
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;
204 get_info(0, &info, f);
205 data.max = upscale_value(0xFF,info.image_bpc);
208 if (flags & IN_WINDOW)
212 width = info.image_width - frame_l - frame_r;
213 height = info.image_height - frame_t - frame_b;
217 r = perform_action_1picture (
219 x0, y0, f, width, height, frames,
221 flags | NOT_WRITABLE,
226 *err = CONVERT_FAILED;
229 r = perform_action_1picture (
231 x0, y0, f, width, height, frames,
238 r = save_picture (0, argv[optind+1], flags);
248 int find_fading_range (ILuint n, struct PixelInfo *p, void *data)
250 struct nofading_data *d;
254 if (p->flags & EFF_GRAY)
256 UPDATE_RANGE(p->value, d->green_low, d->green_high);
258 else if (d->individual_channels)
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);
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);
270 if ((p->flags & EFF_ALPHA) && (d->enhance_alpha))
272 UPDATE_RANGE(p->alpha, d->alpha_low, d->alpha_high);
278 ILuint enhance_fading_1ch (ILuint val, ILuint low, ILuint high, ILuint max)
285 y = (((ILint64)val) - low) * max / (high - low);
286 return (ILuint)((y>max)?max:((y<0)?0:y));
289 int enhance_fading (ILuint n, struct PixelInfo *p, void *data)
291 struct nofading_data *d;
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)
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);
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);
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);