]> bicyclesonthemoon.info Git - ott/enhance/blob - pal_mix.c
2ced874c12b3b0f465b547799e9f286b27941c73
[ott/enhance] / pal_mix.c
1 /*
2 pal_mix.c
3 The tool to hide two indexed images iside one
4 30.11.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 <errno.h>
32
33 #include "core.h"
34 #include "pal_mix.h"
35
36 struct rel_data
37 {
38         ILuint p0;
39         ILuint p1;
40         ILuint p;
41 };
42
43 int palette_mix_value (ILuint n, struct PixelInfo *p, void *data);
44 ILuint mix_value_1ch (ILint64 x, ILint64 y, struct rel_data *rel);
45
46 char PAL_MIX_MISSING_ARGS[] = "Missing parameters.\npal_mix inPix1 inpix2 outPix [p1 p2]\n";
47
48 int subtool_pal_mix (int argc, char **argv, int argi, char **err)
49 {
50         uint_fast16_t id[3] = {0, 1, 2};
51         ILint xyf0[3] = {0, 0, 0};
52         struct IL_full_info info[3];
53         FLAG_TYPE flags[3] = {
54                 MUST_BE_INDEXED | NOT_WRITABLE | OK_PALETTE_ONLY,
55                 MUST_BE_INDEXED | NOT_WRITABLE | OK_PALETTE_ONLY,
56                 MUST_BE_INDEXED | NOT_READABLE | OK_PALETTE_ONLY
57         };
58         ILubyte new_pal[0x100 * 4];
59         struct rel_data data;
60         ILuint i;
61         int r;
62         
63         if (argc < argi + 3)
64         {
65                 *err = PAL_MIX_MISSING_ARGS;
66                 return EINVAL;
67         }
68         
69         if (argc >= argi + 5)
70         {
71                 sscanf(argv[argi+3],"%u",&(data.p0));
72                 sscanf(argv[argi+4],"%u",&(data.p1));
73         }
74         else
75         {
76                 data.p0 = 1;
77                 data.p1 = 0;
78         }
79         data.p = data.p0 + data.p1;
80         
81         r = reserve_pictures(3);
82         if (r)
83         {
84                 *err = CREATE_FAILED;
85                 return r;
86         }
87         
88         r = load_picture(0, argv[argi], &(info[0]), &(flags[0]));
89         if (r)
90         {
91                 *err = LOAD_FAILED;
92                 return r;
93         }
94         
95         r = load_picture(1, argv[argi+1], &(info[1]), &(flags[1]));
96         if (r)
97         {
98                 *err = LOAD_FAILED;
99                 return r;
100         }
101         
102         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))
103         {
104                 *err = SIZE_MISMATCH;
105                 return EINVAL;
106         }
107         
108         if ((info[0].palette_num_cols * info[1].palette_num_cols) > 0x100)
109         {
110                 *err = BAD_PALETTE_SIZE;
111                 return EINVAL;
112         }
113         
114         if ((flags[0] & HAS_ALPHA) || (flags[1] & HAS_ALPHA))
115         {
116                 flags[0] |= MUST_HAVE_ALPHA;
117                 flags[1] |= MUST_HAVE_ALPHA;
118                 flags[2] |= MUST_HAVE_ALPHA;
119         }
120         else
121                 flags[2] |= CANNOT_HAVE_ALPHA;
122         
123         r = convert_picture(0, &(info[0]), &(flags[0]));
124         if (r!=0)
125         {
126                 *err = CONVERT_FAILED;
127                 return EIO;
128         }
129         
130         r = convert_picture(1, &(info[1]), &(flags[1]));
131         if (r!=0)
132         {
133                 *err = CONVERT_FAILED;
134                 return EIO;
135         }
136         
137         r = build_picture_from_info(2, &(info[0]), &(info[2]), &(flags[2]));
138         if (r!=0)
139         {
140                 *err = CREATE_FAILED;
141                 return EIO;
142         }
143         
144         for (i=0; i<=info[2].num_images; ++i)
145         {
146                 set_palette (
147                 2,
148                 new_pal,
149                 info[0].palette_num_cols * info[1].palette_num_cols * info[0].palette_bpp,
150                 info[0].palette_type,
151                 i
152                 );
153         }
154         
155         r = perform_action_palette_mix(
156                 id,
157                 &palette_mix_value,
158                 flags,
159                 &data
160         );
161         if (r)
162         {
163                 *err = CONVERT_FAILED;
164                 return r;
165         }
166         
167         flags[0] &= ~OK_PALETTE_ONLY;
168         flags[1] &= ~OK_PALETTE_ONLY;
169         flags[2] &= ~OK_PALETTE_ONLY;
170         
171         r = perform_action(
172                 3,
173                 id,
174                 xyf0, xyf0, xyf0,
175                 0, 0, 0,
176                 &palette_mix_index,
177                 flags,
178                 &data
179         );
180         if (r)
181         {
182                 *err = CONVERT_FAILED;
183                 return r;
184         }
185         
186         r = save_picture(2, argv[argi+2], flags[2]);
187         if (r!=0)
188         {
189                 *err = SAVE_FAILED;
190                 return r;
191         }
192         
193         return 0;
194 }
195
196 int palette_mix_value (ILuint n, struct PixelInfo *p, void *data)
197 {
198         if (n < 3)
199                 return EIO;
200         
201         p[2].red   = mix_value_1ch(p[0].red,   p[1].red,   data);
202         p[2].green = mix_value_1ch(p[0].green, p[1].green, data);
203         p[2].blue  = mix_value_1ch(p[0].blue,  p[1].blue,  data);
204         if (p[2].flags & EFF_ALPHA)
205                 p[2].alpha = mix_value_1ch(p[0].alpha, p[1].alpha, data);
206         
207         return 0;
208 }
209
210 ILuint mix_value_1ch (ILint64 x, ILint64 y, struct rel_data *rel)
211 {
212         ILint64 v = (x * rel->p0 + y * rel->p1) / rel->p;
213         return (ILuint) v;
214 }
215
216 /*
217 #include <stdlib.h>
218 #include <stdio.h>
219 #include "IL/il.h"
220
221 int mustard(const char *t,int m,int e);
222 int main(int argc, char *argv[]);
223
224 ILuint inpix1, inpix2, outpix;
225 unsigned char q =0;
226
227
228 int main(int argc, char *argv[])
229 {
230         
231         ILubyte *pal1, *pal2, *data1, *data2, *data;
232         ILubyte pal[256*3];
233         unsigned short i,j;
234         unsigned long k;
235         ILuint col1, col2, col,  x1, x2, y1, y2;
236         
237         unsigned short p1, p2, p3;
238         
239         if (argc<4)
240                 return mustard("insert inpix1 inpix2 outpix [p1 p2]",0,1);
241         if(argc>=5)
242                 p1=atoi(argv[4]);
243         else
244                 p1=1;
245         if(argc>=6)
246                 p2=atoi(argv[5]);
247         else
248                 p2=0;
249         if(argc>=7)
250                 q=1;
251         p3=p1+p2;
252         
253         ilInit();
254                 
255         ilEnable(IL_ORIGIN_SET);
256         ilEnable(IL_FILE_OVERWRITE);
257         
258         ilGenImages(1,&inpix1);
259         ilGenImages(1,&inpix2);
260         ilGenImages(1,&outpix);
261         
262         ilBindImage(inpix1);
263         if(!ilLoadImage(argv[1]))
264                 return mustard("inpix1 load fail.",1,1);
265         if(ilGetInteger(IL_IMAGE_FORMAT)!=IL_COLOUR_INDEX)
266                 return mustard("inpix1 not indexed.",1,1);
267         ilConvertPal(IL_PAL_RGB24);
268         col1=ilGetInteger(IL_PALETTE_NUM_COLS);
269         if(col1>16)
270                 return mustard("inpix1 too many colors.",1,1);
271         x1=ilGetInteger(IL_IMAGE_WIDTH);
272         y1=ilGetInteger(IL_IMAGE_HEIGHT);
273         pal1=ilGetPalette();
274         data1=ilGetData();
275         
276         ilBindImage(inpix2);
277         if(!ilLoadImage(argv[2]))
278                 return mustard("inpix2 load fail.",1,1);
279         if(ilGetInteger(IL_IMAGE_FORMAT)!=IL_COLOUR_INDEX)
280                 return mustard("inpix2 not indexed.",1,1);
281         ilConvertPal(IL_PAL_RGB24);
282         col2=ilGetInteger(IL_PALETTE_NUM_COLS);
283         if(col2>16)
284                 return mustard("inpix2 too many colors.",1,1);
285         if(col1!=col2)
286                 return mustard("different palette size.",1,1);
287         x2=ilGetInteger(IL_IMAGE_WIDTH);
288         if(x1!=x2)
289                 return mustard("different widths",1,1);
290         y2=ilGetInteger(IL_IMAGE_HEIGHT);
291         if(y1!=y2)
292                 return mustard("different heights",1,1);
293         pal2=ilGetPalette();
294         data2=ilGetData();
295         col=col1*col2;
296         
297         for(i=0;i<col1;++i)
298         {
299                 for(j=0;j<col2;++j)
300                 {
301                         pal[3*(i*col1+j)  ]=(pal1[3*i  ]*p1+pal2[3*j  ]*p2)/p3;
302                         pal[3*(i*col1+j)+1]=(pal1[3*i+1]*p1+pal2[3*j+1]*p2)/p3;
303                         pal[3*(i*col1+j)+2]=(pal1[3*i+2]*p1+pal2[3*j+2]*p2)/p3;
304                 }
305         }
306         
307         ilBindImage(outpix);
308         if(!ilTexImage(x1,y1,1,1,IL_COLOUR_INDEX,IL_UNSIGNED_BYTE,NULL))
309                 return mustard ("outpix create fail.",1,1);
310         ilRegisterPal(pal,col*3,IL_PAL_RGB24);
311         data=ilGetData();
312         
313         for(k=0;k<x1*y1;++k)
314                 data[k]=data1[k]*col2+data2[k];
315         
316         if(!ilSave(IL_PNG,argv[3]))
317                 return mustard("outpix save fail",1,1);
318                                 
319         return mustard("Ok",1,0);
320         
321         
322 }
323 int mustard(const char *t, int m,int e)
324 {
325         if(!q)puts(t);
326         switch (m)
327   {
328   case 1:
329         ilDeleteImages(1,&inpix1);
330                 ilDeleteImages(1,&inpix2);
331                 ilDeleteImages(1,&outpix);
332   case 0:
333   default:
334                 return e;
335         }
336 }
337         
338 */