]> bicyclesonthemoon.info Git - ott/enhance/blob - npb.c
Online bluenh seems to work ok.
[ott/enhance] / npb.c
1 /*
2 npb.c
3 Take a picture and add a newpixbot to it!
4 30.11.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:ch";
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                 new_border = 0;
231                 npb_after = 1;
232                 fixed_frame = 1;
233         }
234         else if ((width_content <= (NPB1_R - NPB1_L + 1)) && (height_content <= (NPB1_B - NPB1_T + 1)) && (!fullsize))
235         {
236                 npb_pix = npb1;
237                 npb_size = npb1_size;
238                 space_l = NPB1_L;
239                 space_r = NPB1_R;
240                 space_t = NPB1_T;
241                 space_b = NPB1_B;
242                 fill_white = 1;
243                 new_border = 0;
244                 npb_after = 1;
245                 fixed_frame = 1;
246         }
247         else
248         {
249                 npb_pix = npb2;
250                 npb_size = npb2_size;
251                 space_l = NPB2_L;
252                 space_r = NPB2_R;
253                 space_t = NPB2_T;
254                 space_b = NPB2_B;
255                 expand_left = 1;
256                 expand_up = 1;
257                 npb_after = 1;
258         }
259         
260         /* determine borders' sizes */
261         if (!override_new_border)
262                 new_border = new_border_default;
263         if (!override_external_border)
264                 external_border = external_border_default;
265         
266         /* load selected npb */
267         
268         r = load_picture_mem(1, npb_pix, npb_size, &(info_npb), &(flags_npb));
269         if (r)
270         {
271                 *err = LOAD_FAILED;
272                 return r;
273         }
274         
275         /* determine rectangle of content with new border */
276         
277         width_border = width_content + new_border * 2;
278         height_border = height_content + new_border * 2;
279         
280         /* npb rectangle too */
281         
282         width_npb = info_npb.image_width;
283         height_npb = info_npb.image_height;
284         x0_npb = 0;
285         y0_npb = 0;
286         
287         /* initial total size, to update later */
288         
289         width_total = width_npb;
290         height_total = height_npb;
291         
292         /* determine content border placement in full picture */
293         
294         if (expand_right && (width_border >= (space_r - space_l +1)))
295                 x0_border = space_l;
296         else if (expand_left && (width_border >= (space_r - space_l +1)))
297                 x0_border = space_r - width_border + 1;
298         else
299                 x0_border = (space_l + space_r + 1 - width_border) / 2;
300         
301         if (expand_down && (height_border >= (space_b - space_t +1)))
302                 y0_border = space_t;
303         else if (expand_up && (height_border >= (space_b - space_t +1)))
304                 y0_border = space_b - height_border + 1;
305         else
306                 y0_border = (space_t + space_b + 1 - height_border) / 2;
307         
308         /* determine content placement in border in full picture */
309         
310         x0_content_global = x0_border + new_border;
311         y0_content_global = y0_border + new_border;
312         
313         /* adjust full picture size & offsets if content doesn't fit */
314         
315         if (width_total < (x0_border + width_border))
316                 width_total = x0_border + width_border;
317         if (height_total < (y0_border + height_border))
318                 height_total = y0_border + height_border;
319         if (x0_border < 0)
320         {
321                 width_total -= x0_border;
322                 x0_npb -= x0_border;
323                 x0_content_global -= x0_border;
324                 x0_border = 0;
325         }
326         if (y0_border < 0)
327         {
328                 height_total -= y0_border;
329                 y0_npb -= y0_border;
330                 y0_content_global -= y0_border;
331                 y0_border = 0;
332         }
333         
334         /* adjust for external border */
335         
336         if (external_border > 0)
337         {
338                 width_total += 2 * external_border;
339                 height_total += 2 * external_border;
340                 x0_border += external_border;
341                 y0_border += external_border;
342                 x0_content_global += external_border;
343                 y0_content_global += external_border;
344                 x0_npb += external_border;
345                 y0_npb += external_border;
346         }
347         
348         /* ok setup done, now perform actions */
349         
350         /* 1: create target picture */
351         
352         r = build_picture(2, width_total, height_total, 1, &info_total, &flags_total);
353         if (r!=0)
354         {
355                 *err = LOAD_FAILED;
356                 return r;
357         }
358         
359         /* 2: init background */
360         
361         color.red   = max;
362         color.green = max;
363         color.blue  = max;
364         color.alpha = fill_white_all ? max : 0;
365         
366         r = perform_action_1picture(
367                 2, //id
368                 external_border, //x0
369                 external_border, //y0
370                 0, //f0
371                 (width_total - 2 * external_border), //width
372                 (height_total - 2 * external_border), //height
373                 1, //frames
374                 &fill_color, //function
375                 flags_total | IN_WINDOW | NOT_READABLE, //flags
376                 &color //data
377         );
378         if (r!=0)
379         {
380                 *err = CONVERT_FAILED;
381                 return r;
382         }
383         
384         /* 3: draw border outside */
385         
386         if (external_border >0)
387         {
388                 color.red   = 0;
389                 color.green = 0;
390                 color.blue  = 0;
391                 color.alpha = max;
392                 
393                 r = perform_action_1picture( //top
394                         2, //id
395                         0, //x0
396                         0, //y0
397                         0, //f0
398                         width_total, //width
399                         external_border, //height
400                         1, //frames
401                         &fill_color, //function
402                         flags_total | IN_WINDOW | NOT_READABLE, //flags
403                         &color //data
404                 );
405                 if (r!=0)
406                 {
407                         *err = CONVERT_FAILED;
408                         return r;
409                 }
410                 
411                 r = perform_action_1picture( //bottom
412                         2, //id
413                         0, //x0
414                         height_total - external_border, //y0
415                         0, //f0
416                         width_total, //width
417                         external_border, //height
418                         1, //frames
419                         &fill_color, //function
420                         flags_total | IN_WINDOW | NOT_READABLE, //flags
421                         &color //data
422                 );
423                 if (r!=0)
424                 {
425                         *err = CONVERT_FAILED;
426                         return r;
427                 }
428                 
429                 r = perform_action_1picture( //left
430                         2, //id
431                         0, //x0
432                         external_border, //y0
433                         0, //f0
434                         external_border, //width
435                         height_total - 2*external_border, //height
436                         1, //frames
437                         &fill_color, //function
438                         flags_total | IN_WINDOW | NOT_READABLE, //flags
439                         &color //data
440                 );
441                 if (r!=0)
442                 {
443                         *err = CONVERT_FAILED;
444                         return r;
445                 }
446                 
447                 r = perform_action_1picture( //right
448                         2, //id
449                         width_total - external_border, //x0
450                         external_border, //y0
451                         0, //f0
452                         external_border, //width
453                         height_total - 2*external_border, //height
454                         1, //frames
455                         &fill_color, //function
456                         flags_total | IN_WINDOW | NOT_READABLE, //flags
457                         &color //data
458                 );
459                 if (r!=0)
460                 {
461                         *err = CONVERT_FAILED;
462                         return r;
463                 }
464                 
465                 if (corners)
466                 {
467                         color.alpha = 0;
468                         
469                         r = perform_action_1picture_1pixel( //top-left
470                                 2, //id
471                                 0, //x0
472                                 0, //y0
473                                 0, //f0
474                                 &fill_color, //function
475                                 flags_total | IN_WINDOW | NOT_READABLE, //flags
476                                 &color //data
477                         );
478                         if (r!=0)
479                         {
480                                 *err = CONVERT_FAILED;
481                                 return r;
482                         }
483                         
484                         r = perform_action_1picture_1pixel( //top-right
485                                 2, //id
486                                 width_total - 1, //x0
487                                 0, //y0
488                                 0, //f0
489                                 &fill_color, //function
490                                 flags_total | IN_WINDOW | NOT_READABLE, //flags
491                                 &color //data
492                         );
493                         if (r!=0)
494                         {
495                                 *err = CONVERT_FAILED;
496                                 return r;
497                         }
498                         
499                         r = perform_action_1picture_1pixel( //bottom-right
500                                 2, //id
501                                 width_total - 1, //x0
502                                 height_total - 1, //y0
503                                 0, //f0
504                                 &fill_color, //function
505                                 flags_total | IN_WINDOW | NOT_READABLE, //flags
506                                 &color //data
507                         );
508                         if (r!=0)
509                         {
510                                 *err = CONVERT_FAILED;
511                                 return r;
512                         }
513                         
514                         r = perform_action_1picture_1pixel( //bottom-left
515                                 2, //id
516                                 0, //x0
517                                 height_total - 1, //y0
518                                 0, //f0
519                                 &fill_color, //function
520                                 flags_total | IN_WINDOW | NOT_READABLE, //flags
521                                 &color //data
522                         );
523                         if (r!=0)
524                         {
525                                 *err = CONVERT_FAILED;
526                                 return r;
527                         }
528                 }
529         }
530         
531         /* 4: insert npb before */
532         
533         if (!npb_after)
534         {
535                 id[0] = 1; //npb
536                 id[1] = 2; //total
537                 x0[0] = 0;
538                 x0[1] = x0_npb;
539                 y0[0] = 0;
540                 y0[1] = y0_npb;
541                 flags[0] = flags_npb | IN_WINDOW;
542                 flags[1] = flags_total | IN_WINDOW;
543                 
544                 r = perform_action(
545                         2, //n
546                         id,
547                         x0, y0, f0,
548                         width_npb, height_npb, 1,
549                         &copy_pixels,
550                         flags,
551                         &max //data
552                 );
553                 if (r!=0)
554                 {
555                         *err = CONVERT_FAILED;
556                         return r;
557                 }
558         }
559         
560         /* 5: fill_background */
561         
562         if (fill_white)
563         {
564                 color.red   = max;
565                 color.green = max;
566                 color.blue  = max;
567                 color.alpha = max;
568                 
569                 r = perform_action_1picture(
570                         2, //id
571                         fixed_frame ? space_l : x0_content_global, //x0
572                         fixed_frame ? space_t : y0_content_global, //y0
573                         0, //f0
574                         fixed_frame ? (space_r - space_l + 1) : width_content, //width
575                         fixed_frame ? (space_b - space_t + 1) : height_content, //height
576                         1, //frames
577                         &fill_color, //function
578                         flags_total | IN_WINDOW | NOT_READABLE, //flags
579                         &color //data
580                 );
581                 if (r!=0)
582                 {
583                         *err = CONVERT_FAILED;
584                         return r;
585                 }
586         }
587         
588         /* 6: insert content */
589         
590         id[0] = 0; //content
591         id[1] = 2; //total
592         x0[0] = x0_content_own;
593         x0[1] = x0_content_global;
594         y0[0] = y0_content_own;
595         y0[1] = y0_content_global;
596         flags[0] = flags_content | IN_WINDOW;
597         flags[1] = flags_total | IN_WINDOW;
598         
599         r = perform_action(
600                 2, //n
601                 id,
602                 x0, y0, f0,
603                 width_content, height_content, 1,
604                 &copy_pixels,
605                 flags,
606                 &max //data
607         );
608         if (r!=0)
609         {
610                 *err = CONVERT_FAILED;
611                 return r;
612         }
613         
614         /* 7: draw border */
615         
616         if (new_border >0)
617         {
618                 color.red   = 0;
619                 color.green = 0;
620                 color.blue  = 0;
621                 color.alpha = max;
622                 
623                 r = perform_action_1picture( //top
624                         2, //id
625                         corners ? (x0_border + 1) : x0_border, //x0
626                         y0_border, //y0
627                         0, //f0
628                         corners ? (width_border - 2) : width_border, //width
629                         new_border, //height
630                         1, //frames
631                         &fill_color, //function
632                         flags_total | IN_WINDOW | NOT_READABLE, //flags
633                         &color //data
634                 );
635                 if (r!=0)
636                 {
637                         *err = CONVERT_FAILED;
638                         return r;
639                 }
640                 
641                 r = perform_action_1picture( //bottom
642                         2, //id
643                         corners ? (x0_border + 1) : x0_border, //x0
644                         y0_border + height_border - new_border, //y0
645                         0, //f0
646                         corners ? (width_border - 2) : width_border, //width
647                         new_border, //height
648                         1, //frames
649                         &fill_color, //function
650                         flags_total | IN_WINDOW | NOT_READABLE, //flags
651                         &color //data
652                 );
653                 if (r!=0)
654                 {
655                         *err = CONVERT_FAILED;
656                         return r;
657                 }
658                 
659                 r = perform_action_1picture( //left
660                         2, //id
661                         x0_border, //x0
662                         corners ? (y0_border + 1) : y0_content_global , //y0
663                         0, //f0
664                         new_border, //width
665                         corners ? (height_border - 2) : height_content, //height
666                         1, //frames
667                         &fill_color, //function
668                         flags_total | IN_WINDOW | NOT_READABLE, //flags
669                         &color //data
670                 );
671                 if (r!=0)
672                 {
673                         *err = CONVERT_FAILED;
674                         return r;
675                 }
676                 
677                 r = perform_action_1picture( //right
678                         2, //id
679                         x0_border + width_border - new_border, //x0
680                         corners ? (y0_border + 1) : y0_content_global , //y0
681                         0, //f0
682                         new_border, //width
683                         corners ? (height_border - 2) : height_content, //height
684                         1, //frames
685                         &fill_color, //function
686                         flags_total | IN_WINDOW | NOT_READABLE, //flags
687                         &color //data
688                 );
689                 if (r!=0)
690                 {
691                         *err = CONVERT_FAILED;
692                         return r;
693                 }
694         }
695         
696         /* 8: insert npb after */
697         
698         if (npb_after)
699         {
700                 id[0] = 1; //npb
701                 id[1] = 2; //total
702                 x0[0] = 0;
703                 x0[1] = x0_npb;
704                 y0[0] = 0;
705                 y0[1] = y0_npb;
706                 flags[0] = flags_npb | IN_WINDOW;
707                 flags[1] = flags_total | IN_WINDOW;
708                 
709                 r = perform_action(
710                         2, //n
711                         id,
712                         x0, y0, f0,
713                         width_npb, height_npb, 1,
714                         &copy_pixels,
715                         flags,
716                         &max //data
717                 );
718                 if (r!=0)
719                 {
720                         *err = CONVERT_FAILED;
721                         return r;
722                 }
723         }
724         
725         /* 9: ok, done, now save */
726         
727         r = save_picture(2, argv[optind+1], flags_total);
728         if (r!=0)
729         {
730                 *err = SAVE_FAILED;
731                 return r;
732         }
733         
734         return 0;
735 }