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:ch0";
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;
230 override_new_border = 1;
235 else if ((width_content <= (NPB1_R - NPB1_L + 1)) && (height_content <= (NPB1_B - NPB1_T + 1)) && (!fullsize))
238 npb_size = npb1_size;
244 override_new_border = 1;
252 npb_size = npb2_size;
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;
268 /* load selected npb */
270 r = load_picture_mem(1, npb_pix, npb_size, &(info_npb), &(flags_npb));
277 /* determine rectangle of content with new border */
279 width_border = width_content + new_border * 2;
280 height_border = height_content + new_border * 2;
282 /* npb rectangle too */
284 width_npb = info_npb.image_width;
285 height_npb = info_npb.image_height;
289 /* initial total size, to update later */
291 width_total = width_npb;
292 height_total = height_npb;
294 /* determine content border placement in full picture */
296 if (expand_right && (width_border >= (space_r - space_l +1)))
298 else if (expand_left && (width_border >= (space_r - space_l +1)))
299 x0_border = space_r - width_border + 1;
301 x0_border = (space_l + space_r + 1 - width_border) / 2;
303 if (expand_down && (height_border >= (space_b - space_t +1)))
305 else if (expand_up && (height_border >= (space_b - space_t +1)))
306 y0_border = space_b - height_border + 1;
308 y0_border = (space_t + space_b + 1 - height_border) / 2;
310 /* determine content placement in border in full picture */
312 x0_content_global = x0_border + new_border;
313 y0_content_global = y0_border + new_border;
315 /* adjust full picture size & offsets if content doesn't fit */
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;
323 width_total -= x0_border;
325 x0_content_global -= x0_border;
330 height_total -= y0_border;
332 y0_content_global -= y0_border;
336 /* adjust for external border */
338 if (external_border > 0)
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;
350 /* ok setup done, now perform actions */
352 /* 1: create target picture */
354 r = build_picture(2, width_total, height_total, 1, &info_total, &flags_total);
361 /* 2: init background */
366 color.alpha = fill_white_all ? max : 0;
368 r = perform_action_1picture(
370 external_border, //x0
371 external_border, //y0
373 (width_total - 2 * external_border), //width
374 (height_total - 2 * external_border), //height
376 &fill_color, //function
377 flags_total | IN_WINDOW | NOT_READABLE, //flags
382 *err = CONVERT_FAILED;
386 /* 3: draw border outside */
388 if (external_border >0)
395 r = perform_action_1picture( //top
401 external_border, //height
403 &fill_color, //function
404 flags_total | IN_WINDOW | NOT_READABLE, //flags
409 *err = CONVERT_FAILED;
413 r = perform_action_1picture( //bottom
416 height_total - external_border, //y0
419 external_border, //height
421 &fill_color, //function
422 flags_total | IN_WINDOW | NOT_READABLE, //flags
427 *err = CONVERT_FAILED;
431 r = perform_action_1picture( //left
434 external_border, //y0
436 external_border, //width
437 height_total - 2*external_border, //height
439 &fill_color, //function
440 flags_total | IN_WINDOW | NOT_READABLE, //flags
445 *err = CONVERT_FAILED;
449 r = perform_action_1picture( //right
451 width_total - external_border, //x0
452 external_border, //y0
454 external_border, //width
455 height_total - 2*external_border, //height
457 &fill_color, //function
458 flags_total | IN_WINDOW | NOT_READABLE, //flags
463 *err = CONVERT_FAILED;
471 r = perform_action_1picture_1pixel( //top-left
476 &fill_color, //function
477 flags_total | IN_WINDOW | NOT_READABLE, //flags
482 *err = CONVERT_FAILED;
486 r = perform_action_1picture_1pixel( //top-right
488 width_total - 1, //x0
491 &fill_color, //function
492 flags_total | IN_WINDOW | NOT_READABLE, //flags
497 *err = CONVERT_FAILED;
501 r = perform_action_1picture_1pixel( //bottom-right
503 width_total - 1, //x0
504 height_total - 1, //y0
506 &fill_color, //function
507 flags_total | IN_WINDOW | NOT_READABLE, //flags
512 *err = CONVERT_FAILED;
516 r = perform_action_1picture_1pixel( //bottom-left
519 height_total - 1, //y0
521 &fill_color, //function
522 flags_total | IN_WINDOW | NOT_READABLE, //flags
527 *err = CONVERT_FAILED;
533 /* 4: insert npb before */
543 flags[0] = flags_npb | IN_WINDOW;
544 flags[1] = flags_total | IN_WINDOW;
550 width_npb, height_npb, 1,
557 *err = CONVERT_FAILED;
562 /* 5: fill_background */
571 r = perform_action_1picture(
573 fixed_frame ? space_l + external_border : x0_content_global, //x0
574 fixed_frame ? space_t + external_border: y0_content_global, //y0
576 fixed_frame ? (space_r - space_l + 1) : width_content, //width
577 fixed_frame ? (space_b - space_t + 1) : height_content, //height
579 &fill_color, //function
580 flags_total | IN_WINDOW | NOT_READABLE, //flags
585 *err = CONVERT_FAILED;
590 /* 6: insert content */
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;
605 width_content, height_content, 1,
612 *err = CONVERT_FAILED;
625 r = perform_action_1picture( //top
627 corners ? (x0_border + 1) : x0_border, //x0
630 corners ? (width_border - 2) : width_border, //width
633 &fill_color, //function
634 flags_total | IN_WINDOW | NOT_READABLE, //flags
639 *err = CONVERT_FAILED;
643 r = perform_action_1picture( //bottom
645 corners ? (x0_border + 1) : x0_border, //x0
646 y0_border + height_border - new_border, //y0
648 corners ? (width_border - 2) : width_border, //width
651 &fill_color, //function
652 flags_total | IN_WINDOW | NOT_READABLE, //flags
657 *err = CONVERT_FAILED;
661 r = perform_action_1picture( //left
664 corners ? (y0_border + 1) : y0_content_global , //y0
667 corners ? (height_border - 2) : height_content, //height
669 &fill_color, //function
670 flags_total | IN_WINDOW | NOT_READABLE, //flags
675 *err = CONVERT_FAILED;
679 r = perform_action_1picture( //right
681 x0_border + width_border - new_border, //x0
682 corners ? (y0_border + 1) : y0_content_global , //y0
685 corners ? (height_border - 2) : height_content, //height
687 &fill_color, //function
688 flags_total | IN_WINDOW | NOT_READABLE, //flags
693 *err = CONVERT_FAILED;
698 /* 8: insert npb after */
708 flags[0] = flags_npb | IN_WINDOW;
709 flags[1] = flags_total | IN_WINDOW;
715 width_npb, height_npb, 1,
722 *err = CONVERT_FAILED;
727 /* 9: ok, done, now save */
729 r = save_picture(2, argv[optind+1], flags_total);