]> bicyclesonthemoon.info Git - ott/enhance/blob - npb.c
use config tool as submodule
[ott/enhance] / npb.c
1 /*
2 npb.c
3 Take a picture and add a newpixbot to it!
4 05.12.2022
5
6 Copyright (C) 2013 - 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 "npb.h"
35
36 #include "npb0.h"
37 #include "npb1.h"
38 #include "npb2.h"
39 #include "npb_ong1.h"
40 #include "npb_403.h"
41
42 #define NPB0_L      21
43 #define NPB0_R     116
44 #define NPB0_T     122
45 #define NPB0_B     189
46
47 #define NPB1_L      22
48 #define NPB1_R     154
49 #define NPB1_T      69
50 #define NPB1_B     162
51
52 #define NPB2_L      36
53 #define NPB2_R     199
54 #define NPB2_T     171
55 #define NPB2_B     171
56
57 #define NPB_ONG1_L -74
58 #define NPB_ONG1_R 102
59 #define NPB_ONG1_T  66
60 #define NPB_ONG1_B  69
61
62 #define NPB_403_L  224
63 #define NPB_403_R  295
64 #define NPB_403_T  261
65 #define NPB_403_B  261
66
67
68 char NPB_MISSING_ARGS[] = "Missing parameters.\nnpb [-o -4 -r -b -e -c] inPix outPix\n";
69
70 int subtool_npb (int argc, char **argv, int argi, char **err)
71 {
72         uint_fast8_t ong1 = 0;
73         uint_fast8_t t403 = 0;
74         uint_fast8_t corners = 0;
75         uint_fast8_t fullsize = 0;
76         uint_fast8_t fill_white = 0;
77         uint_fast8_t fill_white_all = 0;
78         uint_fast8_t npb_after = 0;
79         uint_fast8_t expand_left = 0;
80         uint_fast8_t expand_right = 0;
81         uint_fast8_t expand_up = 0;
82         uint_fast8_t expand_down = 0;
83         uint_fast8_t fixed_frame = 0;
84         uint_fast8_t override_new_border = 0;
85         uint_fast8_t override_external_border = 0;
86         
87         ILuint cut_border = 0;
88         ILuint new_border;
89         ILuint external_border;
90         ILuint new_border_default = 2;
91         ILuint external_border_default = 0;
92         ILuint max = 0xFF; //upscale_value(0xFF, info[0].image_bpc); // bpc=1
93         ILint width_content, height_content, x0_content_own, y0_content_own, x0_content_global, y0_content_global;
94         ILint width_border, height_border, x0_border, y0_border;
95         ILint width_npb, height_npb, x0_npb, y0_npb;
96         ILint width_total, height_total;
97         const uint8_t *npb_pix;
98         uint_fast32_t npb_size;
99         ILint space_l, space_r, space_t, space_b;
100         
101         struct ColorInfo color;
102         struct IL_full_info info_content;
103         struct IL_full_info info_npb;
104         struct IL_full_info info_total;
105         FLAG_TYPE flags_content = CANNOT_BE_GRAY | CANNOT_BE_INDEXED | NOT_WRITABLE;
106         FLAG_TYPE flags_npb     = CANNOT_BE_GRAY | CANNOT_BE_INDEXED | NOT_WRITABLE | MUST_HAVE_ALPHA;
107         FLAG_TYPE flags_total   = CANNOT_BE_GRAY | CANNOT_BE_INDEXED                | MUST_HAVE_ALPHA;
108         
109         uint_fast16_t id[2];
110         FLAG_TYPE flags[2];
111         ILint x0[2];
112         ILint y0[2];
113         ILint f0[2] = {0, 0};
114         
115         struct option long_options[] = {
116                 {"ong1",           no_argument,       NULL, 'o'},
117                 {"403",            no_argument,       NULL, '4'},
118                 {"remove-border",  required_argument, NULL, 'r'},
119                 {"new-border",     required_argument, NULL, 'b'},
120                 {"external-border",required_argument, NULL, 'e'},
121                 {"corners",        no_argument,       NULL, 'c'},
122                 {"help",           no_argument,       NULL, 'h'},
123                 {0,                0,                 0,    0}
124         };
125         char short_options[] = "o4r:b:e:ch0";
126         
127         int opt;
128         int r;
129         
130         /* we get options first */
131         
132         optind = argi;
133         while ((opt = getopt_long(argc, argv, short_options, long_options, NULL)) != -1)
134         {
135                 switch (opt)
136                 {
137                 case 'o':
138                         ong1 = 1;
139                         break;
140                 case '4':
141                         t403 = 1;
142                         break;
143                 case 'r':
144                         sscanf(optarg, "%u", &cut_border);
145                         break;
146                 case 'b':
147                         sscanf(optarg, "%u", &new_border);
148                         fullsize = 1;
149                         override_new_border = 1;
150                         break;
151                 case 'e':
152                         sscanf(optarg, "%u", &external_border);
153                         override_external_border = 1;
154                         break;
155                 case 'c':
156                         corners = 1;
157                         break;
158                 case 'h':
159                         /* help */
160                         break;
161                 }
162         }
163         
164         if (argc < optind + 2)
165         {
166                 *err = NPB_MISSING_ARGS;
167                 return EINVAL;
168         }
169         
170         r = reserve_pictures(3);
171         if (r)
172         {
173                 *err = CREATE_FAILED;
174                 return r;
175         }
176         
177         /* load content to insert to npb */
178         
179         r = load_picture(0, argv[optind], &(info_content), &(flags_content));
180         if (r)
181         {
182                 *err = LOAD_FAILED;
183                 return r;
184         }
185         
186         /* determine actually used rectangle without border */
187         
188         width_content = (info_content.image_width > (2*cut_border)) ? (info_content.image_width - (2*cut_border)) : 0;
189         height_content = (info_content.image_height > (2*cut_border)) ? (info_content.image_height - (2*cut_border)) : 0;
190         x0_content_own = cut_border;
191         y0_content_own = cut_border;
192         
193         /* select npb mode */
194         
195         if (t403)
196         {
197                 npb_pix = npb_403;
198                 npb_size = npb_403_size;
199                 space_l = NPB_403_L;
200                 space_r = NPB_403_R;
201                 space_t = NPB_403_T;
202                 space_b = NPB_403_B;
203                 expand_right = 1;
204                 expand_up = 1;
205                 new_border_default = 0;
206                 external_border_default = 2;
207                 fill_white_all = 1;
208         }
209         else if (ong1)
210         {
211                 npb_pix = npb_ong1;
212                 npb_size = npb_ong1_size;
213                 space_l = NPB_ONG1_L;
214                 space_r = NPB_ONG1_R;
215                 space_t = NPB_ONG1_T;
216                 space_b = NPB_ONG1_B;
217                 expand_left = 1;
218                 expand_up = 1;
219                 npb_after = 1;
220         }
221         else if ((width_content <= (NPB0_R - NPB0_L + 1)) && (height_content <= (NPB0_B - NPB0_T + 1)) && (!fullsize))
222         {
223                 npb_pix = npb0;
224                 npb_size = npb0_size;
225                 space_l = NPB0_L;
226                 space_r = NPB0_R;
227                 space_t = NPB0_T;
228                 space_b = NPB0_B;
229                 fill_white = 1;
230                 override_new_border = 1;
231                 new_border = 0;
232                 npb_after = 1;
233                 fixed_frame = 1;
234         }
235         else if ((width_content <= (NPB1_R - NPB1_L + 1)) && (height_content <= (NPB1_B - NPB1_T + 1)) && (!fullsize))
236         {
237                 npb_pix = npb1;
238                 npb_size = npb1_size;
239                 space_l = NPB1_L;
240                 space_r = NPB1_R;
241                 space_t = NPB1_T;
242                 space_b = NPB1_B;
243                 fill_white = 1;
244                 override_new_border = 1;
245                 new_border = 0;
246                 npb_after = 1;
247                 fixed_frame = 1;
248         }
249         else
250         {
251                 npb_pix = npb2;
252                 npb_size = npb2_size;
253                 space_l = NPB2_L;
254                 space_r = NPB2_R;
255                 space_t = NPB2_T;
256                 space_b = NPB2_B;
257                 expand_left = 1;
258                 expand_up = 1;
259                 npb_after = 1;
260         }
261         
262         /* determine borders' sizes */
263         if (!override_new_border)
264                 new_border = new_border_default;
265         if (!override_external_border)
266                 external_border = external_border_default;
267         
268         /* load selected npb */
269         
270         r = load_picture_mem(1, npb_pix, npb_size, &(info_npb), &(flags_npb));
271         if (r)
272         {
273                 *err = LOAD_FAILED;
274                 return r;
275         }
276         
277         /* determine rectangle of content with new border */
278         
279         width_border = width_content + new_border * 2;
280         height_border = height_content + new_border * 2;
281         
282         /* npb rectangle too */
283         
284         width_npb = info_npb.image_width;
285         height_npb = info_npb.image_height;
286         x0_npb = 0;
287         y0_npb = 0;
288         
289         /* initial total size, to update later */
290         
291         width_total = width_npb;
292         height_total = height_npb;
293         
294         /* determine content border placement in full picture */
295         
296         if (expand_right && (width_border >= (space_r - space_l +1)))
297                 x0_border = space_l;
298         else if (expand_left && (width_border >= (space_r - space_l +1)))
299                 x0_border = space_r - width_border + 1;
300         else
301                 x0_border = (space_l + space_r + 1 - width_border) / 2;
302         
303         if (expand_down && (height_border >= (space_b - space_t +1)))
304                 y0_border = space_t;
305         else if (expand_up && (height_border >= (space_b - space_t +1)))
306                 y0_border = space_b - height_border + 1;
307         else
308                 y0_border = (space_t + space_b + 1 - height_border) / 2;
309         
310         /* determine content placement in border in full picture */
311         
312         x0_content_global = x0_border + new_border;
313         y0_content_global = y0_border + new_border;
314         
315         /* adjust full picture size & offsets if content doesn't fit */
316         
317         if (width_total < (x0_border + width_border))
318                 width_total = x0_border + width_border;
319         if (height_total < (y0_border + height_border))
320                 height_total = y0_border + height_border;
321         if (x0_border < 0)
322         {
323                 width_total -= x0_border;
324                 x0_npb -= x0_border;
325                 x0_content_global -= x0_border;
326                 x0_border = 0;
327         }
328         if (y0_border < 0)
329         {
330                 height_total -= y0_border;
331                 y0_npb -= y0_border;
332                 y0_content_global -= y0_border;
333                 y0_border = 0;
334         }
335         
336         /* adjust for external border */
337         
338         if (external_border > 0)
339         {
340                 width_total += 2 * external_border;
341                 height_total += 2 * external_border;
342                 x0_border += external_border;
343                 y0_border += external_border;
344                 x0_content_global += external_border;
345                 y0_content_global += external_border;
346                 x0_npb += external_border;
347                 y0_npb += external_border;
348         }
349         
350         /* ok setup done, now perform actions */
351         
352         /* 1: create target picture */
353         
354         r = build_picture(2, width_total, height_total, 1, &info_total, &flags_total);
355         if (r!=0)
356         {
357                 *err = LOAD_FAILED;
358                 return r;
359         }
360         
361         /* 2: init background */
362         
363         color.red   = max;
364         color.green = max;
365         color.blue  = max;
366         color.alpha = fill_white_all ? max : 0;
367         
368         r = perform_action_1picture(
369                 2, //id
370                 external_border, //x0
371                 external_border, //y0
372                 0, //f0
373                 (width_total - 2 * external_border), //width
374                 (height_total - 2 * external_border), //height
375                 1, //frames
376                 &fill_color, //function
377                 flags_total | IN_WINDOW | NOT_READABLE, //flags
378                 &color //data
379         );
380         if (r!=0)
381         {
382                 *err = CONVERT_FAILED;
383                 return r;
384         }
385         
386         /* 3: draw border outside */
387         
388         if (external_border >0)
389         {
390                 color.red   = 0;
391                 color.green = 0;
392                 color.blue  = 0;
393                 color.alpha = max;
394                 
395                 r = perform_action_1picture( //top
396                         2, //id
397                         0, //x0
398                         0, //y0
399                         0, //f0
400                         width_total, //width
401                         external_border, //height
402                         1, //frames
403                         &fill_color, //function
404                         flags_total | IN_WINDOW | NOT_READABLE, //flags
405                         &color //data
406                 );
407                 if (r!=0)
408                 {
409                         *err = CONVERT_FAILED;
410                         return r;
411                 }
412                 
413                 r = perform_action_1picture( //bottom
414                         2, //id
415                         0, //x0
416                         height_total - external_border, //y0
417                         0, //f0
418                         width_total, //width
419                         external_border, //height
420                         1, //frames
421                         &fill_color, //function
422                         flags_total | IN_WINDOW | NOT_READABLE, //flags
423                         &color //data
424                 );
425                 if (r!=0)
426                 {
427                         *err = CONVERT_FAILED;
428                         return r;
429                 }
430                 
431                 r = perform_action_1picture( //left
432                         2, //id
433                         0, //x0
434                         external_border, //y0
435                         0, //f0
436                         external_border, //width
437                         height_total - 2*external_border, //height
438                         1, //frames
439                         &fill_color, //function
440                         flags_total | IN_WINDOW | NOT_READABLE, //flags
441                         &color //data
442                 );
443                 if (r!=0)
444                 {
445                         *err = CONVERT_FAILED;
446                         return r;
447                 }
448                 
449                 r = perform_action_1picture( //right
450                         2, //id
451                         width_total - external_border, //x0
452                         external_border, //y0
453                         0, //f0
454                         external_border, //width
455                         height_total - 2*external_border, //height
456                         1, //frames
457                         &fill_color, //function
458                         flags_total | IN_WINDOW | NOT_READABLE, //flags
459                         &color //data
460                 );
461                 if (r!=0)
462                 {
463                         *err = CONVERT_FAILED;
464                         return r;
465                 }
466                 
467                 if (corners)
468                 {
469                         color.alpha = 0;
470                         
471                         r = perform_action_1picture_1pixel( //top-left
472                                 2, //id
473                                 0, //x0
474                                 0, //y0
475                                 0, //f0
476                                 &fill_color, //function
477                                 flags_total | IN_WINDOW | NOT_READABLE, //flags
478                                 &color //data
479                         );
480                         if (r!=0)
481                         {
482                                 *err = CONVERT_FAILED;
483                                 return r;
484                         }
485                         
486                         r = perform_action_1picture_1pixel( //top-right
487                                 2, //id
488                                 width_total - 1, //x0
489                                 0, //y0
490                                 0, //f0
491                                 &fill_color, //function
492                                 flags_total | IN_WINDOW | NOT_READABLE, //flags
493                                 &color //data
494                         );
495                         if (r!=0)
496                         {
497                                 *err = CONVERT_FAILED;
498                                 return r;
499                         }
500                         
501                         r = perform_action_1picture_1pixel( //bottom-right
502                                 2, //id
503                                 width_total - 1, //x0
504                                 height_total - 1, //y0
505                                 0, //f0
506                                 &fill_color, //function
507                                 flags_total | IN_WINDOW | NOT_READABLE, //flags
508                                 &color //data
509                         );
510                         if (r!=0)
511                         {
512                                 *err = CONVERT_FAILED;
513                                 return r;
514                         }
515                         
516                         r = perform_action_1picture_1pixel( //bottom-left
517                                 2, //id
518                                 0, //x0
519                                 height_total - 1, //y0
520                                 0, //f0
521                                 &fill_color, //function
522                                 flags_total | IN_WINDOW | NOT_READABLE, //flags
523                                 &color //data
524                         );
525                         if (r!=0)
526                         {
527                                 *err = CONVERT_FAILED;
528                                 return r;
529                         }
530                 }
531         }
532         
533         /* 4: insert npb before */
534         
535         if (!npb_after)
536         {
537                 id[0] = 1; //npb
538                 id[1] = 2; //total
539                 x0[0] = 0;
540                 x0[1] = x0_npb;
541                 y0[0] = 0;
542                 y0[1] = y0_npb;
543                 flags[0] = flags_npb | IN_WINDOW;
544                 flags[1] = flags_total | IN_WINDOW;
545                 
546                 r = perform_action(
547                         2, //n
548                         id,
549                         x0, y0, f0,
550                         width_npb, height_npb, 1,
551                         &copy_pixels,
552                         flags,
553                         &max //data
554                 );
555                 if (r!=0)
556                 {
557                         *err = CONVERT_FAILED;
558                         return r;
559                 }
560         }
561         
562         /* 5: fill_background */
563         
564         if (fill_white)
565         {
566                 color.red   = max;
567                 color.green = max;
568                 color.blue  = max;
569                 color.alpha = max;
570                 
571                 r = perform_action_1picture(
572                         2, //id
573                         fixed_frame ? space_l + external_border : x0_content_global, //x0
574                         fixed_frame ? space_t + external_border: y0_content_global, //y0
575                         0, //f0
576                         fixed_frame ? (space_r - space_l + 1) : width_content, //width
577                         fixed_frame ? (space_b - space_t + 1) : height_content, //height
578                         1, //frames
579                         &fill_color, //function
580                         flags_total | IN_WINDOW | NOT_READABLE, //flags
581                         &color //data
582                 );
583                 if (r!=0)
584                 {
585                         *err = CONVERT_FAILED;
586                         return r;
587                 }
588         }
589         
590         /* 6: insert content */
591         
592         id[0] = 0; //content
593         id[1] = 2; //total
594         x0[0] = x0_content_own;
595         x0[1] = x0_content_global;
596         y0[0] = y0_content_own;
597         y0[1] = y0_content_global;
598         flags[0] = flags_content | IN_WINDOW;
599         flags[1] = flags_total | IN_WINDOW;
600         
601         r = perform_action(
602                 2, //n
603                 id,
604                 x0, y0, f0,
605                 width_content, height_content, 1,
606                 &copy_pixels,
607                 flags,
608                 &max //data
609         );
610         if (r!=0)
611         {
612                 *err = CONVERT_FAILED;
613                 return r;
614         }
615         
616         /* 7: draw border */
617         
618         if (new_border >0)
619         {
620                 color.red   = 0;
621                 color.green = 0;
622                 color.blue  = 0;
623                 color.alpha = max;
624                 
625                 r = perform_action_1picture( //top
626                         2, //id
627                         corners ? (x0_border + 1) : x0_border, //x0
628                         y0_border, //y0
629                         0, //f0
630                         corners ? (width_border - 2) : width_border, //width
631                         new_border, //height
632                         1, //frames
633                         &fill_color, //function
634                         flags_total | IN_WINDOW | NOT_READABLE, //flags
635                         &color //data
636                 );
637                 if (r!=0)
638                 {
639                         *err = CONVERT_FAILED;
640                         return r;
641                 }
642                 
643                 r = perform_action_1picture( //bottom
644                         2, //id
645                         corners ? (x0_border + 1) : x0_border, //x0
646                         y0_border + height_border - new_border, //y0
647                         0, //f0
648                         corners ? (width_border - 2) : width_border, //width
649                         new_border, //height
650                         1, //frames
651                         &fill_color, //function
652                         flags_total | IN_WINDOW | NOT_READABLE, //flags
653                         &color //data
654                 );
655                 if (r!=0)
656                 {
657                         *err = CONVERT_FAILED;
658                         return r;
659                 }
660                 
661                 r = perform_action_1picture( //left
662                         2, //id
663                         x0_border, //x0
664                         corners ? (y0_border + 1) : y0_content_global , //y0
665                         0, //f0
666                         new_border, //width
667                         corners ? (height_border - 2) : height_content, //height
668                         1, //frames
669                         &fill_color, //function
670                         flags_total | IN_WINDOW | NOT_READABLE, //flags
671                         &color //data
672                 );
673                 if (r!=0)
674                 {
675                         *err = CONVERT_FAILED;
676                         return r;
677                 }
678                 
679                 r = perform_action_1picture( //right
680                         2, //id
681                         x0_border + width_border - new_border, //x0
682                         corners ? (y0_border + 1) : y0_content_global , //y0
683                         0, //f0
684                         new_border, //width
685                         corners ? (height_border - 2) : height_content, //height
686                         1, //frames
687                         &fill_color, //function
688                         flags_total | IN_WINDOW | NOT_READABLE, //flags
689                         &color //data
690                 );
691                 if (r!=0)
692                 {
693                         *err = CONVERT_FAILED;
694                         return r;
695                 }
696         }
697         
698         /* 8: insert npb after */
699         
700         if (npb_after)
701         {
702                 id[0] = 1; //npb
703                 id[1] = 2; //total
704                 x0[0] = 0;
705                 x0[1] = x0_npb;
706                 y0[0] = 0;
707                 y0[1] = y0_npb;
708                 flags[0] = flags_npb | IN_WINDOW;
709                 flags[1] = flags_total | IN_WINDOW;
710                 
711                 r = perform_action(
712                         2, //n
713                         id,
714                         x0, y0, f0,
715                         width_npb, height_npb, 1,
716                         &copy_pixels,
717                         flags,
718                         &max //data
719                 );
720                 if (r!=0)
721                 {
722                         *err = CONVERT_FAILED;
723                         return r;
724                 }
725         }
726         
727         /* 9: ok, done, now save */
728         
729         r = save_picture(2, argv[optind+1], flags_total);
730         if (r!=0)
731         {
732                 *err = SAVE_FAILED;
733                 return r;
734         }
735         
736         return 0;
737 }