]> bicyclesonthemoon.info Git - ott/enhance/blob - diff.c
Partial CGI update bacause git disagrees with me.
[ott/enhance] / diff.c
1 /*
2 diff.c
3 see the difference!
4 30.11.2022
5
6 Copyright (C) 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 #define RA 0x00
30 #define GA 0x57
31 #define BA 0xAF
32
33 #define RB 0xBB
34 #define GB 0x66
35 #define BB 0x22
36
37 #include <stdio.h>
38 #include <errno.h>
39
40 #include "bluenh.h"
41 #include "core.h"
42
43 struct diff_data
44 {
45         ILuint r_a;
46         ILuint g_a;
47         ILuint b_a;
48         ILuint r_b;
49         ILuint g_b;
50         ILuint b_b;
51         ILuint max;
52 };
53
54 int difference (ILuint n, struct PixelInfo *p, void *data);
55 static inline ILuint diff_1ch (ILint64 x, ILint64 y, ILint64 A, ILint64 B, ILint64 F);
56
57 char DIFF_MISSING_ARGS[] = "Missing parameters.\ndiff inPixA inPixB outPix [RA GA BA [RB GB BB]]\n";
58
59 int subtool_diff (int argc, char **argv, int argi, char **err)
60 {
61         ILubyte v;
62         struct diff_data data;
63         struct IL_full_info info[3];
64         uint_fast16_t id[3] = {0, 1, 2};
65         ILint xyf0[3] = {0, 0, 0};
66         FLAG_TYPE flags[3] = {
67                 CAN_BE_MULTIPLE | CAN_BE_OVER_8BIT | CANNOT_BE_GRAY | NOT_WRITABLE,
68                 CAN_BE_MULTIPLE | CAN_BE_OVER_8BIT | CANNOT_BE_GRAY | NOT_WRITABLE,
69                 CAN_BE_MULTIPLE | CAN_BE_OVER_8BIT | CANNOT_BE_GRAY | NOT_READABLE
70         };
71         uint_fast8_t palette_only;
72         ILuint i;
73         ILubyte new_pal[0x100 * 4];
74         int r;
75         
76         if (argc < argi + 3)
77         {
78                 *err = DIFF_MISSING_ARGS;
79                 return EINVAL;
80         }
81         
82         r = reserve_pictures(3);
83         if (r)
84         {
85                 *err = CREATE_FAILED;
86                 return r;
87         }
88         
89         r = load_picture(0, argv[argi], &(info[0]), &(flags[0]));
90         if (r)
91         {
92                 *err = LOAD_FAILED;
93                 return r;
94         }
95         
96         r = load_picture(1, argv[argi+1], &(info[1]), &(flags[1]));
97         if (r)
98         {
99                 *err = LOAD_FAILED;
100                 return r;
101         }
102         
103         if ((info[0].image_height != info[1].image_height) || (info[0].image_width != info[1].image_width) || (info[0].num_images != info[1].num_images))
104         {
105                 *err = SIZE_MISMATCH;
106                 return EINVAL;
107         }
108         
109         if ((info[0].image_bpc != info[1].image_bpc) || (!(flags[0] & IS_OVER_8BIT)) || (!(flags[0] & IS_OVER_8BIT)))
110         {
111                 flags[0] &= ~CAN_BE_OVER_8BIT;
112                 flags[1] &= ~CAN_BE_OVER_8BIT;
113                 flags[2] &= ~CAN_BE_OVER_8BIT;
114         }
115         
116         if ((flags[0] & HAS_ALPHA) || (flags[1] & HAS_ALPHA))
117         {
118                 flags[0] |= MUST_HAVE_ALPHA;
119                 flags[1] |= MUST_HAVE_ALPHA;
120                 flags[2] |= MUST_HAVE_ALPHA;
121         }
122         else
123                 flags[2] |= CANNOT_HAVE_ALPHA;
124         
125         if ((flags[0] & IS_INDEXED) && (flags[1] & IS_INDEXED) && ((info[0].palette_num_cols * info[1].palette_num_cols) <= 0x100))
126         {
127                 palette_only = 1;
128                 flags[0] |= OK_PALETTE_ONLY;
129                 flags[1] |= OK_PALETTE_ONLY;
130                 flags[2] |= OK_PALETTE_ONLY;
131                 flags[0] &= ~CAN_BE_OVER_8BIT;
132                 flags[1] &= ~CAN_BE_OVER_8BIT;
133                 flags[2] &= ~CAN_BE_OVER_8BIT;
134                 flags[2] |= MUST_BE_INDEXED;
135         }
136         else
137         {
138                 palette_only = 0;
139                 flags[0] |= CANNOT_BE_INDEXED;
140                 flags[1] |= CANNOT_BE_INDEXED;
141                 flags[2] |= CANNOT_BE_INDEXED;
142         }
143         
144         r = convert_picture(0, &(info[0]), &(flags[0]));
145         if (r!=0)
146         {
147                 *err = CONVERT_FAILED;
148                 return EIO;
149         }
150         
151         r = convert_picture(1, &(info[1]), &(flags[1]));
152         if (r!=0)
153         {
154                 *err = CONVERT_FAILED;
155                 return EIO;
156         }
157         
158         if (argc >= argi + 6)
159         {
160                 sscanf(argv[argi+3],"%hhu",&v);
161                 data.r_a = upscale_value(v, info[0].image_bpc);
162                 sscanf(argv[argi+4],"%hhu",&v);
163                 data.g_a = upscale_value(v, info[0].image_bpc);
164                 sscanf(argv[argi+5],"%hhu",&v);
165                 data.b_a = upscale_value(v, info[0].image_bpc);
166         }
167         else
168         {
169                 data.r_a = upscale_value(RA, info[0].image_bpc);
170                 data.g_a = upscale_value(GA, info[0].image_bpc);
171                 data.b_a = upscale_value(BA, info[0].image_bpc);
172         }
173         if (argc >= argi + 9)
174         {
175                 sscanf(argv[argi+6],"%hhu",&v);
176                 data.r_b = upscale_value(v, info[0].image_bpc);
177                 sscanf(argv[argi+7],"%hhu",&v);
178                 data.g_b = upscale_value(v, info[0].image_bpc);
179                 sscanf(argv[argi+8],"%hhu",&v);
180                 data.b_b = upscale_value(v, info[0].image_bpc);
181         }
182         else
183         {
184                 data.r_b = upscale_value(RB, info[0].image_bpc);
185                 data.g_b = upscale_value(GB, info[0].image_bpc);
186                 data.b_b = upscale_value(BB, info[0].image_bpc);
187         }
188         data.max = upscale_value(0xFF, info[0].image_bpc);
189         
190         r = build_picture_from_info(2, &(info[0]), &(info[2]), &(flags[2]));
191         if (r!=0)
192         {
193                 *err = CREATE_FAILED;
194                 return EIO;
195         }
196         
197         if (palette_only)
198         {
199                 for (i=0; i<=info[2].num_images; ++i)
200                 {
201                         set_palette (
202                         2,
203                         new_pal,
204                         info[0].palette_num_cols * info[1].palette_num_cols * info[0].palette_bpp,
205                         info[0].palette_type,
206                         i
207                         );
208                 }
209                 
210                 r = perform_action_palette_mix(
211                         id,
212                         &difference,
213                         flags,
214                         &data
215                 );
216                 if (r)
217                 {
218                         *err = CONVERT_FAILED;
219                         return r;
220                 }
221                 flags[0] &= ~OK_PALETTE_ONLY;
222                 flags[1] &= ~OK_PALETTE_ONLY;
223                 flags[2] &= ~OK_PALETTE_ONLY;
224                 r = perform_action(
225                         3,
226                         id,
227                         xyf0, xyf0, xyf0,
228                         0, 0, 0,
229                         &palette_mix_index,
230                         flags,
231                         &data
232                 );
233                 if (r)
234                 {
235                         *err = CONVERT_FAILED;
236                         return r;
237                 }
238         }
239         else
240         {
241                 r = perform_action(
242                         3,
243                         id,
244                         xyf0, xyf0, xyf0,
245                         0, 0, 0,
246                         &difference,
247                         flags,
248                         &data
249                 );
250                 if (r)
251                 {
252                         *err = CONVERT_FAILED;
253                         return r;
254                 }
255         }
256         
257         r = save_picture(2, argv[argi+2], flags[2]);
258         if (r!=0)
259         {
260                 *err = SAVE_FAILED;
261                 return r;
262         }
263         
264         return 0;
265 }
266
267 int difference (ILuint n, struct PixelInfo *p, void *data)
268 {
269         struct diff_data *d;
270         d = data;
271         
272         if (n < 3)
273                 return EIO;
274         
275         p[2].red   = diff_1ch(p[0].red,   p[1].red,   d->r_a, d->r_b, d->max);
276         p[2].green = diff_1ch(p[0].green, p[1].green, d->g_a, d->g_b, d->max);
277         p[2].blue  = diff_1ch(p[0].blue,  p[1].blue,  d->b_a, d->b_b, d->max);
278         if (p[2].flags & EFF_ALPHA)
279                 p[2].alpha = (p[0].alpha + p[1].alpha) / 2; /* no better idea */
280         
281         return 0;
282 }
283
284 static inline ILuint diff_1ch (ILint64 x, ILint64 y, ILint64 A, ILint64 B, ILint64 F)
285 {
286         ILint64 v;
287         
288         if (x == y)
289                 return (ILuint) x;
290         else if (x > y)
291                 v = y + ((A * (x - y)) / F);
292         else
293                 v = x + ((B * (y - x)) / F);
294         
295         return (ILuint) v;
296 }