3 The tool with multiple enhancements and manipulations of pictures
6 Copyright (C) 2014, 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)
36 uint_fast16_t n_pictures = 0;
37 struct Picture * picture;
39 char INIT_FAILED[] = "Failed to set up library.\n";
40 char LOAD_FAILED[] = "Failed to load picture.\n";
41 char SAVE_FAILED[] = "Failed to save picture.\n";
42 char CREATE_FAILED[] = "Failed to create picture(s).\n";
43 char CONVERT_FAILED[] = "Failed to convert picture.\n";
44 char SIZE_MISMATCH[] = "Pictures have different sizes.\n";
45 char MULTIPLE_FORBIDDEN[] = "Picture is not allowed to have multiple frames.\n";
46 char INDEXED_REQUIRED[] = "Picture must be indexed.\n";
47 char PALETTE_ONLY_REQUIRED[]= "Palette-only operation must be allowed.\n";
48 char BAD_PALETTE_SIZE[] = "Palette has wrong number of colours.\n";
54 if (!ilEnable(IL_FILE_OVERWRITE))
56 // if(!ilEnable(IL_ORIGIN_SET))
58 // if(!ilOriginFunc(IL_ORIGIN_UPPER_LEFT))
63 void finish (int const returnvalue, char const * const returntext)
66 fputs(returntext, stderr);
70 ILuint get_handle (uint_fast16_t id)
73 return picture[id].handle;
74 else /* invalid but must return something */
78 int get_data (uint_fast16_t id, void **data, ILuint frame)
82 if (!(picture[id].open))
84 ilBindImage(picture[id].handle);
85 if (frame > ilGetInteger(IL_NUM_IMAGES))
92 int get_palette (uint_fast16_t id, void *palette, ILuint frame)
96 if (!(picture[id].open))
98 ilBindImage(picture[id].handle);
99 if (frame > ilGetInteger(IL_NUM_IMAGES))
101 ilActiveImage(frame);
102 if (ilGetInteger(IL_IMAGE_FORMAT) != IL_COLOUR_INDEX)
104 *((void **)palette) = ilGetPalette();
108 int set_palette (uint_fast16_t id, void *palette, ILuint size, ILenum type, ILuint frame)
110 if (id >= n_pictures)
112 if (!(picture[id].open))
114 ilBindImage(picture[id].handle);
115 if (frame > ilGetInteger(IL_NUM_IMAGES))
117 ilActiveImage(frame);
118 if (ilGetInteger(IL_IMAGE_FORMAT) != IL_COLOUR_INDEX)
120 ilRegisterPal(palette, size, type);
124 void create_picture (uint_fast16_t id)
128 if (picture[id].open)
130 ilGenImages(1, &(picture[id].handle));
131 picture[id].open = 1;
135 int create_pictures (uint_fast16_t n)
140 r = reserve_pictures(n);
143 for (i=0; i<n_pictures; ++i)
148 void close_picture (uint_fast16_t id)
152 if (picture[id].open)
154 ilDeleteImages(1, &(picture[id].handle));
160 void close_pictures (void)
163 for (i=0; i<n_pictures; ++i)
167 void clear_pictures (void)
175 int reserve_pictures (uint_fast16_t n)
184 picture = malloc((sizeof (struct Picture)) * n);
189 perror("reserve_pictures(): malloc():");
193 for(i=0; i<n_pictures; ++i)
202 void get_flags (struct IL_full_info *info, FLAG_TYPE *flags)
204 *flags &= ~(HAS_ALPHA | IS_GRAY | IS_INDEXED | IS_MULTIPLE | IS_OVER_8BIT | EFF_ALPHA | EFF_GRAY | EFF_INDEXED);
206 if (info->num_images > 0)
207 *flags |= IS_MULTIPLE;
209 if (info->image_bpc > 1)
210 *flags |= IS_OVER_8BIT;
212 switch (info->image_format)
214 case IL_COLOUR_INDEX:
215 *flags |= IS_INDEXED | EFF_INDEXED;
216 switch (info->palette_type)
220 *flags |= IS_OVER_8BIT;
224 *flags |= HAS_ALPHA | EFF_ALPHA;
232 case IL_LUMINANCE_ALPHA:
233 *flags |= HAS_ALPHA | EFF_ALPHA;
235 *flags |= IS_GRAY | EFF_GRAY;
239 *flags |= HAS_ALPHA | EFF_ALPHA;
247 int convert_picture (uint_fast16_t id, struct IL_full_info *info, FLAG_TYPE *flags)
249 ILint current_format;
253 ILint current_palette_type;
254 ILint final_palette_type;
255 struct IL_full_info info_c;
258 if (id >= n_pictures)
261 if (!(picture[id].open))
264 r = get_info (id, &info_c, 0);
268 ilBindImage(picture[id].handle);
269 current_format = info_c.image_format;
270 final_format = current_format;
271 current_type = info_c.image_type;
272 final_type = current_type;
274 if (!(*flags & CAN_BE_MULTIPLE))
276 if (ilGetInteger(IL_NUM_IMAGES) > 0)
278 fputs(MULTIPLE_FORBIDDEN, stderr);
283 if (final_format == IL_COLOUR_INDEX)
285 current_palette_type = info_c.palette_type;
286 final_palette_type = current_palette_type;
288 if (*flags & (CANNOT_BE_INDEXED | MUST_BE_GRAY))
290 switch (final_palette_type)
293 final_format = IL_BGR;
294 final_type = IL_UNSIGNED_BYTE;
297 final_format = IL_BGR;
298 final_type = IL_UNSIGNED_SHORT;
301 final_format = IL_BGRA;
302 final_type = IL_UNSIGNED_BYTE;
305 final_format = IL_RGBA;
306 final_type = IL_UNSIGNED_BYTE;
309 final_format = IL_RGB;
310 final_type = IL_UNSIGNED_SHORT;
314 final_format = IL_RGB;
315 final_type = IL_UNSIGNED_BYTE;
321 if (!(*flags & CAN_BE_OVER_8BIT))
323 switch (final_palette_type)
326 final_palette_type = IL_PAL_BGR24;
329 final_palette_type = IL_PAL_RGB24;
336 if (*flags & MUST_HAVE_ALPHA)
338 switch (final_palette_type)
342 final_palette_type = IL_PAL_BGRA32;
346 final_palette_type = IL_PAL_RGBA32;
352 else if (*flags & CANNOT_HAVE_ALPHA)
354 switch (final_palette_type)
357 final_palette_type = IL_PAL_BGR24;
360 final_palette_type = IL_PAL_RGB24;
367 if (final_palette_type != current_palette_type)
369 fputs("Palette was converted!\n", stderr);
370 if (!(ilConvertPal(final_palette_type)))
372 fputs("Palette conversion failed.\n", stderr);
379 if (final_format != IL_COLOUR_INDEX) /* might have changed */
381 if (*flags & MUST_BE_INDEXED)
383 fputs(INDEXED_REQUIRED, stderr);
387 if (*flags & MUST_HAVE_ALPHA)
389 switch (final_format)
392 final_format = IL_RGBA;
395 final_format = IL_BGRA;
398 final_format = IL_LUMINANCE_ALPHA;
404 else if (*flags & CANNOT_HAVE_ALPHA)
406 switch (final_format)
409 final_format = IL_RGB;
412 final_format = IL_BGR;
414 case IL_LUMINANCE_ALPHA:
415 final_format = IL_LUMINANCE;
422 if (*flags & MUST_BE_GRAY)
424 switch (final_format)
428 final_format = IL_LUMINANCE;
432 final_format = IL_LUMINANCE_ALPHA;
438 else if (*flags & CANNOT_BE_GRAY)
440 switch (final_format)
443 final_format = IL_RGB;
445 case IL_LUMINANCE_ALPHA:
446 final_format = IL_RGBA;
453 if (*flags & CAN_BE_OVER_8BIT)
458 final_type = IL_UNSIGNED_BYTE;
461 final_type = IL_UNSIGNED_SHORT;
466 final_type = IL_UNSIGNED_INT;
473 final_type = IL_UNSIGNED_BYTE;
475 if ((final_type != current_type) || (final_format != current_format))
477 fputs("Picture is converted!\n", stderr);
478 if (!(ilConvertImage(final_format, final_type)))
480 fputs("Image format conversion failed.\n", stderr);
487 r = get_info (id, &info_c, 0);
490 get_flags(&info_c, flags);
494 r = get_info (id, info, 0);
497 get_flags(info, flags);
502 int load_picture (uint_fast16_t id, char *path, struct IL_full_info *info, FLAG_TYPE *flags)
504 if (id >= n_pictures)
507 // if(!(picture[id].open))
510 ilBindImage(picture[id].handle);
511 if (!ilLoadImage(path))
514 return convert_picture(id, info, flags);
517 int load_picture_mem (uint_fast16_t id, const void *address, ILuint size, struct IL_full_info *info, FLAG_TYPE *flags)
519 if (id >= n_pictures)
522 // if(!(picture[id].open))
525 ilBindImage(picture[id].handle);
526 if (!ilLoadL(IL_TYPE_UNKNOWN, address, size))
529 return convert_picture(id, info, flags);
532 int build_picture (uint_fast16_t id, ILint width, ILint height, ILint frames, struct IL_full_info *info, FLAG_TYPE *flags)
534 struct IL_full_info reference_info;
536 reference_info.image_width = width;
537 reference_info.image_height = height;
538 if (*flags & CAN_BE_MULTIPLE)
539 reference_info.num_images = frames-1;
541 reference_info.num_images = 0;
543 if (*flags & MUST_BE_INDEXED)
545 reference_info.image_format = IL_COLOUR_INDEX;
546 reference_info.image_type = IL_UNSIGNED_BYTE;
547 reference_info.image_channels = 1;
551 if (*flags & MUST_BE_GRAY)
553 if (*flags & MUST_HAVE_ALPHA)
555 reference_info.image_format = IL_LUMINANCE_ALPHA;
556 reference_info.image_channels = 2;
560 reference_info.image_format = IL_LUMINANCE;
561 reference_info.image_channels = 1;
566 if (*flags & MUST_HAVE_ALPHA)
568 reference_info.image_format = IL_RGBA;
569 reference_info.image_channels = 4;
573 reference_info.image_format = IL_RGB;
574 reference_info.image_channels = 3;
577 if (*flags & CAN_BE_OVER_8BIT)
578 reference_info.image_type = IL_UNSIGNED_SHORT;
580 reference_info.image_type = IL_UNSIGNED_BYTE;
582 return build_picture_from_info(id, &reference_info, info, flags);
585 int build_picture_from_info (uint_fast16_t id, struct IL_full_info *reference_info, struct IL_full_info *info, FLAG_TYPE *flags)
589 if (id >= n_pictures)
592 // if(!(picture[id].open))
595 ilBindImage(picture[id].handle);
596 if (reference_info->num_images > 0)
598 if (!ilCreateSubImage(IL_SUB_NEXT, reference_info->num_images))
602 for (i=0; i<=reference_info->num_images; ++i)
604 ilBindImage(picture[id].handle);
607 reference_info->image_width,
608 reference_info->image_height,
610 reference_info->image_channels,
611 reference_info->image_format,
612 reference_info->image_type,
618 return convert_picture (id, info, flags);
621 int save_picture (uint_fast16_t id, char *path, FLAG_TYPE flags)
625 if (id >= n_pictures)
628 ilBindImage(picture[id].handle);
629 r = convert_picture(id, NULL, &flags);
633 if (!ilSaveImage(path))
638 int get_info (uint_fast16_t id, struct IL_full_info *info, ILint frame)
644 ilBindImage(picture[id].handle);
645 if (frame <= ilGetInteger(IL_NUM_IMAGES))
647 if(!ilActiveImage(frame))
652 info->active_image = ilGetInteger(IL_ACTIVE_IMAGE);
653 info->active_layer = ilGetInteger(IL_ACTIVE_LAYER);
654 info->active_mipmap = ilGetInteger(IL_ACTIVE_MIPMAP);
655 info->blit_blend = ilGetInteger(IL_BLIT_BLEND);
656 info->compress_mode = ilGetInteger(IL_COMPRESS_MODE);
657 info->conv_pal = ilGetInteger(IL_CONV_PAL);
658 info->cur_image = ilGetInteger(IL_CUR_IMAGE);
659 info->default_on_fail = ilGetInteger(IL_DEFAULT_ON_FAIL);
660 info->dxtc_data_format = ilGetInteger(IL_DXTC_DATA_FORMAT);
661 info->file_mode = ilGetInteger(IL_FILE_MODE);
662 info->format_mode = ilGetInteger(IL_FORMAT_MODE);
663 info->format_set = ilGetInteger(IL_FORMAT_SET);
664 info->image_bits_per_pixel = ilGetInteger(IL_IMAGE_BITS_PER_PIXEL);
665 info->image_bpc = ilGetInteger(IL_IMAGE_BPC);
666 info->image_bytes_per_pixel = ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL);
667 info->image_channels = ilGetInteger(IL_IMAGE_CHANNELS);
668 info->image_cubeflags = ilGetInteger(IL_IMAGE_CUBEFLAGS);
669 info->image_depth = ilGetInteger(IL_IMAGE_DEPTH);
670 info->image_duration = ilGetInteger(IL_IMAGE_DURATION);
671 info->image_format = ilGetInteger(IL_IMAGE_FORMAT);
672 info->image_height = ilGetInteger(IL_IMAGE_HEIGHT);
673 info->image_offx = ilGetInteger(IL_IMAGE_OFFX);
674 info->image_offy = ilGetInteger(IL_IMAGE_OFFY);
675 info->image_origin = ilGetInteger(IL_IMAGE_ORIGIN);
676 info->image_planesize = ilGetInteger(IL_IMAGE_PLANESIZE);
677 info->image_size_of_data = ilGetInteger(IL_IMAGE_SIZE_OF_DATA);
678 info->image_type = ilGetInteger(IL_IMAGE_TYPE);
679 info->image_width = ilGetInteger(IL_IMAGE_WIDTH);
680 info->keep_dxtc_data = ilGetInteger(IL_KEEP_DXTC_DATA);
681 info->num_faces = ilGetInteger(IL_NUM_FACES);
682 info->num_images = ilGetInteger(IL_NUM_IMAGES);
683 info->num_layers = ilGetInteger(IL_NUM_LAYERS);
684 info->num_mipmaps = ilGetInteger(IL_NUM_MIPMAPS);
685 info->origin_mode = ilGetInteger(IL_ORIGIN_MODE);
686 info->origin_set = ilGetInteger(IL_ORIGIN_SET);
687 info->palette_base_type = ilGetInteger(IL_PALETTE_BASE_TYPE);
688 info->palette_bpp = ilGetInteger(IL_PALETTE_BPP);
689 info->palette_num_cols = ilGetInteger(IL_PALETTE_NUM_COLS);
690 info->palette_type = ilGetInteger(IL_PALETTE_TYPE);
691 info->type_mode = ilGetInteger(IL_TYPE_MODE);
692 info->type_set = ilGetInteger(IL_TYPE_SET);
693 info->use_key_colour = ilGetInteger(IL_USE_KEY_COLOUR);
694 info->version_num = ilGetInteger(IL_VERSION_NUM);
700 int perform_action_1picture (
702 ILint x0, ILint y0, ILint f0,
703 ILint width, ILint height, ILint frames,
709 return perform_action(
713 width, height, frames,
720 int perform_action_1picture_1pixel (
722 ILint x, ILint y, ILint f,
728 return perform_action_1picture (
741 ILint *x0, ILint *y0, ILint *f0,
742 ILint width, ILint height, ILint frames,
749 uint_fast8_t palette_only = 1;
750 uint_fast8_t skip_frame;
751 uint_fast8_t skip_line;
752 uint_fast8_t skip_pixel;
753 ILint actual_frames = 0x7FFFFFFF;
754 ILint actual_width = 0x7FFFFFFF;
755 ILint actual_height = 0x7FFFFFFF;
756 ILint actual_colours= 0x7FFFFFFF;
764 p = malloc((sizeof (struct PixelInfo)) * n);
767 perror("perform_action(): malloc():");
774 p[i].handle = get_handle(p[i].id);
775 p[i].flags = flags[i] & ~(IS_MULTIPLE);
777 if (p[i].id >= n_pictures)
782 if (!(picture[p[i].id].open))
788 r = get_info(p[i].id, &(p[i].info), 0);
791 p[i].frames = p[i].info.num_images + 1;
794 p[i].flags |= IS_MULTIPLE;
795 if (p[i].flags & CAN_BE_MULTIPLE)
797 if (p[i].frames < actual_frames)
798 actual_frames = p[i].frames;
803 if (p[i].info.image_width < actual_width)
804 actual_width = p[i].info.image_width;
805 if (p[i].info.image_height < actual_height)
806 actual_height = p[i].info.image_height;
808 if (*flags & IN_WINDOW) /* check first flags only! */
821 if ((p[i].info.image_format != IL_COLOUR_INDEX) || (!(p[i].flags & OK_PALETTE_ONLY)))
825 if (!(*flags & IN_WINDOW)) /* check first flags only! */
827 width = actual_width;
828 height = actual_height;
829 frames = actual_frames;
832 for (f = 0; (f < frames) && (r == 0); ++f)
838 p[i].f_pict = p[i].f0 + f;
839 if ((p[i].f_pict < 0) || (p[i].f_pict >= p[i].frames))
845 r = get_info(p[i].id, &(p[i].info), p[i].f_pict);
849 r = get_data(p[i].id, &(p[i].data), p[i].f_pict);
853 p[i].flags &= ~(HAS_ALPHA|IS_GRAY|IS_INDEXED|IS_OVER_8BIT|IS_PALETTE_ONLY|EFF_ALPHA|EFF_GRAY|EFF_INDEXED);
855 p[i].flags |= IS_PALETTE_ONLY;
857 p[i].alpha_offset = 0;
858 p[i].value_offset = 0;
859 p[i].index_offset = 0;
861 p[i].green_offset = 0;
862 p[i].blue_offset = 0;
866 if (p[i].info.palette_num_cols < actual_colours)
867 actual_colours = p[i].info.palette_num_cols;
870 switch (p[i].info.image_format)
872 case IL_COLOUR_INDEX:
873 p[i].flags |= IS_INDEXED | EFF_INDEXED;
874 r = get_palette(p[i].id, &(p[i].palette), p[i].f_pict);
877 switch (p[i].info.palette_type)
881 p[i].flags |= IS_OVER_8BIT;
884 p[i].flags |= HAS_ALPHA | EFF_ALPHA;
885 p[i].alpha_offset = 3;
888 p[i].green_offset = 1;
889 p[i].blue_offset = 0;
892 p[i].flags |= HAS_ALPHA | EFF_ALPHA;
893 p[i].alpha_offset = 3;
897 p[i].green_offset = 1;
898 p[i].blue_offset = 2;
902 case IL_LUMINANCE_ALPHA:
903 p[i].flags |= HAS_ALPHA | EFF_ALPHA;
904 p[i].alpha_offset = 1 * p[i].info.image_bpc;
906 p[i].flags |= IS_GRAY | EFF_GRAY;
907 p[i].value_offset = 0 * p[i].info.image_bpc;
910 p[i].flags |= HAS_ALPHA | EFF_ALPHA;
911 p[i].alpha_offset = 3 * p[i].info.image_bpc;
913 p[i].red_offset = 2 * p[i].info.image_bpc;
914 p[i].green_offset = 1 * p[i].info.image_bpc;
915 p[i].blue_offset = 0 * p[i].info.image_bpc;
918 p[i].flags |= HAS_ALPHA | EFF_ALPHA;
919 p[i].alpha_offset = 3 * p[i].info.image_bpc;
922 p[i].red_offset = 0 * p[i].info.image_bpc;
923 p[i].green_offset = 1 * p[i].info.image_bpc;
924 p[i].blue_offset = 2 * p[i].info.image_bpc;
927 if (p[i].info.image_bpc > 1)
928 p[i].flags |= IS_OVER_8BIT;
930 if ((p[i].flags & IS_INDEXED) && (p[i].flags & CANNOT_BE_INDEXED))
931 p[i].flags &= ~EFF_INDEXED;
932 if ((p[i].flags & IS_GRAY) && (p[i].flags & CANNOT_BE_GRAY))
933 p[i].flags &= ~EFF_GRAY;
934 else if (!(p[i].flags & IS_GRAY) && (p[i].flags & MUST_BE_GRAY))
935 p[i].flags |= EFF_GRAY;
936 if ((!(p[i].flags & HAS_ALPHA)) && (p[i].flags & MUST_HAVE_ALPHA))
937 p[i].flags |= EFF_ALPHA;
938 else if ((p[i].flags & HAS_ALPHA) && (p[i].flags & CANNOT_HAVE_ALPHA))
939 p[i].flags &= ~EFF_ALPHA;
949 flags[i] |= IS_PALETTE_ONLY;
951 for (j=0; (j<actual_colours) && (r==0); ++j)
955 if (!(p[i].flags & NOT_READABLE))
957 p[i].red = (ILuint)(*((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].red_offset)));
958 p[i].green = (ILuint)(*((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].green_offset)));
959 p[i].blue = (ILuint)(*((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].blue_offset)));
960 if (p[i].flags & HAS_ALPHA)
962 if (p[i].flags & CANNOT_HAVE_ALPHA)
965 p[i].alpha = (ILuint)(*((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].alpha_offset)));
967 else if (p[i].flags & MUST_HAVE_ALPHA)
969 if (p[i].flags & MUST_BE_GRAY)
970 p[i].value = (p[i].red + p[i].green + p[i].blue) / 3;
974 r = function(n, p, data);
980 if (!(p[i].flags & NOT_WRITABLE))
982 if (p[i].flags & MUST_BE_GRAY)
984 p[i].red = p[i].value;
985 p[i].green = p[i].value;
986 p[i].blue = p[i].value;
988 if (p[i].flags & HAS_ALPHA)
990 if (p[i].flags & CANNOT_HAVE_ALPHA)
992 *((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].alpha_offset)) = (ILubyte)(p[i].alpha);
994 *((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].red_offset)) = (ILubyte)(p[i].red);
995 *((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].green_offset)) = (ILubyte)(p[i].green);
996 *((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].blue_offset)) = (ILubyte)(p[i].blue);
1000 p[i].pal_offset += p[i].info.palette_bpp;
1008 p[i].line_bytes = p[i].info.image_bytes_per_pixel * p[i].info.image_width;
1009 p[i].frame_bytes = p[i].line_bytes * p[i].info.image_height;
1011 if (p[i].info.image_origin == IL_ORIGIN_LOWER_LEFT)
1013 p[i].line_start = p[i].frame_bytes - p[i].line_bytes;
1014 p[i].line_bytes = 0 - p[i].line_bytes;
1017 p[i].line_start = 0;
1020 p[i].y_pict = p[i].y0;
1021 p[i].line_offset = p[i].line_start + (p[i].y_pict * p[i].line_bytes);
1023 for (y=0; (y<height) && (r == 0); ++y)
1028 if ((p[i].y_pict < 0) || (p[i].y_pict >= p[i].info.image_height))
1035 p[i].x_pict = p[i].x0;
1036 p[i].pixel_offset = p[i].line_offset + (p[i].x_pict * p[i].info.image_bytes_per_pixel);
1040 for (x=0; x<width; ++x)
1045 if ((p[i].x_pict < 0) || (p[i].x_pict >= p[i].info.image_width))
1055 if (!(p[i].flags & NOT_READABLE))
1057 /* can this be done better? think about it */
1058 switch (p[i].info.image_type)
1061 case IL_UNSIGNED_INT:
1062 if (p[i].flags & IS_INDEXED)
1063 p[i].index = *((ILuint*)(p[i].data + p[i].pixel_offset + p[i].index_offset));
1066 if (p[i].flags & IS_GRAY)
1067 p[i].value = *((ILuint*)(p[i].data + p[i].pixel_offset + p[i].value_offset));
1070 p[i].red = *((ILuint*)(p[i].data + p[i].pixel_offset + p[i].red_offset));
1071 p[i].green = *((ILuint*)(p[i].data + p[i].pixel_offset + p[i].green_offset));
1072 p[i].blue = *((ILuint*)(p[i].data + p[i].pixel_offset + p[i].blue_offset));
1074 if (p[i].flags & HAS_ALPHA)
1075 p[i].alpha = *((ILuint*)(p[i].data + p[i].pixel_offset + p[i].alpha_offset));
1079 case IL_UNSIGNED_SHORT:
1080 if (p[i].flags & IS_INDEXED)
1081 p[i].index = (ILuint)(*((ILushort*)(p[i].data + p[i].pixel_offset + p[i].index_offset)));
1084 if(p[i].flags & IS_GRAY)
1085 p[i].value = (ILuint)(*((ILushort*)(p[i].data + p[i].pixel_offset + p[i].value_offset)));
1088 p[i].red = (ILuint)(*((ILushort*)(p[i].data + p[i].pixel_offset + p[i].red_offset)));
1089 p[i].green = (ILuint)(*((ILushort*)(p[i].data + p[i].pixel_offset + p[i].green_offset)));
1090 p[i].blue = (ILuint)(*((ILushort*)(p[i].data + p[i].pixel_offset + p[i].blue_offset)));
1092 if(p[i].flags & HAS_ALPHA)
1093 p[i].alpha = (ILuint)(*((ILushort*)(p[i].data + p[i].pixel_offset + p[i].alpha_offset)));
1097 case IL_UNSIGNED_BYTE:
1098 if(p[i].flags & IS_INDEXED)
1099 p[i].index = (ILuint)(*((ILubyte*)(p[i].data + p[i].pixel_offset + p[i].index_offset)));
1102 if(p[i].flags & IS_GRAY)
1103 p[i].value = (ILuint)(*((ILubyte*)(p[i].data + p[i].pixel_offset + p[i].value_offset)));
1106 p[i].red = (ILuint)(*((ILubyte*)(p[i].data + p[i].pixel_offset + p[i].red_offset)));
1107 p[i].green = (ILuint)(*((ILubyte*)(p[i].data + p[i].pixel_offset + p[i].green_offset)));
1108 p[i].blue = (ILuint)(*((ILubyte*)(p[i].data + p[i].pixel_offset + p[i].blue_offset)));
1110 if(p[i].flags & HAS_ALPHA)
1111 p[i].alpha = (ILuint)(*((ILubyte*)(p[i].data + p[i].pixel_offset + p[i].alpha_offset)));
1118 if ((p[i].flags & IS_INDEXED) && (p[i].flags & CANNOT_BE_INDEXED))
1120 if (p[i].index < p[i].info.palette_num_cols)
1122 p[i].pal_offset = p[i].index * p[i].info.palette_bpp;
1123 p[i].red = (ILuint)(*((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].red_offset)));
1124 p[i].green = (ILuint)(*((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].green_offset)));
1125 p[i].blue = (ILuint)(*((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].blue_offset)));
1126 if (p[i].flags & HAS_ALPHA)
1127 p[i].alpha = (ILuint)(*((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].alpha_offset)));
1131 if ((p[i].flags & IS_GRAY) && (p[i].flags & CANNOT_BE_GRAY))
1133 p[i].red = p[i].value;
1134 p[i].green = p[i].value;
1135 p[i].blue = p[i].value;
1137 else if (!(p[i].flags & IS_GRAY) && (p[i].flags & MUST_BE_GRAY))
1138 p[i].value = (p[i].red + p[i].green + p[i].blue) / 3;
1140 if (((!(p[i].flags & HAS_ALPHA)) && (p[i].flags & MUST_HAVE_ALPHA)) || ((p[i].flags & HAS_ALPHA) && (p[i].flags & CANNOT_HAVE_ALPHA)))
1141 p[i].alpha = upscale_value(0xFF, p[i].info.image_bpc);
1145 r = function(n, p, data);
1151 if (!(p[i].flags & NOT_WRITABLE))
1153 if ((p[i].flags & HAS_ALPHA) && (p[i].flags & CANNOT_HAVE_ALPHA))
1154 p[i].alpha = upscale_value(0xFF, p[i].info.image_bpc);
1156 else if (!(p[i].flags & IS_GRAY) && (p[i].flags & MUST_BE_GRAY))
1158 p[i].red = p[i].value;
1159 p[i].green = p[i].value;
1160 p[i].blue = p[i].value;
1162 else if ((p[i].flags & IS_GRAY) && (p[i].flags & CANNOT_BE_GRAY))
1163 p[i].value = (p[i].red + p[i].green + p[i].blue) / 3;
1165 switch (p[i].info.image_type)
1168 case IL_UNSIGNED_INT:
1169 if(p[i].flags & IS_INDEXED)
1170 *((ILuint*)(p[i].data + p[i].pixel_offset + p[i].index_offset)) = p[i].index;
1173 if(p[i].flags & IS_GRAY)
1174 *((ILuint*)(p[i].data + p[i].pixel_offset + p[i].value_offset)) = p[i].value;
1177 *((ILuint*)(p[i].data + p[i].pixel_offset + p[i].red_offset)) = p[i].red;
1178 *((ILuint*)(p[i].data + p[i].pixel_offset + p[i].green_offset)) = p[i].green;
1179 *((ILuint*)(p[i].data + p[i].pixel_offset + p[i].blue_offset)) = p[i].blue;
1181 if(p[i].flags & HAS_ALPHA)
1182 *((ILuint*)(p[i].data + p[i].pixel_offset + p[i].alpha_offset)) = (ILubyte)p[i].alpha;
1186 case IL_UNSIGNED_SHORT:
1187 if(p[i].flags & IS_INDEXED)
1188 *((ILushort*)(p[i].data + p[i].pixel_offset + p[i].index_offset)) = (ILushort)p[i].index;
1191 if(p[i].flags & IS_GRAY)
1192 *((ILushort*)(p[i].data + p[i].pixel_offset + p[i].value_offset)) = (ILushort)p[i].value;
1195 *((ILushort*)(p[i].data + p[i].pixel_offset + p[i].red_offset)) = (ILushort)p[i].red;
1196 *((ILushort*)(p[i].data + p[i].pixel_offset + p[i].green_offset)) = (ILushort)p[i].green;
1197 *((ILushort*)(p[i].data + p[i].pixel_offset + p[i].blue_offset)) = (ILushort)p[i].blue;
1199 if(p[i].flags & HAS_ALPHA)
1200 *((ILushort*)(p[i].data + p[i].pixel_offset + p[i].alpha_offset)) = (ILushort)p[i].alpha;
1204 case IL_UNSIGNED_BYTE:
1205 if(p[i].flags & IS_INDEXED)
1206 *((ILubyte*)(p[i].data + p[i].pixel_offset + p[i].index_offset)) = (ILubyte)p[i].index;
1209 if(p[i].flags & IS_GRAY)
1210 *((ILubyte*)(p[i].data + p[i].pixel_offset + p[i].value_offset)) = (ILubyte)p[i].value;
1213 *((ILubyte*)(p[i].data + p[i].pixel_offset + p[i].red_offset)) = (ILubyte)p[i].red;
1214 *((ILubyte*)(p[i].data + p[i].pixel_offset + p[i].green_offset)) = (ILubyte)p[i].green;
1215 *((ILubyte*)(p[i].data + p[i].pixel_offset + p[i].blue_offset)) = (ILubyte)p[i].blue;
1217 if(p[i].flags & HAS_ALPHA)
1218 *((ILubyte*)(p[i].data + p[i].pixel_offset + p[i].alpha_offset)) = (ILubyte)p[i].alpha;
1231 p[i].pixel_offset += p[i].info.image_bytes_per_pixel;
1239 p[i].line_offset += p[i].line_bytes;
1250 int perform_action_palette_mix (
1259 struct PixelInfo p[3];
1261 ILint actual_frames = 0x7FFFFFFF;
1263 uint_fast8_t skip_frame;
1270 p[i].handle = get_handle(p[i].id);
1271 p[i].flags = flags[i];
1272 r = get_info(p[i].id, &(p[i].info), 0);
1275 get_flags(&(p[i].info), &(p[i].flags));
1277 if (!(p[i].flags & IS_INDEXED))
1279 fputs(INDEXED_REQUIRED, stderr);
1282 if (!(p[i].flags & OK_PALETTE_ONLY))
1284 fputs(PALETTE_ONLY_REQUIRED, stderr);
1287 if (p[i].flags & CAN_BE_MULTIPLE)
1289 if (p[i].info.num_images+1 < actual_frames)
1290 actual_frames = p[i].info.num_images+1;
1298 n_colors = p[0].info.palette_num_cols * p[1].info.palette_num_cols;
1299 if (p[2].info.palette_num_cols < n_colors)
1301 fputs(BAD_PALETTE_SIZE, stderr);
1305 for (f = 0; (f < actual_frames) && (r == 0); ++f)
1311 p[i].f_pict = p[i].f0 + f;
1312 if ((p[i].f_pict < 0) || (p[i].f_pict > p[i].info.num_images))
1318 r = get_info(p[i].id, &(p[i].info), p[i].f_pict);
1322 get_flags(&(p[i].info), &(p[i].flags));
1323 p[i].flags |= IS_PALETTE_ONLY;
1325 r = get_data(p[i].id, &(p[i].data), p[i].f_pict);
1329 r = get_palette(p[i].id, &(p[i].palette), p[i].f_pict);
1333 if (!(p[i].flags & IS_INDEXED))
1335 fputs(INDEXED_REQUIRED, stderr);
1339 p[i].alpha_offset = 0;
1340 p[i].value_offset = 0;
1341 p[i].index_offset = 0;
1342 p[i].red_offset = 0;
1343 p[i].green_offset = 0;
1344 p[i].blue_offset = 0;
1346 switch (p[i].info.palette_type)
1352 p[i].alpha_offset = 3;
1354 p[i].red_offset = 2;
1355 p[i].green_offset = 1;
1356 p[i].blue_offset = 0;
1359 p[i].alpha_offset = 3;
1362 p[i].red_offset = 0;
1363 p[i].green_offset = 1;
1364 p[i].blue_offset = 2;
1368 if ((p[i].flags & IS_GRAY) && (p[i].flags & CANNOT_BE_GRAY))
1369 p[i].flags &= ~EFF_GRAY;
1370 else if (!(p[i].flags & IS_GRAY) && (p[i].flags & MUST_BE_GRAY))
1371 p[i].flags |= EFF_GRAY;
1372 if ((!(p[i].flags & HAS_ALPHA)) && (p[i].flags & MUST_HAVE_ALPHA))
1373 p[i].flags |= EFF_ALPHA;
1374 else if ((p[i].flags & HAS_ALPHA) && (p[i].flags & CANNOT_HAVE_ALPHA))
1375 p[i].flags &= ~EFF_ALPHA;
1380 p[0].pal_offset = 0;
1382 p[2].pal_offset = 0;
1383 for (j=0; j<p[0].info.palette_num_cols; ++j)
1386 p[1].pal_offset = 0;
1387 for (k=0; k<p[1].info.palette_num_cols; ++k)
1391 if (!(p[i].flags & NOT_READABLE))
1393 p[i].red = (ILuint)(*((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].red_offset)));
1394 p[i].green = (ILuint)(*((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].green_offset)));
1395 p[i].blue = (ILuint)(*((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].blue_offset)));
1396 if (p[i].flags & HAS_ALPHA)
1398 if (p[i].flags & CANNOT_HAVE_ALPHA)
1401 p[i].alpha = (ILuint)(*((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].alpha_offset)));
1403 else if (p[i].flags & MUST_HAVE_ALPHA)
1405 if (p[i].flags & MUST_BE_GRAY)
1406 p[i].value = (p[i].red + p[i].green + p[i].blue) / 3;
1410 r = function(3, p, data);
1416 if (!(p[i].flags & NOT_WRITABLE))
1418 if (p[i].flags & MUST_BE_GRAY)
1420 p[i].red = p[i].value;
1421 p[i].green = p[i].value;
1422 p[i].blue = p[i].value;
1424 if (p[i].flags & HAS_ALPHA)
1426 if (p[i].flags & CANNOT_HAVE_ALPHA)
1428 *((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].alpha_offset)) = (ILubyte)(p[i].alpha);
1430 *((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].red_offset)) = (ILubyte)(p[i].red);
1431 *((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].green_offset)) = (ILubyte)(p[i].green);
1432 *((ILubyte*)(p[i].palette + p[i].pal_offset + p[i].blue_offset)) = (ILubyte)(p[i].blue);
1437 p[1].pal_offset += p[1].info.palette_bpp;
1439 p[2].pal_offset += p[1].info.palette_bpp;
1442 p[0].pal_offset += p[0].info.palette_bpp;
1450 ILuint upscale_value (ILubyte x, ILint bytes)
1455 for (i=0; i<bytes; ++i)
1463 ILubyte downscale_value (ILuint x, ILint bytes)
1465 return (ILubyte)(x >> (8 * (bytes-1)));
1468 int copy_pixels (ILuint n, struct PixelInfo *p, void *data)
1470 ILuint max = *((ILuint *)data);
1475 if (p[0].flags & EFF_INDEXED)
1477 if (!(p[1].flags & EFF_INDEXED))
1479 p[1].index = p[0].index;
1481 else if (p[0].flags & EFF_ALPHA)
1483 if (p[0].flags & EFF_GRAY)
1485 if (!(p[1].flags & EFF_GRAY))
1487 p[1].value = copy_1p_alpha(p[0].value, p[1].value, p[0].alpha, max);
1491 if (p[1].flags & EFF_GRAY)
1493 p[1].red = copy_1p_alpha(p[0].red, p[1].red, p[0].alpha, max);
1494 p[1].green = copy_1p_alpha(p[0].green, p[1].green, p[0].alpha, max);
1495 p[1].blue = copy_1p_alpha(p[0].blue, p[1].blue, p[0].alpha, max);
1497 if (p[1].flags & EFF_ALPHA)
1498 p[1].alpha = copy_1p_alpha(max, p[1].alpha, p[0].alpha, max);
1502 if (p[0].flags & EFF_GRAY)
1504 if (!(p[1].flags & EFF_GRAY))
1506 p[1].value = p[0].value;
1510 if (p[1].flags & EFF_GRAY)
1512 p[1].red = p[0].red;
1513 p[1].green = p[0].green;
1514 p[1].blue = p[0].blue;
1516 if (p[1].flags & EFF_ALPHA)
1523 int fill_color (ILuint n, struct PixelInfo *p, void *data)
1525 struct ColorInfo *d = data;
1527 if (p->flags & EFF_INDEXED)
1529 p->index = d->index;
1533 if (p->flags & EFF_ALPHA)
1534 p->alpha = d->alpha;
1535 if (p->flags & EFF_GRAY)
1536 p->value = d->value;
1540 p->green = d->green;
1548 ILuint copy_1p_alpha (ILint64 src, ILint64 dst, ILint64 alpha, ILint64 max)
1550 ILint64 v = (src * alpha + dst * (max - alpha)) / max;
1554 int palette_mix_index (ILuint n, struct PixelInfo *p, void *data)
1559 p[2].index = p[0].index * p[1].info.palette_num_cols + p[1].index;
1564 ILuint tsqrt(ILuint s)
1600 default: // not a square - please fail
1605 //unsigned short isqrt(unsigned s)
1607 // unsigned short r;
1608 // unsigned short b=0x0040;
1628 // ILuint n, struct PixelInfo *info, void *data
1632 // "%04lu %04lu %04lu: %03lu %03lu %03lu %03lu %03lu %03lu\n",
1633 // (unsigned long)(info->x_pict), (unsigned long)(info->y_pict), (unsigned long)(info->f_pict),
1634 // (unsigned long)(info->red), (unsigned long)(info->green), (unsigned long)(info->blue),
1635 // (unsigned long)(info->alpha), (unsigned long)(info->value), (unsigned long)(info->index)