3 Take a picture and add a newpixbot to it!
6 Copyright (C) 2013 - 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)
57 #define NPB_ONG1_L -74
58 #define NPB_ONG1_R 102
68 char NPB_MISSING_ARGS[] = "Missing parameters.\nnpb [-o -4 -r -b -e -c] inPix outPix\n";
70 int subtool_npb (int argc, char **argv, int argi, char **err)
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;
87 ILuint cut_border = 0;
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;
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;
113 ILint f0[2] = {0, 0};
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'},
125 char short_options[] = "o4r:b:e:ch";
130 /* we get options first */
133 while ((opt = getopt_long(argc, argv, short_options, long_options, NULL)) != -1)
144 sscanf(optarg, "%u", &cut_border);
147 sscanf(optarg, "%u", &new_border);
149 override_new_border = 1;
152 sscanf(optarg, "%u", &external_border);
153 override_external_border = 1;
164 if (argc < optind + 2)
166 *err = NPB_MISSING_ARGS;
170 r = reserve_pictures(3);
173 *err = CREATE_FAILED;
177 /* load content to insert to npb */
179 r = load_picture(0, argv[optind], &(info_content), &(flags_content));
186 /* determine actually used rectangle without border */
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;
193 /* select npb mode */
198 npb_size = npb_403_size;
205 new_border_default = 0;
206 external_border_default = 2;
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;
221 else if ((width_content <= (NPB0_R - NPB0_L + 1)) && (height_content <= (NPB0_B - NPB0_T + 1)) && (!fullsize))
224 npb_size = npb0_size;
234 else if ((width_content <= (NPB1_R - NPB1_L + 1)) && (height_content <= (NPB1_B - NPB1_T + 1)) && (!fullsize))
237 npb_size = npb1_size;
250 npb_size = npb2_size;
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;
266 /* load selected npb */
268 r = load_picture_mem(1, npb_pix, npb_size, &(info_npb), &(flags_npb));
275 /* determine rectangle of content with new border */
277 width_border = width_content + new_border * 2;
278 height_border = height_content + new_border * 2;
280 /* npb rectangle too */
282 width_npb = info_npb.image_width;
283 height_npb = info_npb.image_height;
287 /* initial total size, to update later */
289 width_total = width_npb;
290 height_total = height_npb;
292 /* determine content border placement in full picture */
294 if (expand_right && (width_border >= (space_r - space_l +1)))
296 else if (expand_left && (width_border >= (space_r - space_l +1)))
297 x0_border = space_r - width_border + 1;
299 x0_border = (space_l + space_r + 1 - width_border) / 2;
301 if (expand_down && (height_border >= (space_b - space_t +1)))
303 else if (expand_up && (height_border >= (space_b - space_t +1)))
304 y0_border = space_b - height_border + 1;
306 y0_border = (space_t + space_b + 1 - height_border) / 2;
308 /* determine content placement in border in full picture */
310 x0_content_global = x0_border + new_border;
311 y0_content_global = y0_border + new_border;
313 /* adjust full picture size & offsets if content doesn't fit */
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;
321 width_total -= x0_border;
323 x0_content_global -= x0_border;
328 height_total -= y0_border;
330 y0_content_global -= y0_border;
334 /* adjust for external border */
336 if (external_border > 0)
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;
348 /* ok setup done, now perform actions */
350 /* 1: create target picture */
352 r = build_picture(2, width_total, height_total, 1, &info_total, &flags_total);
359 /* 2: init background */
364 color.alpha = fill_white_all ? max : 0;
366 r = perform_action_1picture(
368 external_border, //x0
369 external_border, //y0
371 (width_total - 2 * external_border), //width
372 (height_total - 2 * external_border), //height
374 &fill_color, //function
375 flags_total | IN_WINDOW | NOT_READABLE, //flags
380 *err = CONVERT_FAILED;
384 /* 3: draw border outside */
386 if (external_border >0)
393 r = perform_action_1picture( //top
399 external_border, //height
401 &fill_color, //function
402 flags_total | IN_WINDOW | NOT_READABLE, //flags
407 *err = CONVERT_FAILED;
411 r = perform_action_1picture( //bottom
414 height_total - external_border, //y0
417 external_border, //height
419 &fill_color, //function
420 flags_total | IN_WINDOW | NOT_READABLE, //flags
425 *err = CONVERT_FAILED;
429 r = perform_action_1picture( //left
432 external_border, //y0
434 external_border, //width
435 height_total - 2*external_border, //height
437 &fill_color, //function
438 flags_total | IN_WINDOW | NOT_READABLE, //flags
443 *err = CONVERT_FAILED;
447 r = perform_action_1picture( //right
449 width_total - external_border, //x0
450 external_border, //y0
452 external_border, //width
453 height_total - 2*external_border, //height
455 &fill_color, //function
456 flags_total | IN_WINDOW | NOT_READABLE, //flags
461 *err = CONVERT_FAILED;
469 r = perform_action_1picture_1pixel( //top-left
474 &fill_color, //function
475 flags_total | IN_WINDOW | NOT_READABLE, //flags
480 *err = CONVERT_FAILED;
484 r = perform_action_1picture_1pixel( //top-right
486 width_total - 1, //x0
489 &fill_color, //function
490 flags_total | IN_WINDOW | NOT_READABLE, //flags
495 *err = CONVERT_FAILED;
499 r = perform_action_1picture_1pixel( //bottom-right
501 width_total - 1, //x0
502 height_total - 1, //y0
504 &fill_color, //function
505 flags_total | IN_WINDOW | NOT_READABLE, //flags
510 *err = CONVERT_FAILED;
514 r = perform_action_1picture_1pixel( //bottom-left
517 height_total - 1, //y0
519 &fill_color, //function
520 flags_total | IN_WINDOW | NOT_READABLE, //flags
525 *err = CONVERT_FAILED;
531 /* 4: insert npb before */
541 flags[0] = flags_npb | IN_WINDOW;
542 flags[1] = flags_total | IN_WINDOW;
548 width_npb, height_npb, 1,
555 *err = CONVERT_FAILED;
560 /* 5: fill_background */
569 r = perform_action_1picture(
571 fixed_frame ? space_l : x0_content_global, //x0
572 fixed_frame ? space_t : y0_content_global, //y0
574 fixed_frame ? (space_r - space_l + 1) : width_content, //width
575 fixed_frame ? (space_b - space_t + 1) : height_content, //height
577 &fill_color, //function
578 flags_total | IN_WINDOW | NOT_READABLE, //flags
583 *err = CONVERT_FAILED;
588 /* 6: insert content */
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;
603 width_content, height_content, 1,
610 *err = CONVERT_FAILED;
623 r = perform_action_1picture( //top
625 corners ? (x0_border + 1) : x0_border, //x0
628 corners ? (width_border - 2) : width_border, //width
631 &fill_color, //function
632 flags_total | IN_WINDOW | NOT_READABLE, //flags
637 *err = CONVERT_FAILED;
641 r = perform_action_1picture( //bottom
643 corners ? (x0_border + 1) : x0_border, //x0
644 y0_border + height_border - new_border, //y0
646 corners ? (width_border - 2) : width_border, //width
649 &fill_color, //function
650 flags_total | IN_WINDOW | NOT_READABLE, //flags
655 *err = CONVERT_FAILED;
659 r = perform_action_1picture( //left
662 corners ? (y0_border + 1) : y0_content_global , //y0
665 corners ? (height_border - 2) : height_content, //height
667 &fill_color, //function
668 flags_total | IN_WINDOW | NOT_READABLE, //flags
673 *err = CONVERT_FAILED;
677 r = perform_action_1picture( //right
679 x0_border + width_border - new_border, //x0
680 corners ? (y0_border + 1) : y0_content_global , //y0
683 corners ? (height_border - 2) : height_content, //height
685 &fill_color, //function
686 flags_total | IN_WINDOW | NOT_READABLE, //flags
691 *err = CONVERT_FAILED;
696 /* 8: insert npb after */
706 flags[0] = flags_npb | IN_WINDOW;
707 flags[1] = flags_total | IN_WINDOW;
713 width_npb, height_npb, 1,
720 *err = CONVERT_FAILED;
725 /* 9: ok, done, now save */
727 r = save_picture(2, argv[optind+1], flags_total);